引入
在cyber/examples/common_component_example/channel_test_writer.c实例中,除初始化cyber框架外外,第一步就是需要创建一个节点
auto talker_node = apollo::cyber::CreateNode("channel_test_writer");
接下来,我们分析一下这个接口到底干了些啥
官方文档
在cyber/doxy-docs/source/CyberRT_API_for_Developers.md目录下:
可以知道:
- 在cyber中,Node是最基本的单元,类似于"句柄"
- 比如writer, reader等都是基于Node创建的
接口:
std::unique_ptr<Node> apollo::cyber::CreateNode(const std::string& node_name, const std::string& name_space = "");
-
参数:
- node_name: 节点的名称,全局唯一标识符
- name_space:
- 节点所在空间的名称
- name_space默认为空。它是与node_name连接的空间的名称。格式为
/namespace/node_name
- 暂时无需关注这个变量
-
返回值:
- 成功的话返回一个指向节点的独占智能指针
- 错误条件:未调用"cyber::Init()" 时,系统处于未初始化状态,无法创建节点,返回nullptr
CreateNode
接下来我们看下apollo::cyber::CreateNode这个接口到底是怎么实现的
这个接口是在cyber/cyber.cc中实现的,里面返回了Node的引用。可以看到最终调用了new Node(node_name, name_space)
- 如果是实车环境而且未调用"cyber::Init()",那么返回nullptr
- 否则,调用
new Node(node_name, name_space)
Node
接下来我们仔细分析下Node是怎么实现的。
它定义在cyber/node/node.h目录下
成员变量
在Node中有一些关键的成员变量:
- 有一系列相关的Reader
- 以及相应的NodeChannelImpl 和 NodeServiceImpl。
每个Node保存了它的名字和名字空间
- 一个存有channel_name对应的Reader的map
- 一个node可以读取多个topic,可以有多个reader
- 一个NodeChannelImpl和一个NodeServiceImpl
- NodeChannelImpl用来创建reader和writer
- NodeServiceImpl用来参加service和client
上面还可以看到Node的构造函数是private的,这说明不可以直接构造Node节点,必须通过apollo::cyber::CreateNode这个接口来定义Node。
通过注释我们可以看到:
- Node是通信的最顶层的类,是cyber RT最基本的单元
- 每个Component都有一个Node
- 每个Node负责创建Reader, Writer, Service, Client来帮该组件获取信息或者传达信息。
- 拓扑中不允许重复的节点名。
然后我们看看Node的构造函数怎么实现的:
关键在于初始化了两个成员变量:NodeChannelImpl,NodeServiceImpl
成员函数
单向通信
CreateWriter
writer是cyber中发送消息的基本工具。每个writer都可以通过channel发送一些特定类型的消息。
一共有两种方法来创建writer:
参数:
- role_attr。里面包括了要往哪个通道写
- channel_name:要写入的通道的名称
- MessageT:要写入的消息类型
返回值:
- 指向Writer对象的共享指针
具体实现:
可以看到,node使用了node_channel_impl_以便创建writer。
CreateReader
reader是cyber中用来接收信息的基本设施。
- 创建reader时,必须将其绑定到回调函数。
- 当新消息到达通道时,将调用回调。
读取器由Node类的“CreateReader”接口创建。接口如下:
参数:
- MessageT:要读取的消息类型
- channel_name:要从中接收的频道的名称
- reader_func:处理消息的回调函数
返回值:
- 指向Reader对象的共享指针
使用示例
- cyber/examples/talker.cc
- cyber/examples/listener.cc
双向通信
CreateService
CreateClient
使用示例
- cyber/examples/proto/examples.pb.h
- cyber/examples/service.cc
小结
Node是通信的最顶层的类,每个Component都有一个Node
- 每个Node负责创建Reader, Writer, Service, Client来帮该组件获取信息或者传达信息。
- 每个Node保存了它的名字和名字空间,一个存有channel_name对应的Reader的map以及一个NodeChannelImpl和一个NodeServiceImpl(创建以上4种东西的创建器)。
Node是Server/Client/Writer/Reader的容器:
- Server/Client/Writer/Reader是有向图的顶点。
- Channel是Writer到Reader的边缘
- Service是Server到Client的边缘
cyber/message
MessageHeader
- apollo-master/cyber/message/message_header.h中定义了一个消息头
- apollo-master/cyber/message/message_header_test.cc告知你消息头应该怎么用
数据类型 | 变量名 | 作用 |
---|---|---|
char | magic_num_[8]; | |
char | seq_[8]; | |
char | timestamp_ns_[8]; | |
char | src_id_[8]; | |
char | dst_id_[8]; | |
char | msg_type_[129]; | |
char | res_[19]; | |
char | content_size_[4]; |
message_traits.h
看不懂
参数服务(Parameter Service)
- 参数服务用于节点间共享数据,并提供基本操作,如“set”、“get”和“list”。
- 参数服务基于“Service”实现,包含 service 和 client.
参数对象
支持的数据类型
这些参数都是基于 apollo::cyber::Parameter
的,下面列出了所有支持的数据类型
Parameter type | C++ data type | protobuf data type |
---|---|---|
apollo::cyber::proto::ParamType::INT | int64_t | int64 |
apollo::cyber::proto::ParamType::DOUBLE | double | double |
apollo::cyber::proto::ParamType::BOOL | bool | bool |
apollo::cyber::proto::ParamType::STRING | std::string | string |
apollo::cyber::proto::ParamType::PROTOBUF | std::string | string |
apollo::cyber::proto::ParamType::NOT_SET | - | - |
除了上述5种类型,Parameter还支持以protobuf对象作为传入参数的接口。执行后序列化处理对象并将其转换为STRING类型以进行传输。
如何构造
构造函数:
使用示例:
如何读取
接口:
示例:
文件名 | 作用 |
---|---|
parameter_test.cc | 告知你Parameter应该怎么使用 |
parameter.cc | 从这里可以学到如何构建一个数据类型,以及std::enable_if怎么用 |
parameter_test.cc
parameter.cc
数据类型 | 变量名 | 作用 |
---|---|---|
Param | param_; | Param是proto定义的 |
parameter_service_names.h
std::string FixParameterServiceName(const std::string& node_name,
const char* service_name)
- 作用:返回
node_name/service_name
其他
主要文件
文件名 | 作用 |
---|---|
node_test.cc | |
reader_test.cc | |
writer_test.cc | |
writer_reader_test.cc | |
node_channel_impl_test.cc | |
node.cc | 节点是CyberRT中的基本单元,每个模块都包含一个节点,并且相互之间使用节点通信。一个模块可以定义不同的通信方式在一个节点中,如read/write or/and service/client。 |
reader_base.h | Reader的基类 |
writer_base.h | Writer的基类 |
reader.h | Reader类 |
writer.h | Writer类 |
node_channel_impl.h | reader writer的具体实现 |
node_service_impl.h | service client的具体实现 |
接下来,我们从下到上分析。
Block
apollo-master/cyber/transport/shm/block.h
- 一段segment中会有多个block
- block时用来存储channel中的数据的,它也是其他类用来读写数据的对象
Receiver
Receiver
apollo-master/cyber/transport/receiver/receiver.h
一个基类
成员变量
数据类型 | 变量名字 | 说明 |
---|---|---|
MessageListener | msg_listener_ |
|