How_to_add_a_subnode

添加文件
  • modules/perception/obstacle/onboard新建两个文件,我这里分别是zuo_test_subnode.cczuo_test_subnode.h

bpmn创建子节点时自动添加extensionElements_子节点

实现基础代码
  • 添加一个子节点类,我们这里假定是放在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
  • perceptionBUILD的依赖项里面增加子节点。如下:
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

流程图
  1. 启动
  2. Topic配置
    2.