前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自动驾驶 Apollo 源码分析系列,感知篇(二):Perception 如何启动?

自动驾驶 Apollo 源码分析系列,感知篇(二):Perception 如何启动?

作者头像
Frank909
发布2021-12-06 11:40:57
1.6K0
发布2021-12-06 11:40:57
举报
文章被收录于专栏:Frank909

从 Apollo 的官方文档,我们很容易得知 Perception 是核心的组件之一,但像所有的 C++ 程序一样,每个应用都有一个 Main 函数入口,那么引出本文要探索的 2 个问题:

  1. Perception 的入口在哪里?
  2. Perception 如何启动?

CyberRT

在讲 Perception 组件具体内容前,非常有必要讲 CyberRT。

Apollo Cyber RT framework is built based on the concept of component. As a basic building block of Apollo Cyber RT framework, each component contains a specific algorithm module which process a set of data inputs and generate a set of outputs. – Apollo github.com

CyberRT 就是 Apollo 中的一套基础框架,是面向组件(component)的。组件呈现高度的模块化。

每个组件包含特定的算法,用于处理数据输入,并输出算法处理的结果。

玩过 ROS 的同学应该对此类东西不陌生,CyberRT 和 ROS 类似,实际上 Apollo 最初也是用的 ROS1,后来因为时延问题得不到满足,所以自行开发了一个类似的,但性能更好。

回到组件问题,Perception 也是组件,之前的文章有介绍,它接收传感器的数据,然后输出障碍物的 3D 信息。

在 CyberRT 中,有如何定义、实现、启动组件的机制说明。

组件管理

通常 4 个步骤进行组件开发:

  • 设置组件文件结构
  • 实现组件类
  • 设置配置文件
  • 启动组件

Perception 组件相关文件

按照 Apollo 官方文档提示,一个 component 相关的文档有这几个:

代码语言:javascript
复制
Header file: common_component_example.h
Source file: common_component_example.cc
Build file: BUILD
DAG dependency file: common.dag
Launch file: common.launch

按照提示,我们就可以去源码中搜索相关的文件。

Apollo 6.0 官方文档有这么一句:

The Perception module is now capable of detecting and classifying obstacles within only one component named Detection component.

这是说 Perception 模块现在可以只有一个组件:Dectection。

为什么这么说呢?

Apollo 是多数据融合的,它融合 Camera、Lidar、Radar 目标,而这 3 个都是一个 component。

在这里插入图片描述
在这里插入图片描述

我们可以先从总入口出发,再一个个分析。

所以,我们得先寻找 Detection 相关的组件。

很容易找到,路径:

代码语言:javascript
复制
apollo/modules/perception/onboard/component

这个目录下,定义和实现了很多感知相关的组件,本文只关注于 Detection。

它的两个相关文件是:

  • detection_component.h
  • detection_component.cc

detection_component.h

代码语言:javascript
复制
namespace apollo {
namespace perception {
namespace onboard {

class DetectionComponent : public cyber::Component<drivers::PointCloud> {
 public:
  DetectionComponent() = default;
  virtual ~DetectionComponent() = default;

  bool Init() override;
  bool Proc(const std::shared_ptr<drivers::PointCloud>& message) override;

 private:
  static std::atomic<uint32_t> seq_num_;
  std::string sensor_name_;
  // bool enable_hdmap_ = true;
  float lidar_query_tf_offset_ = 20.0f;
  std::string lidar2novatel_tf2_child_frame_id_;
  std::string output_channel_name_;
  base::SensorInfo sensor_info_;
  TransformWrapper lidar2world_trans_;
  std::unique_ptr<lidar::LidarObstacleDetection> detector_;
  std::shared_ptr<apollo::cyber::Writer<LidarFrameMessage>> writer_;
};

CYBER_REGISTER_COMPONENT(DetectionComponent);

}  // namespace onboard
}  // namespace perception
} 

可以看到是以点云数据输入为主。

