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.
- 启动