在前面我们介绍了Cyber RT的基础介绍以及框架方面的知识,我们对Cyber RT是一个什么样的系统和框架有了一个大概的认知。这节我们将介绍一下Cyber RT中的一些基础且关键的概念,搞清楚这些概念所代表的意义以及作用,之后我们再对Cyber RT的各个部分的详细过程以及使用方法进行细致的介绍。
这些概念我们将使用两种方法进行介绍,以保证我们对这些有一个大概的认知。首先我们会将这些概念与Ros中的概念进行对比介绍,以保证我们明白Cyber RT中这些概念与Ros中的概念的不同与相同,其次,我们会按照上节中所介绍的Cyber RT的框架的各个部分进行分门别类的介绍,以确保我们明白这些概念分别属于Cyber RT中的哪些部分以及相互之间的关系。
接下来我们按照Cyber RT的框架进行相关概念的详细介绍。
对象池
队列
在我们创建了Node之后,我们就可以使用Node去实例化Writer类和Reader类对Channel进行消息的推送和接收。
在使用时,我们需要标明Writer或者Reader推送或者接收的目标是谁,即要明确Topic;
而Channel可以看做是Topic对应的一块共享内存,这样我们就可以通过Writer/Reader进行数据的推送和接收了。
在此过程中使用的数据格式的定义是在对应的proto文件中。
该通信方式的使用场景:
适合于持续性通信的应用场景,比如雷达信号,摄像头图像信息这类数据的传输。
服务Server的通信过程:
当客户端/Client发出消息请求获取某些数据的时候,服务端/Service才会进行对应的请求回应,并且将客户端需要的数据返回到指定的共享内存RTPS,客户端/Client自行从此共享内存取出数据。
在此过程中,Client与Server同样需要明确Topic是谁
RTPS可以看做是该Topic对应的一块共享内存。
Client和Service传输的数据依然在对应的proto文件中。
适用场景:
适用于不需要持续性发送数据
Service Discovery负责节点Node的监察。关于的详细介绍看这里:
Cyber - Service Discovery 模塊
参数可以被看作是一些需要被各个模块共用或者使用过程中更改的“全局变量”。
Cyber RT中设计了全局参数服务器来实现这个功能,其通信依然基于RTps协议。
通过ParameterServer参数服务器我们可以对参数列表中的参数进行读取和更新,并且是客户端和服务端均可以进行该操作。
Protobuf是Google公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议,与XML和JSON格式相比,Protobuf更小、更快、更便捷。
Protobuf是跨语言的,并且自带一个编译器(protoc),只需要用protoc进行编译,就可以编译成Java、Python、C++、C#、Go等多种语言代码,然后可以直接使用,不需要再写其它代码,自带有解析的代码。
只需要将要被序列化的结构化数据定义一次(在.proto文件定义),便可以使用特别生成的源代码(使用protobuf提供的生成工具)轻松的使用不同的数据流完成对结构数据的读写操作。甚至可以更新.proto文件中对数据结构的定义而不会破坏依赖旧格式编译出来的程序。
其优点如下:
性能效率高:序列化后字节占用空间比XML少3-10倍,序列化的时间效率比XML快20-100倍。
使用便捷便捷:将对结构化数据的操作封装成一个类,便于使用。
兼容性高:通信两方使用同一数据协议,当有一方修改了数据结构,不会影响另一方的使用。
跨语言:支持Java,C++,Python、Go、Ruby等多种语言。
Cyber多进程通讯模块-Transport(Shared Memory篇)
Cyber 多進程通訊模塊 - Transport(Intra 和 rtps 篇)
DataVisitor(消息访问器)是一个辅助的类,一个数据处理过程对应一个DataVisitor,通过在DataVisitor中注册Notify(唤醒对应的协程,协程执行绑定的回调函数),并且注册对应的Buffer到DataDispather/消息分发器,这样在DataDispather/消息分发器工作的时候会通知对应的DataVisitor去唤醒对应的协程。
详细介绍看这里:
Cyber data_visitor 分析
Node 跟rosnode在定位上有點像,都是負責上層的讀寫功能。
可以用Node::Reader在某channel (topic)中註冊回調,可以用Node::Writer把新的數據寫到channel中。
TopologyManager
nodeManager(查找Node是否存在于Topology),
ChannelManager(查找channel是否存在于Topology以及对应的Writer和Reader),
ServiceManager(查找Service是否存在于Topology以及对应的Server和client)
Cyber RT里面的元素之间的关系由Topology来表达并呈现
Topology相当于一个有向无环图DAG的描述
Node是有向无环图DAG里面的某个顶点
Channel是Writer流向Reader的边
Service是Server流向Client的边
Topology是由TopologyManager生成的,TopologyManager里面有三个内容:nodeManager(查找Node是否存在于Topology),ChannelManager(查找channel是否存在于Topology以及对应的Writer和Reader),ServiceManager(查找Service是否存在于Topology以及对应的Server和client)
TopologyManager依靠fast-rtps进行通信,可以监听元素加入和离开topology网络,可以自己注册channnelfunc来见听topology网络的变化
多路传感器之间的数据融合
算法需要缓存一定的数据
Cyber - Scheduler 模塊
Scheduler自然是把一堆Task做調度,然後順調度結果執行,就跟一般os的scheduling一样。
Scheduler中的主要Task有甚麼?
注意,Scheduler並不是負責管理Cyber中所有內部模塊的執行,有很多內部模塊有自己的thread,它們的調度是由os去做的,而不是Scheduler。Scheduler只管以下2種Task:
(1)第一種就是Component自身處理數據的task,即是Component中Proc()的部份
它會從DataVisitor拿數據,再調用bool Component::Process(const std::shared_ptr& msg0, …),最後調用Proc(),這種task的task name就是在dag檔案中定義的Component名字,比如control
(2)第二種task,就是Node::Reader不停從DataVisitor拿數據,然後Enqueue到自身的Blocker容器,最後調用回調。
注意,Component一般是不會從中的reader拿數據來用的,除非是在is_reality_mode是False時,才會不生成第一種task,改為靠Reader去拿數據處理。
這種Task的使用比較靈活,因為你可以在自己的Componet中用this->node_->CreateReader去直接生成第二種Task
而這種Task的名字為Component Name + '’ + Channel Name,比如"control/apollo/planning"
Processor 1 Processor等於一個Thread,內部會設定cpu親和度,用cpuset去把Processor的內部線程綁定到特定cpu
SchedulerFactory 外部接口,生成跟取得Scheduler實體
Scheduler 放Task到ProcessorContext的地方
SchedulerClassic Scheduler的Classic模式實現
SchedulerChoreography Scheduler的Choreography模式實現
ProcessorContext Processor拿Task的地方
ClassicContext ProcessorContext的Classic模式實現
ChoreographyContext ProcessorContext的Choreography模式實現
算法任务的载体
DAG有向无环图
DAG有向无环图的拓扑排序方法:
按照每个顶点的输入量/输入边的数目的多少进行排序,例如下图中,其排序为542310或者452310。4,5顶点无输入,2,3顶点有一个输入,1,0顶点有两个输入
经典调度算法
任务Task的实现:CRoutine模块
Cyber Rt框架建立在组件的概念之上。作为Cyber Rt的构建块,每个组件都是特定乐算法模块,它处理一组输入并产生一组输出。
在上述的介绍中,我们看到,在Node里面与之有关的概念有通信机制类(Writer/Reader;Server/Client;Channel;Service),节点调度类(DAG,Topology,TopologyManager以及NodeManager、ChannelManager、ServiceManager),但除此之外,在Node里面还有Component和TimerComponent的存在。
继承于Component,需要自己重写init和proc函数,由输入数据进行驱动
继承于Component,需要自己重写init和proc函数,由Timer维持的计数器来进行计时并驱动。
cyber中自己的计时器