实现组件

detection_component.cc

代码语言:javascript
复制
bool DetectionComponent::Init() {
  LidarDetectionComponentConfig comp_config;
  if (!GetProtoConfig(&comp_config)) {
    return false;
  }
  ADEBUG << "Lidar Component Configs: " << comp_config.DebugString();
  output_channel_name_ = comp_config.output_channel_name();
  sensor_name_ = comp_config.sensor_name();
  lidar2novatel_tf2_child_frame_id_ =
      comp_config.lidar2novatel_tf2_child_frame_id();
  lidar_query_tf_offset_ =
      static_cast<float>(comp_config.lidar_query_tf_offset());
  //  enable_hdmap_ = comp_config.enable_hdmap();
  writer_ = node_->CreateWriter<LidarFrameMessage>(output_channel_name_);

  if (!InitAlgorithmPlugin()) {
    AERROR << "Failed to init detection component algorithm plugin.";
    return false;
  }
  return true;
}

bool DetectionComponent::Proc(
    const std::shared_ptr<drivers::PointCloud>& message) {
  AINFO << std::setprecision(16)
        << "Enter detection component, message timestamp: "
        << message->measurement_time()
        << " current timestamp: " << Clock::NowInSeconds();

  auto out_message = std::make_shared<LidarFrameMessage>();

  bool status = InternalProc(message, out_message);
  if (status) {
    writer_->Write(out_message);
    AINFO << "Send lidar detect output message.";
  }
  return status;
}

Init 和 Proc 是组件两个核心方法。

BUILD 文件地址是:

apollo/modules/perception/onboard/component/BUILD

BUILD 文件定义了 perception 中所有的 component 如 camera,radar,lidar 等的信息,本文只关注 Detection。

代码语言:javascript
复制
cc_library(
    name = "detection_component",
    srcs = ["detection_component.cc"],
    hdrs = ["detection_component.h"],
    deps = [
        ":lidar_inner_component_messages",
        "//cyber/time:clock",
        "//modules/common/util:string_util",
        "//modules/perception/common/sensor_manager",
        "//modules/perception/lib/registerer",
        "//modules/perception/lidar/app:lidar_obstacle_detection",
        "//modules/perception/lidar/common",
        "//modules/perception/onboard/common_flags",
        "//modules/perception/onboard/proto:lidar_component_config_cc_proto",
        "//modules/perception/onboard/transform_wrapper",
        "@eigen",
    ],
)

设置配置文件

一个 Component 的配置文件有 2 种:

  • DAG
  • Launch

DAG 定义了模块的依赖关系。

Launch 文件定义了模块的启动。

先看 Launch 文件。

apollo/modules/perception/production/launch/perception_all.launch

代码语言:javascript
复制
<cyber>
    <desc>cyber modules list config</desc>
    <version>1.0.0</version>
    <!-- sample module config, and the files should have relative path like
         ./bin/cyber_launch
         ./bin/mainboard
         ./conf/dag_streaming_0.conf -->
    <module>
        <name>perception</name>
        <dag_conf>/apollo/modules/perception/production/dag/dag_streaming_perception.dag</dag_conf>
        <!-- if not set, use default process -->
        <process_name>perception</process_name>
        <version>1.0.0</version>
    </module>
    <module>
        <name>perception_camera</name>
        <dag_conf>/apollo/modules/perception/production/dag/dag_streaming_perception_camera.dag</dag_conf>
        <!-- if not set, use default process -->
        <process_name>perception</process_name>
        <version>1.0.0</version>
    </module>

    <module>
        <name>perception_traffic_light</name>
        <dag_conf>/apollo/modules/perception/production/dag/dag_streaming_perception_trafficlights.dag</dag_conf>
        <!-- if not set, use default process -->
        <process_name>perception_trafficlights</process_name>
        <version>1.0.0</version>
    </module>
    <module>
        <name>motion_service</name>
        <dag_conf>/apollo/modules/perception/production/dag/dag_motion_service.dag</dag_conf>
        <!-- if not set, use default process -->
        <process_name>motion_service</process_name>
        <version>1.0.0</version>
    </module>
