实验内容
Component 是 Cyber RT 提供的用来构建功能模块的基础类,Component 有两种类型,分别为 Component 和 TimerComponent。
相较于 Component,TimerComponent 不提供消息融合,也不由消息触发运行,而是由系统定时调用,可用来执行一些例行任务。
本实验将编写一个 TimerComponent 实例,来模拟传感器产生数据。
实验流程
创建TimerComponent模板实例
进入apollo容器,终端执行以下命令,创建实验代码目录
buildtool create --template timer_component component/timer_component_sensor
最终生成component目录,其目录结构如下:
./component/
`-- timer_component_sensor
|-- BUILD
|-- conf
| |-- timer_component_sensor.conf
| `-- timer_component_sensor.pb.txt
|-- cyberfile.xml
|-- dag
| `-- timer_component_sensor.dag
|-- launch
| `-- timer_component_sensor.launch
|-- proto
| |-- BUILD
| `-- timer_component_sensor.proto
|-- timer_component_sensor_component.cc
`-- timer_component_sensor_component.h
- BUILD 文件为 TimerComponent 的源码编译的规则文件
- conf 目录下
timer_component_sensor.conf
为全局变量配置文件timer_component_sensor.pb.txt
为用户在 proto 文件中定义的可配置项的配置文件cyberfile.xml
为timer_component_sensor
功能包的描述文件- dag 目录下的
timer_component_sensor.dag
文件中描述了timer_component_sensor
功能包的依赖关系- launch 文件夹下
timer_component_sensor.launch
为timer_component_sensor
功能包的 launch 启动文件- proto 文件夹下的
- BUILD 为用户在 proto 文件夹下定义的 protobuffer 文件的编译规则文件
timer_component_sensor.proto
文件中用户可以定义自己的消息结构timer_component_sensor.cc
和timer_component_sensor.h
两个文件为 TimerComponent 的源文件和头文件。
定义消息结构
在timer_component_sensor.proto
中,添加以下消息数据结构。
syntax = "proto2";
package apollo;
// message type of channel, just a placeholder for demo,
// you should use `--channel_message_type` option to specify the real message type
//定义相机传感器的消息结构
message CameraSensorMsg {
optional string content =1;//消息内容
optional uint64 msg_id =2;//消息id
optional uint64 timestamp=3;//发送消息的时间戳
}
//定义激光雷达传感器的消息结构
message LidarSensorMsg {
optional string content =1;//消息内容
optional uint64 msg_id =2;//消息id
optional uint64 timestamp=3;//发送消息的时间戳
}
//配置TimerComponentSensorConfig的名称和输出数据的channel
message TimerComponentSensorConfig {
optional string camera_name = 1;
optional string camera_sensor_topic=2;
optional string lidar_name=3;
optional string lidar_sensor_topic=4;
};
在 proto 文件夹下的 BUILD 文件中,添加 protobuffer 文件的编译规则。
load("//tools:apollo_package.bzl", "apollo_package")
load("//tools/proto:proto.bzl", "proto_library")
load("//tools:cpplint.bzl", "cpplint")
package(default_visibility = ["//visibility:public"])
proto_library(
name = "timer_component_sensor_proto",
srcs = ["timer_component_sensor.proto"],
)
apollo_package()
cpplint()
配置TimerComponent的配置文件
在timer_component_sensor.pb.txt
中,配置timer_component_sensor.proto
文件中定义的可配置项。
camera_name: "camera-sensor"
camera_sensor_topic: "/sensor/camera"
lidar_name: "lidar-sensor"
lidar_sensor_topic: "/sensor/lidar"
编写TimerComponent的源文件
修改timer_component_sensor.h
文件:
/******************************************************************************
* Copyright 2023 The Apollo Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
/******************************************************************************
* @file timer_component_sensor_component.h
*****************************************************************************/
#pragma once
#include <memory>
#include "cyber/common/macros.h"
#include "cyber/component/component.h"
#include "cyber/component/timer_component.h"
#include "cyber/cyber.h"
#include "component/timer_component_sensor/proto/timer_component_sensor.pb.h"
using apollo::cyber::Time;
using apollo::cyber::Writer;
namespace apollo {
class TimerComponentSensor final
: public apollo::cyber::TimerComponent {
public:
bool Init() override;
bool Proc() override;
private:
apollo::TimerComponentSensorConfig config_;
//定义camera的消息writer
std::shared_ptr<Writer<CameraSensorMsg>> camera_sensor_writer_=nullptr;
//定义lidar的消息writer
std::shared_ptr<Writer<LidarSensorMsg>> lidar_sensor_writer_=nullptr;
};
CYBER_REGISTER_COMPONENT(TimerComponentSensor)
} // namespace apollo
修改
timer_component_sensor.cc`文件。
/******************************************************************************
* Copyright 2023 The Apollo Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
/******************************************************************************
* @file timer_component_sensor_component.cc
*****************************************************************************/
#include "component/timer_component_sensor/timer_component_sensor_component.h"
namespace apollo {
bool TimerComponentSensor::Init() {
ACHECK(ComponentBase::GetProtoConfig(&config_))
<< "failed to load timer_component_sensor config file "
<< ComponentBase::ConfigFilePath();
AINFO << "Load config succedded.\n" << config_.DebugString();
//创建camera和lidar的writer
camera_sensor_writer_=node_->CreateWriter<CameraSensorMsg>(config_.camera_sensor_topic().c_str());
lidar_sensor_writer_=node_->CreateWriter<LidarSensorMsg> (config_.lidar_sensor_topic().c_str());
AINFO << "Init TimerComponentSensor succedded.";
return true;
}
bool TimerComponentSensor::Proc() {
AINFO << "Proc TimerComponentSensor triggered.";
//封装camera消息
static int i=0;
auto camera_out_msg=std::make_shared<CameraSensorMsg>();
camera_out_msg->set_msg_id(++i);
camera_out_msg->set_content(config_.camera_name());
camera_out_msg->set_timestamp(Time::Now().ToNanosecond());
//将camera消息写入通道
camera_sensor_writer_->Write(camera_out_msg);
//封装lidar消息
auto lidar_out_msg=std::make_shared<LidarSensorMsg>();
lidar_out_msg->set_msg_id(++i);
lidar_out_msg->set_content(config_.lidar_name());
lidar_out_msg->set_timestamp(Time::Now().ToNanosecond());
//写入lidar消息
lidar_sensor_writer_->Write(lidar_out_msg);
return true;
}
} // namespace apollo
修改 BUILD 文件
load("//tools:apollo_package.bzl", "apollo_cc_library", "apollo_cc_binary", "apollo_package", "apollo_component")
load("//tools:cpplint.bzl", "cpplint")
package(default_visibility = ["//visibility:public"])
filegroup(
name = "timer_component_sensor_files",
srcs = glob([
"dag/**",
"launch/**",
"conf/**",
]),
)
apollo_component(
name = "libtimer_component_sensor_component.so",
srcs = [
"timer_component_sensor_component.cc",
],
hdrs = [
"timer_component_sensor_component.h",
],
linkstatic = True,
deps = [
"//cyber",
"//component/timer_component_sensor/proto:timer_component_sensor_proto",
],
)
apollo_package()
cpplint()
编译TimerComponent功能包
在终端中,执行以下指令,编译 timer_component_sensor 功能包。
root@in-dev-docker:/apollo_workspace# buildtool build -p component/timer_component_sensor/
出现如下信息即为编译成功
修改启动配置
修改TimerComponent的dag文件
在timer_component_sensor.dag
文件中,将 interval 项的值改为 500,即每 500ms 运行一次。interval 值为 TimerComponent 的运行时间间隔。
module_config {
module_library : "component/timer_component_sensor/libtimer_component_sensor_component.so"
timer_components {
class_name : "TimerComponentSensor"
config {
name: "timer_component_sensor"
config_file_path: "component/timer_component_sensor/conf/timer_component_sensor.pb.txt"
flag_file_path: "component/timer_component_sensor/conf/timer_component_sensor.conf"
interval: 500
}
}
}
修改TimerComponent的launch文件
在<dag_conf>标签内的 dag 文件路径前加上“ ./ ” 。由于目前 cyber 与 apollo 绑定的比较紧密,编译完成后,系统会把编译产出及配置文件拷贝到 apollo 相应目录下,且执行文件时,系统会优先执行 apollo 目录下的文件,这样就会导致此处的配置无法起作用,这里加上“ ./ ”,就是告诉系统使用此处的 dag 文件来运行 component。
<cyber>
<module>
<name>communication</name>
<dag_conf>./communication/dag/communication.dag</dag_conf>
<process_name>communication</process_name>
</module>
</cyber>
运行TimerComponent
方式一:使用mainboard运行timer_component_sensor.dag文件
在终端中,输入以下指令,使用 mainboard 工具运行timer_component_sensor.dag
文件,运行timer_component_sensor
功能包。
mainboard -d ./component/timer_component_sensor/dag/timer_component_sensor.dag
方式二:使用cyber_launch运行timer_component_sensor.launch文件
在终端中,也可以使用 cyber_launch 工具运行timer_component_sensor.launch
文件,运行timer_component_sensor
功能包。
查看TimerComponent运行结果
使用cyber_monitor工具查看timer_component_sensor运行结果。
新启一个终端窗口,在终端中输入执行 cyber_monitor 命令,启动cyber_monitor工具。
cyber_monitor
参考:
apollo.baidu.com/community/Apollo-Homepage-Document?doc=BYFxAcGcC4HpYIbgPYBtXIHQCMEEsATAV0wGNkBbWA5UyRFdZWVBEAU0hFgoIH0adPgCY%2BADwCiAVnEBBCeIAcATnETFcgMxKZkgGxKAwkoDsa3YoAi45WdGSLxsYt0SzY%2BXICMa98oAMSgYALF7%2B2NhemsLBJsrCYZqKwors7AikBIp6miYmpFJSXpigFKhAA
Apollo开发者社区_cyber专项课(9.0版)