以下文章来源于分子运动 ,作者王方浩
下面是由社区开发者—王方浩提供的文章,本文主要介绍Cyber框架。
ENJOY THE FOLLOWING
本文将主要从以下几个方面来介绍:
-
数据处理流程
-
整体介绍
-
总结
Cyber中整个的数据处理流程,通过理解数据流程中各个模块如何工作,清楚地了解每个模块的作用,然后分析具体的模块。
如上图所示,Cyber的数据流程可以分为6个过程:
1、Node节点中的Writer往通道里面写数据;
2、通道中的Transmitter发布消息,通道中的Receiver订阅消息;
3、Receiver接收到消息之后,触发回调,触发DataDispather进行消息分发;
4、DataDispather接收到消息后,把消息放入CacheBuffer,并且触发Notifier,通知对应的DataVisitor处理消息;
5、DataVisitor把数据从CacheBuffer中读出,并且进行融合,然后通过notifier_唤醒对应的协程;
6、协程执行对应的注册回调函数,进行数据处理,处理完成之后接着进入睡眠状态。
对数据流程有整体的认识之后,接下来按照功能划分分析具体的每个模块。
首先对Cyber中各个模块做一个简单的介绍,然后再接着分析。只要清楚了下面这些概念之间的关系,就基本理解清楚了整个Cyber的数据流程。
-
Component和Node的关系
Component是Cyber中封装好的数据处理流程,对用户来说,对应自动驾驶中的Planning Component、Perception Component等,目的是帮助用户更方便的订阅和处理消息。实际上Component模块在加载之后会执行"Initialize()"函数,这是个隐藏的初始化过程,对用户不可见。在"Initialize"中,Component会创建一个Node节点,概念上对应ROS的节点,每个Component模块只能有一个Node节点,也就是说每个Component模块有且只能有一个节点,在Node节点中进行消息订阅和发布。
-
Node和Reader\Writer的关系
在Node节点中可以创建Reader订阅消息,也可以创建Writer发布消息,每个Node节点中可以创建多个Reader和Writer。
-
Reader和Receiver,Writer和Transmitter,Channel的关系
一个Channel对应一个Topic,概念上对应ROS的消息通道,每个Topic都是唯一的。而Channel中包括一个发送器(Transmitter)和接收器(Receiver),通过Receiver接收消息,通过Transmitter发送消息。
一个Reader只能订阅一个通道的消息,如果一个Node需要订阅多个通道的消息,需要创建多个Reader。同理一个Writer也只能发布一个通道的消息,如果需要发布多个消息,需要创建多个Writer。
Reader中调用Receiver订阅消息,而Writer通过Transmitter发布消息。
-
Receiver, DataDispatcher和DataVisitor的关系
每一个Receiver接收到消息之后,都会触发回调,回调中触发DataDispather(消息分发器)发布消息,DataDispather是一个单例,所有的数据分发都在数据分发器中进行,DataDispather会把数据放到对应的缓存中,然后Notify(通知)对应的协程(实际上这里调用的是DataVisitor中注册的Notify)去处理消息。
DataVisitor(消息访问器)是一个辅助的类,一个数据处理过程对应一个DataVisitor,通过在DataVisitor中注册Notify(唤醒对应的协程,协程执行绑定的回调函数),并且注册对应的Buffer到DataDispather,这样在DataDispather的时候会通知对应的DataVisitor去唤醒对应的协程。
也就是说DataDispather(消息分发器)发布对应的消息到DataVisitor,DataVisitor(消息访问器)唤醒对应的协程,协程中执行绑定的数据处理回调函数。
-
DataVisitor和Croutine的关系
实际上DataVisitor中的Notify是通过唤醒协程(为了方便理解也可以理解为线程,可以理解为你有一个线程池,通过线程池绑定数据处理函数,数据到来之后就唤醒对应的线程去执行任务),每个协程绑定了一个数据处理函数和一个DataVisitor,数据到达之后,通过DataVisitor中的Notify唤醒对应的协程,执行数据处理回调,执行完成之后协程进入休眠状态。
-
Scheduler, Task和Croutine
通过上述分析,数据处理的过程实际上就是通过协程完成的,每一个协程被称为一个Task,所有的Task(任务)都由Scheduler进行调度。从中可以分析得出实际上Cyber的实时调度由协程去保障,并且可以灵活的通过协程去设置对应的调度策略,当然协程依赖于进程,Apollo在Linux中设置进程的优先级为实时轮转,先保障进程的优先级最高,然后内部再通过协程实现对应的调度策略。
协程和线程的优缺点这里就不展开了,这里有一个疑问是协程不能被终止,除非协程主动退出,这里先留一个伏笔,后面再分析协程的调度问题。
上述就是Cyber中各个概念之间的关系,对理解数据的流程非常有帮助,希望大家可以画一下对应的数据流程图和关系。
* 《 Apollo介绍之Cyber框架》
https://zhuanlan.zhihu.com/p/115046708