自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层

浅淡Apollo Cyber RT之数据缓存与融合

Cyber RT的层次图如下:

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第1张图片

今天要讲的内容位于上图中的中间层。

一、基于Cyber RT的开发流程

在开发基于Cyber RT的模块时,并不是从main()函数开始的,常规的流程是这样的:

以PlanningComponent为例

● 从Component派生一个子类PlanningComponent。

● 重新实现虚函数Proc()和Init()。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第2张图片

Init(),组件初始化函数,当进程初始化时,被CyberRT框架调用,我们在此添加我们的初始化逻辑。

Proc(),数据处理函数,每当数据就绪时,被CyberRT框架调用,我们在此添加我们的业务处理逻辑。

这一切看起来很简单,Cyber RT将大量的工作都隐藏在这两个函数后面。

先看Proc()函数的声明:

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第3张图片

可以看到,Planning组件依赖三组数据输入,分别是预测障碍物、底盘数据和定位信息。在没有使用Cyber RT之前,这些数据的对齐需要我们自己来做,其中包括时间对齐、线程同步和数据拷贝。这些工作很繁琐,且容易出错,且每个模块都要做大量这样的重复性工作。现在Cyber RT帮我们做了这些工作,我们只需要关注业务逻辑的处理。那Cyber RT是怎么做到的呢?

二、数据处理流程

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第4张图片

这个一个精简的数据流图,图中只标出了核心的调用关系,但足以说明问题。主要包括以下步骤:

① Init()是被框架中的Initialize()函数调用,Initialize()函数还做了其它大量的工作。它通过CreateReader()创建了多个Reader,分别绑定以Proc函数中的多个消息类型。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第5张图片

图1.1

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第6张图片

图1.2

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第7张图片

图1.3

CreatReader()函数间接调用了ReceiverManager,向Transport层订阅消息。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第8张图片

② Initialize()函数紧接着创建了一个数据访问器(DataVisitor),DataVisitor的引用被保存在异步Task中。每个Component有专属的DataVisitor,DataVisitor又绑定了相关的一组消息。DataVisitor还做了以下几项工作:

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第9张图片

2.1 为每个消息类型创建一个消息队列。

2.2 创建一个消息对齐/融合器(Fusion/Alllatest)。这一组消息对齐的频率,等于第一个消息M0的频率,所以只向M0的消息队列注册回调函数。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第10张图片

③ 通过CreateTask向调度器中注册回调任务(协程)(图1.3)。调度器会向DataVisitor注册自己(再通过Notify向DataNotify注册),这样,当Transport层数据就绪时,调度器就会收到通知。调度器再根据消息优先级,结合调度策略,唤醒协程,最终调用到组件的Proc函数。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第11张图片

上面介绍了组件(Component)的初始化过程。而一个完整的消息处理流程分为后面几个步骤:

④ 被动接收底层(Transport)的消息。

⑤ 收到消息后,没有直接发送到应用进行处理,而是发送到了数据分发器(DataDispatcher)。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第12张图片

⑥ DataDispatcher再将消息放到相关消息的缓存队列。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第13张图片

⑦ 其中Fill()函数中缓存数据,并执行前面 (2.2) 注册的对齐/融合回调函数。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第14张图片

⑧通过DataNotifier调用前面 (③) 注册的回调函数(RegisterNotifyCallback()),通知调度器(NotifyProcessor()),进行后续处理。

⑨ NotifyProcessor() 根据优先级和调度策略唤醒协程,Cyber实现了两种策略,分别是"SchedulerClassic"和"SchedulerChoreography"。这里不作详述,更多信息请参见:

https://zhuanlan.zhihu.com/p/121042548。

要注意的是,到目前为止的这一系列的调用,都是在Transport的回调函数(线程)中进行。而被调度器唤醒后的任务是在调度器框架中的协程中执行。这是一个异步的过程,它保证了上层应用处理,不会阻塞底层消息收发。

⑩ 协程处理函数是一个无限循环。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第15张图片

⑾ 协程函数首先(通过DataVisitor)向缓存中读取对齐后的数据。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第16张图片

⑿ 获得融合后的数据后,协程会调用应用组件(Component)的回调函数。

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第17张图片

而这个回调函数就是我们在前面①中初始化组件时注册进来的

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第18张图片

而Process()函数最终会调用我们重新实现的Proc()函数,到此,一个完整的数据处理流程完成!

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第19张图片

附完整时序图:

自动驾驶开发入门(五)---浅谈Apollo Cyber RT的数据处理层_第20张图片

总结,Cyber RT 数据处理最大特点是:

1、上层业务逻辑与底层数据收发解耦,包括静态(设计)和动态(运行)的。

2、数据对齐/融合。

3、协程调度器。

你可能感兴趣的:(自动驾驶,C/C++,嵌入式,自动驾驶,中间件)