How_to_add_a_subnode
添加文件
- 在modules/perception/obstacle/onboard新建两个文件,我这里分别是zuo_test_subnode.cc和zuo_test_subnode.h。
实现基础代码
- 添加一个子节点类,我们这里假定是放在perception模块下,那要记得加namespace。
- 除此之外,因为整体的子节点框架是用多态的方法来调用的,所以我们的子类要继承Subnode。
- 既然是继承了,记得要实现父类的纯虚函数。
- 这里假设我的节点名为ZuoTestSubnode,具体代码如下:
//-- zuo_test_subnode.h
#ifndef MODULES_PERCEPTION_OBSTACLE_ONBOARD_ZUO_TEST_SUBNODE_H_
#define MODULES_PERCEPTION_OBSTACLE_ONBOARD_ZUO_TEST_SUBNODE_H_
//-- 子节点基类(抽象类)public继承自Thread
#include "modules/perception/onboard/subnode.h"
/**
* Zuo add on 2018-04-02
* How to add a subnode
*/
namespace apollo {
namespace perception {
class ZuoTestSubnode : public Subnode {
public:
ZuoTestSubnode() = default;
~ZuoTestSubnode() = default;
//-- Zuo commented on 2018-04-02
//-- 如果不需要用到事件处理函数,那么就如下实现即可。
//-- 如果需要用到事件处理,可以参考VisualizationSubnode的实现
//-- ProcEvents()会在Subnode::Run()被调用
apollo::common::Status ProcEvents() override {
return apollo::common::Status::OK();
}
private:
bool InitInternal() override;
};
//-- 节点注册
REGISTER_SUBNODE(ZuoTestSubnode);
} // namespace perception
} // namespace apollo
//-- zuo_test_subnode.cc
#include "modules/perception/obstacle/onboard/zuo_test_subnode.h"
namespace apollo {
namespace perception {
bool ZuoTestSubnode::InitInternal() {
//-- Zuo add a test info output --//
AINFO << "===== Zuo test info on zuo_test_subnode.cc InitInternal =====";
return true;
}
} // namespace perception
} // namespace apollo
注册节点
可以看到,在头文件zuo_test_subnode.h后面我添加了
REGISTER_SUBNODE(ZuoTestSubnode)
这里是为了注册这个子节点,它是一个宏定义,展开会生成一些函数和类,具体可以在/apollo-master/modules/perception/lib/base/registerer.h里面找到定义。如下:
#define REGISTER_CLASS(clazz, name) \
class ObjectFactory##name : public apollo::perception::ObjectFactory { \
public: \
virtual ~ObjectFactory##name() {} \
virtual perception::Any NewInstance() { \
return perception::Any(new name()); \
} \
}; \
inline void RegisterFactory##name() { \
perception::FactoryMap &map = perception::GlobalFactoryMap()[#clazz]; \
if (map.find(#name) == map.end()) map[#name] = new ObjectFactory##name(); \
}
这里的注册,实际是定义一些实例化对象的函数,如GetInstanceByName, GetUniqInstanceName, NewInstance等等。本质上都是在头文件中宏展开,这些在registerer.h文首有一个关于如何使用Registerer的简短教程,大家可自行查阅。这里稍微解释下,上文中的##
是字符串拼接的作用,可以将前后的字符串拼接在一起,例如这里我们调用的时候,name参数传入的是ZuoTestSubnode
,所以RegisterFactory##name()
实际会是RegisterFactoryZuoTestSubnode()
在Apollo里面大量的用到了##拼接加宏定义,展开为类、函数的方法,虽然它能大大增加了代码的复用率,但是也有一个很不好的缺点,由于是拼接的函数名,所以IDE不能跳转找到,甚至都不会搜索到,如果你不熟悉此方法,可能一开始会有点晕头转向。
在perception.cc里面增加子节点的头文件:
#include "modules/perception/obstacle/onboard/zuo_test_subnode.h"
在perception.cc::RegistAllOnboardClass()里面调用RegisterFactoryZuoTestSubnode函数:
void Perception::RegistAllOnboardClass() {
/// regist sharedata
RegisterFactoryLidarObjectData();
......
//-- Zuo add on 2018-04-03 --//
RegisterFactoryZuoTestSubnode();
AINFO << " Zuo Register TestSubnode successfull ";
//-- Zuo add on 2018-04-03 --//
}
修改BUILD文件
- 在BUILD里面增加一个zuo_test_subnode编译单元。在/apollo-master/modules/perception/obstacle/onboard/BUILD里面增加一个代码块,如下:
cc_library(
name = "zuo_test_subnode",
srcs = [
"zuo_test_subnode.cc",
],
hdrs = [
"zuo_test_subnode.h",
"object_shared_data.h",
],
deps = [
":perception_obstacle_shared_data",
"//modules/common:log",
"//modules/common/adapters:adapter_manager",
"//modules/perception/common",
"//modules/perception/lib/config_manager",
"//modules/perception/onboard",
"@eigen",
"@opencv2//:core",
"@ros//:ros_common",
],
)
这里有些依赖项没必要加,但是我也放在这里做一个实例。
这是bazel的写法,和cmake有所区别,但是原理大致相同,各个标签意思如下:
- name: 模块名字,用来在上一级BUILD文件的引用**
- srcs/hdrs: 对应的实现文件和头文件**
- deps: 依赖项
- bazel Guide Doc
- 在perception的BUILD的依赖项里面增加子节点。如下:
cc_library(
name = "perception_lib",
srcs = ["perception.cc"],
hdrs = [
"perception.h",
],
deps = [
"//modules/common",
......
"//modules/perception/obstacle/onboard:zuo_test_subnode",
......
],
)
修改config文件
- 在/apollo-master/modules/perception/conf/dag_camera_obstacle_vis.config里面增加一段TestNode的信息。例如:
subnode_config {
......
# Test node. Zuo added on 2018-04-08
# id 我是随便设置的不重复的
# name 节点的类名
# device_id 跟节点头文件里面的device_id对应上
subnodes {
id: 4
name: "ZuoTestSubnode"
reserve: "device_id:ZuoTest;publish:1;"
type: SUBNODE_IN
}
......
}
这里因为我执行的是scripts/perception_offline_visualizer.sh,因为在脚本里面设置了--dag_config_path="./conf/dag_camera_obstacle_vis.config"
,所以我这里需要在对应的config文件里面增加ZuoTestSubnode
流程图
- 启动
- Topic配置
2.