2.4.2 基本组件演示(下)
需求
现无人车前后各安装了一颗雷达,雷达可以发布障碍物消息,需要将两颗雷达发送的消息进行融合,运行效果如下:
准备
- 编写两个节点,分别模拟前后雷达发送障碍物消息;
- 在 demo_cc 目录下新建文件夹:component_common02,并在 component_common02 下新建BUILD文件。
模拟雷达消息发布实现如下:
1.定义雷达消息
demo_base_proto 目录下新建 lasers.proto,输入如下内容:
syntax = "proto2";
package apollo.cyber.demo_base_proto;
message Lasers {
required uint64 seq = 1;
required uint64 count = 2;
}
配置文件BUILD添加内容如下:
proto_library(
name = "lasers_proto",
srcs = ["lasers.proto"]
)
cc_proto_library(
name = "lasers_proto_cc",
deps = [
":lasers_proto",
],
)
py_proto_library(
name = "lasers_proto_py",
deps = [
":lasers_proto",
],
)
2.分别编写前后雷达消息发送节点
component_common02 目录下新建 C++ 文件 front_laser.cc,输入如下内容:
/*
前置雷达发布
*/
#include "cyber/cyber.h"
#include "cyber/demo_base_proto/lasers.pb.h"
using apollo::cyber::demo_base_proto::Lasers;
int main(int argc, char *argv[])
{
apollo::cyber::Init(argv[0]);
AINFO << "模拟前雷达节点....";
auto pub_node = apollo::cyber::CreateNode("front_laser_node");
auto pub = pub_node->CreateWriter<Lasers>("/front/laser");
apollo::cyber::Rate rate(1.0);
auto lasers = std::make_shared<Lasers>();
lasers->set_count(2);
uint64_t seq = 0;
while (apollo::cyber::OK())
{
seq++;
lasers->set_seq(seq);
pub->Write(lasers);
rate.Sleep();
}
apollo::cyber::WaitForShutdown();
return 0;
}
component_common02 目录下新建 C++ 文件 back_laser.cc,输入如下内容:
/*
前置雷达发布
*/
#include "cyber/cyber.h"
#include "cyber/demo_base_proto/lasers.pb.h"
using apollo::cyber::demo_base_proto::Lasers;
int main(int argc, char *argv[])
{
apollo::cyber::Init(argv[0]);
AINFO << "模拟后雷达节点....";
auto pub_node = apollo::cyber::CreateNode("back_laser_node");
auto pub = pub_node->CreateWriter<Lasers>("/back/laser");
apollo::cyber::Rate rate(0.2);
auto lasers = std::make_shared<Lasers>();
lasers->set_count(3);
uint64_t seq = 0;
while (apollo::cyber::OK())
{
seq++;
lasers->set_seq(seq);
pub->Write(lasers);
rate.Sleep();
}
apollo::cyber::WaitForShutdown();
return 0;
}
配置文件BUILD添加内容如下:
cc_binary(
name = "front_laser",
srcs = ["front_laser.cc"],
deps = [
"//cyber",
"//cyber/demo_base_proto:lasers_proto_cc"
],
)
cc_binary(
name = "back_laser",
srcs = ["back_laser.cc"],
deps = [
"//cyber",
"//cyber/demo_base_proto:lasers_proto_cc"
],
)
接下来可以编译并执行,以测试程序是否正确。
实现流程
上述需求可以通过组件实现,只要包括如下步骤:
- 自定义类继承 Component 类,并重写其 Init() 与 Proc() 函数;
- 编写 dag 文件与 launch 文件;
- 编辑BUILD文件;
- 编译执行。
1.继承并重写 Component 类
component_common02 目录下新建 C++ 文件 lasers_cpt.h,输入如下内容:
#include "cyber/component/component.h"
#include "cyber/demo_base_proto/lasers.pb.h"
using apollo::cyber::Component;
using apollo::cyber::demo_base_proto::Lasers;
class LaserCpt : public Component<Lasers,Lasers> {
public:
bool Init() override;
bool Proc(const std::shared_ptr<Lasers>& front_laser,const std::shared_ptr<Lasers>& back_laser) override;
private:
std::shared_ptr<apollo::cyber::Writer<Lasers>> pub = nullptr;
uint64_t seq;
};
CYBER_REGISTER_COMPONENT(LaserCpt)
在 component_common02 目录下新建 C++ 文件 lasers_cpt.cc,输入如下内容:
#include "cyber/demo_cc/component_common02/lasers_cpt.h"
using apollo::cyber::demo_base_proto::Lasers;
bool LaserCpt::Init(){
AINFO << ".....lasers filter init.......";
pub = this->node_->CreateWriter<Lasers>("/laser");
seq = 0;
return true;
}
bool LaserCpt::Proc(const std::shared_ptr<Lasers>& front_laser,const std::shared_ptr<Lasers>& back_laser){
uint64_t seq_front = front_laser->seq();
uint64_t seq_back = back_laser->seq();
uint64_t num_front = front_laser->count();
uint64_t num_back = back_laser->count();
uint64_t sum = num_back + num_front;
AINFO << "total sum = " << sum << ", front seq = " << seq_front << ", back seq = " << seq_back;
seq++;
auto laser = std::make_shared<Lasers>();
laser->set_seq(seq);
laser->set_count(sum);
pub->Write(laser);
return true;
}
代码解释:
使用的模板与订阅的消息类型一致,此处为两通道数据,最多可以支持四通道数据。
Init() 函数是用于初始化的,只会执行一次。
proc()函数在订阅到消息时就会被回调执行。
2.编写 dag 文件与 launch 文件
在 component_common02 目录下新建 cpt2.dag 文件,输入如下内容:
# Define all coms in DAG streaming.
module_config {
module_library : "/apollo/bazel-bin/cyber/demo_cc/component_common02/lib_lasers_cpt.so"
components {
class_name : "LaserCpt"
config {
name : "my_common2"
readers {
channel: "/front/laser"
}
readers {
channel: "/back/laser"
}
}
}
}
在 component_common02 目录下新建 cpt2.launch 文件,输入如下内容:
<cyber>
<module>
<name>my_common2</name>
<dag_conf>/apollo/cyber/demo_cc/component_common02/cpt2.dag</dag_conf>
<process_name>my_common2</process_name>
</module>
</cyber>
3.编辑BUILD文件
配置文件BUILD添加内容如下:
package(default_visibility = ["//visibility:public"])
# https://docs.bazel.build/versions/master/be/c-cpp.html#cc_library
cc_library(
name = "lasers_cpt_lib",
srcs = ["lasers_cpt.cc"],
hdrs = ["lasers_cpt.h"],
deps = [
"//cyber",
"//cyber/demo_base_proto:lasers_proto_cc"
],
)
# https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary
cc_binary(
name = "lib_lasers_cpt.so",
linkshared = True,
linkstatic = False,
deps = [":lasers_cpt_lib"],
)
filegroup(
name = "conf",
srcs = [
":cpt2.dag",
":cpt2.launch",
],
)
4.编译执行
编译:
bazel build cyber/demo_cc/component_common02/...
执行(需要三个终端):
终端A执行前雷达发布方:
source cyber/setup.bash
./bazel-bin/cyber/demo_cc/component_common02/front_laser
终端B执行后雷达发布方:
source cyber/setup.bash
./bazel-bin/cyber/demo_cc/component_common02/back_laser
终端C执行组件:
source cyber/setup.bash
cyber_launch start cyber/demo_cc/component_common02/cpt2.launch
或执行 dag 文件:
mainboard -d cyber/demo_cc/component_common02/cpt2.dag
关闭组件(需要系启动终端):
source cyber/setup.bash
cyber_launch stop cyber/demo_cc/component_common02/cpt2.launch
执行结果:会对前后雷达检测到的障碍物进行融合。