Apollo如何添加一个子节点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012423865/article/details/79870904

How_to_add_a_subnode

  1. 添加文件

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

    这里写图片描述

  2. 实现基础代码

    • 添加一个子节点类,我们这里假定是放在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
  3. 注册节点

    ​ 可以看到,在头文件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 --//
    }
  4. 修改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",
          ......
       ],
      )
  5. 修改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

  6. 流程图

    1. 启动
      这里写图片描述
    2. Topic配置
      这里写图片描述2.

猜你喜欢

转载自blog.csdn.net/u012423865/article/details/79870904