Apollo学习(1)-- Cyber模块解析
一、Talker-Listener
1、参考文件
参考教程:docs/cyber/CyberRT_API_for_Developers.md github
代码示例:cyber/examples/
其中,文件均为apollo根目录的相对路径
2、发布-订阅机制
Apollo的Cyber话题发布-订阅机制及代码架构与ROS类似,可以参考ROS教程对Cyber机制有更好地理解
3、代码示例
(1)Talker (cyber/examples/talker.cc)
#include "cyber/cyber.h"
#include "cyber/proto/chatter.pb.h"
#include "cyber/time/rate.h"
#include "cyber/time/time.h"
using apollo::cyber::Rate;
using apollo::cyber::Time;
using apollo::cyber::proto::Chatter;
int main(int argc, char *argv[]) {
// init cyber framework
apollo::cyber::Init(argv[0]);
// create talker node
std::shared_ptr<apollo::cyber::Node> talker_node(
apollo::cyber::CreateNode("talker"));
// create talker
auto talker = talker_node->CreateWriter<Chatter>("channel/chatter");
Rate rate(1.0);
while (apollo::cyber::OK()) {
static uint64_t seq = 0;
auto msg = std::make_shared<apollo::cyber::proto::Chatter>();
msg->set_timestamp(Time::Now().ToNanosecond());
msg->set_lidar_timestamp(Time::Now().ToNanosecond());
msg->set_seq(seq++);
msg->set_content("Hello, apollo!");
talker->Write(msg);
AINFO << "talker sent a message!";
rate.Sleep();
}
return 0;
}
(2)Listener (cyber/examples/listener.cc)
#include "cyber/cyber.h"
#include "cyber/proto/chatter.pb.h"
void MessageCallback(
const std::shared_ptr<apollo::cyber::proto::Chatter>& msg) {
AINFO << "Received message seq-> " << msg->seq();
AINFO << "msgcontent->" << msg->content();
}
int main(int argc, char *argv[]) {
// init cyber framework
apollo::cyber::Init(argv[0]);
// create listener node
auto listener_node = apollo::cyber::CreateNode("listener");
// create listener
auto listener =
listener_node->CreateReader<apollo::cyber::proto::Chatter>(
"channel/chatter", MessageCallback);
apollo::cyber::WaitForShutdown();
return 0;
}
(3)Bazel BUILD file(cyber/samples/BUILD) 编译文件,类似ROS中的CMakeLists文件
cc_binary(
name = "talker",
srcs = [ "talker.cc", ],
deps = [
"//cyber",
"//cyber/examples/proto:examples_cc_proto",
],
)
cc_binary(
name = "listener",
srcs = [ "listener.cc", ],
deps = [
"//cyber",
"//cyber/examples/proto:examples_cc_proto",
],
)
4、运行示例程序
- 进入容器
sudo bash docker/scripts/dev_start.sh
sudo bash docker/scripts/dev_into.sh
- 编译示例文件
bazel build cyber/examples/…
- 分别在不同的终端启动talker和listener,命令如下:
./bazel-bin/cyber/examples/talker
./bazel-bin/cyber/examples/listener
注释:docker启动新终端方式
(base) lv@lv-Legion:~/apollo$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5cf01a6ace92 apolloauto/apollo:dev-x86_64-18.04-20210914_1336 "/bin/bash" 38 minutes ago Up 38 minutes apollo_dev_root
执行下面两条命令中任一命令均可,其中5cf01a6ace92为容器ID,apollo_dev_root为容器名字
sudo docker exec -ti apollo_dev_root bash
sudo docker exec -ti 5cf01a6ace92 bash
- 打开两个终端执行命令后,终端未显示输出,原因是程序中用的输出语句为
AINFO << "talker sent a message!";
AINFO为apollo的log信息,若想在输出方法如下:
- Change
GLOG_alsologtostderr
from0
to1
incyber/setup.bash
- Run
source cyber/setup.bash
in current console.
或者终端输入命令export GLOG_alsologtostderr=1
另外可通过cyber_channel查看话题信息
cyber_channel echo channel/chatter
若提示未找到命令,bash: cyber_channel: command not found
source ./cyber/setup.bash
- 运行成功,可看到如下输出:
root@in-dev-docker:/apollo# cyber_channel echo channel/chatter
timestamp: 1676884418184410648
lidar_timestamp: 1676884418184411113
seq: 413
content: "Hello, apollo!"
timestamp: 1676884419184403591
lidar_timestamp: 1676884419184403985
seq: 414
content: "Hello, apollo!"
timestamp: 1676884420184459860
lidar_timestamp: 1676884420184460322
seq: 415
content: "Hello, apollo!"
二、Component
1、参考文件
参考文档:docs/cyber/CyberRT_API_for_Developers.md和cyber/examples/common_component_example/README.md
代码位置:cyber/examples/common_component_example
2、概念及优点
-
概念
Component是Cyber RT提供的基类,通过继承Init
和Proc
函数将应用载入Cyber RT框架
Component中Init()
函数等价于主函数
Component中Proc()
函数等价于接受端回调函数 -
优点
Component可以通过launch文件在不同的进程中被载入,应用灵活
Component通过改变dag文件改变接受话题名而不需要重新编译
Component支持接受多种类型数据
Component支持提供多种融合策略
3、代码解析
文件架构
文件名 | 功能 |
---|---|
BUILD | 编译文件,将component文件编译成动态链接库 |
channel_test_writer.cc | 发布话题/apollo/test |
channel_prediction_writer.cc | 发布话题/apollo/prediction |
common_component_example.cc | component源文件 |
common_component_example.h | component头文件 |
common.dag | dag文件 |
common.launch | launch文件 |
(1)common_component_example.h(重载Component函数,类名CommonComponentSample)
#include <memory>
#include "cyber/component/component.h"
#include "cyber/examples/proto/examples.pb.h"
using apollo::cyber::Component;
using apollo::cyber::ComponentBase;
using apollo::cyber::examples::proto::Driver;
class CommonComponentSample : public Component<Driver, Driver> {
public:
bool Init() override;
bool Proc(const std::shared_ptr<Driver>& msg0,
const std::shared_ptr<Driver>& msg1) override;
};
CYBER_REGISTER_COMPONENT(CommonComponentSample)
(2)common_component_example.cc
init()
为初始化函数 ,Proc()
为回调函数
#include "cyber/examples/common_component_example/common_component_example.h"
bool CommonComponentSample::Init() {
AINFO << "Commontest component init";
return true;
}
bool CommonComponentSample::Proc(const std::shared_ptr<Driver>& msg0,
const std::shared_ptr<Driver>& msg1) {
AINFO << "Start common component Proc [" << msg0->msg_id() << "] ["
<< msg1->msg_id() << "]";
return true;
}
(3)BUILD
将common_component_example.cc
和common_component_example.h
文件编译成libcommon_component_example.so
动态链接库,dag文件使用动态链接库进行操作。
(4)common.dag
# Define all coms in DAG streaming.
module_config {
module_library : "/apollo/bazel-bin/cyber/examples/common_component_example/libcommon_component_example.so"
components {
class_name : "CommonComponentSample"
config {
name : "common"
readers {
channel: "/apollo/prediction"
}
readers {
channel: "/apollo/test"
}
}
}
}
- module_library:动态链接库(.so)文件
- components & timer_component: 选择基类的类别,一共两种基类:
components
和timer_component
,此示例为components - class_name: 需要被载入的类名
- name: 新建节点的名字
- readers: 接收1~3个话题名
(5)代码运行
1、编译文件:
bazel build //cyber/examples/common_component_example/...
2、log语句显示为终端输出
export GLOG_alsologtostderr=1
3、启动程序
cyber_launch start cyber/examples/common_component_example/common.launch
或者
mainboard -d cyber/examples/common_component_example/common.dag
4、分别打开docker两个终端,运行两个发布话题程序
bazel run //cyber/examples/common_component_example:channel_test_writer
bazel run //cyber/examples/common_component_example:channel_prediction_writer
5、查看commen.launch程序终端
I0220 22:23:12.235702 11926 common_component_example.cc:19] [mainboard]Commontest component init
I0220 22:23:12.236104 11926 scheduler.cc:55] [mainboard]create croutine: common_/apollo/test
I0220 22:23:12.236408 11926 scheduler.cc:55] [mainboard]create croutine: common_/apollo/prediction
I0220 22:23:12.236531 11926 scheduler.cc:55] [mainboard]create croutine: common
I0220 22:25:09.937448 11936 common_component_example.cc:25] [mainboard]Start common component Proc [1] [64]
I0220 22:25:10.270659 11937 common_component_example.cc:25] [mainboard]Start common component Proc [2] [64]
I0220 22:25:10.603984 11934 common_component_example.cc:25] [mainboard]Start common component Proc [3] [65]
I0220 22:25:10.937593 11939 common_component_example.cc:25] [mainboard]Start common component Proc [4] [66]
I0220 22:25:11.270395 11935 common_component_example.cc:25] [mainboard]Start common component Proc [5] [66]
I0220 22:25:11.604032 11934 common_component_example.cc:25] [mainboard]Start common component Proc [6] [67]
6、查看节点名,common为component节点名字
root@in-dev-docker:/apollo# cyber_node list
Number of active nodes: 3
channel_test_writer
common
prediction_writer
三、其他
附表
Cyber和ROS对节点的一些操作类似,命令使用方法参考以下两个链接。对ROS系统不了解的同学可以从官网ROS教程熟悉ROS基本原理
Apollo 应用与源码分析:CyberRT-工具与命令
ROS教程
cyber | ROS | |
---|---|---|
可视化通道信息 | cyber_visualizer | |
可视化 | cyber_monitor | |
记录数据 | cyber_recorder | rosbag |
通道/节点信息 | cyber_node | rosnode |
话题信息 | cyber_channel | rostopic |
服务信息 | cyber_service | rosservice |
launch文件 | cyber_launch | roslaunch |
其他内容
Service、Param、Log、Timer、Record
可参照教程自学,后续代码若遇到会继续补充。