</cyber>

我们可以发现 Perception 模块中的 dag 路径:

代码语言:javascript
复制
 <dag_conf>/apollo/modules/perception/production/dag/dag_streaming_perception.dag</dag_conf>

它里面的内容长什么样子呢?

代码语言:javascript
复制
module_config {
  module_library : "/apollo/bazel-bin/modules/perception/onboard/component/libperception_component_lidar.so"

  components {
    class_name : "DetectionComponent"
    config {
      name: "Velodyne128Detection"
      config_file_path: "/apollo/modules/perception/production/conf/perception/lidar/velodyne128_detection_conf.pb.txt"
      flag_file_path: "/apollo/modules/perception/production/conf/perception/perception_common.flag"
      readers {
          channel: "/apollo/sensor/lidar128/compensator/PointCloud2"
        }
    }
  }

  components {
    class_name : "RecognitionComponent"
    config {
      name: "RecognitionComponent"
      config_file_path: "/apollo/modules/perception/production/conf/perception/lidar/recognition_conf.pb.txt"
      readers {
          channel: "/perception/inner/DetectionObjects"
        }
    }
  }

  components {
    class_name: "RadarDetectionComponent"
    config {
      name: "FrontRadarDetection"
      config_file_path: "/apollo/modules/perception/production/conf/perception/radar/front_radar_component_conf.pb.txt"
      readers {
          channel: "/apollo/sensor/radar/front"
        }
    }
  }

  components {
    class_name: "RadarDetectionComponent"
    config {
      name: "RearRadarDetection"
      config_file_path: "/apollo/modules/perception/production/conf/perception/radar/rear_radar_component_conf.pb.txt"
      readers {
          channel: "/apollo/sensor/radar/rear"
        }
    }
  }

  components {
    class_name: "FusionComponent"
    config {
      name: "SensorFusion"
      config_file_path: "/apollo/modules/perception/production/conf/perception/fusion/fusion_component_conf.pb.txt"
      readers {
          channel: "/perception/inner/PrefusedObjects"
        }
    }
  }
}

module_config {
  module_library : "/apollo/bazel-bin/modules/v2x/fusion/apps/libv2x_fusion_component.so"

  components {
    class_name : "V2XFusionComponent"
    config {
      name : "v2x_fusion"
      flag_file_path : "/apollo/modules/v2x/conf/v2x_fusion_tracker.conf"
      readers: [
        {
          channel: "/perception/vehicle/obstacles"
        }
      ]
    }
  }
}

我们发现了 DetectionComponent 的身影,看它的配置参数是 Velodyne 128 线激光雷达的配置文件,确实可以看到 Apollo 是以 Lidar 为主。

启动组件

定义了一个 component 相关的文档后,就可以启动了。

命令:

代码语言:javascript
复制
cyber_launch start apollo/modules/perception/production/launch/perception_all.launch

自此,我们就发现了在 Apollo 中启动 perception 一个组件的整个代码过程。

总结

因为 Perception 这个模块非常庞大,涉及到 Camera、Radar、Lidar 3 种类型的传感器,针对各个传感器的数据处理和模型处理会产生 10 多个任务,每个任务都被设计成了组件。

直接去阅读相关的代码会非常容易让自己迷失在代码森林中,所以,本文先讲解一下 CyberRT 这个基础框架 Component 的配置机制,熟悉基础套路后,以后再去学习相应组件时,查询代码就变得非常容易。

后续文章将从 Camera 开始,逐个分析与数据融合相关的 component 基础算法及代码实现,任务有点艰巨,但相信会有很多收获。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/12/23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CyberRT
    • 组件管理
    • Perception 组件相关文件
    • 实现组件
    • 设置配置文件
    • 启动组件
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档