介绍
感知模块结合了使用多个摄像头、雷达(前后)和激光雷达来识别障碍物并融合它们各自的轨迹以获得最终轨迹列表的能力。障碍物子模块对障碍物进行检测、分类和跟踪。该子模块还预测障碍物运动和位置信息(例如,航向和速度)。对于车道线,我们通过后处理车道解析像素来构造车道实例,并计算车道与本车的相对位置(L0、L1、R0、R1 等)。
感知的目的
1、障碍物检测(车、行人或者其他交通要素)
2、红绿灯检测
借助于激光雷达和深度学习,Apollo的感知模块需要接收传感器信息以及自车速度信息,经过内部算法处理最终输出障碍物的3D轨迹和交通灯探测结果,其中3D障碍物轨迹其实就是融合的体现。
融合就是将多传感器进行融合。最主要的部分就是cmera,radar,lidar,fusion。
Camera
camera的任务有四个:障碍物感知、车道检测、交通灯检测、障碍物和车道检测基础上计算出来的cipv。
Radar
处理障碍物检测。
Lidar
Lidar 的感知主要是处理点云数据,Apollo 6.0 会应用 PointPillar 模型得到障碍物的 3D 信息,也就是能得到障碍物的 3D 尺寸框加上速度和偏航角信息。
Lidar 输出的信息送到 Fusion 组件和 Camera 、Radar 的结果进行融合,形成最终的 3D 障碍物跟踪轨迹。
Fusion
fusion是感知模块的核心,不同的自动驾驶场景要求的传感器不一样,也许是纯视觉方案,也许是激光雷达为主,也许是视觉+毫米波雷达,但无论传感器怎么配置,多传感器的融合也必不可少。
融合的好坏决定了感知的好坏,甚至是一款自动驾驶产品的好坏。
Apollo 要融合的东西大概这 5 样:
目标存在可能性的融合
目标运动状态的融合
目标形状的融合
目标轨迹融合
目标的类别融合
目录结构分析
base——整个感知模块公用的一些基础类型定义,比如表示感知目标的Object等类型;
camera——相机处理子模块;主要实现车道线识别、红绿灯检测以及障碍物识别追踪。
common——整个感知模块公用的一些基础操作定义,如点云预处理、图像预处理等;可以理解为该模块的一些库函数。
data——感知模块用到的数据,目前只有相机的标定参数yaml文件;
fusion——融合处理子模块;
inference——深度学习推理模块;
lib——整个感知模块公用的一些算法定义,如config_manager参数配置操作;
lidar——激光雷达处理子模块;主要实现障碍物识别和追踪(对点云做分割、分类、识别等)
map——高精度地图的一些操作,主要在感知模块中用于提取感兴趣区域;
onboard——定义多个子模块实现(包括初始化函数和处理函数,但是这些组件只是入口,具体实现还是要去阅读process函数),每个子模块对应一个功能,包括车道线识别、障碍物识别、红绿灯识别、传感器融合、场景分割等。分别用来处理不同的传感器信息(Lidar,Radar,Camera)。各个子模块入口在这个目录中,每个传感器流程大致可以分为预处理、物体识别、感兴趣区域过滤以及追踪。
production——感知模块所有配置参数定义;感知模块入口在这个目录,一个launch文件中包含多个dag文件(dag文件就是配置文件),通过lanuch加载对应的dag,一个launch文件启动多个子模块。
proto——感知模块protobuf文件定义;定义数据结构
radar——毫米波雷达处理子模块.主要实现障碍物识别和追踪(主要是障碍物追踪)
testdata——提前设置好的数据
BUILD——定义构建规则
感知模块由production开始,由fusion模块结束。阅读代码顺序最好为:
production/.launch -> production/.dag -> onboard/component/*componet.cc -> fusion/app 或者 lidar/app等等
启动感知模块
CyberRT是Apollo中的一套基础框架,是面向组件的,组件呈现高度模块化。Apollo的感知模块接受传感器数据,输出障碍物3D信息。
1 组件管理
①设置组件文件结构
②实现组件类
③设置配置文件
④启动组件
2 感知模块组件相关文件
Header file: common_component_example.h
Source file: common_component_example.cc
Build file: BUILD
DAG dependency file: common.dag
Launch file: common.launch
*感知模块只有一个组件Dectection,因为它融合了camera,lidar,radar。
3 Dection相关组件
头文件和实现文件
目录
apollo/modules/perception/onboard/component
中有detection_component.h头文件和detection_component.cc实现文件,在实现文件中 可以发现init和Proc是两个核心方法。
BUILD文件
build文件定义感知模块中的组件信息,目录位于
apollo/modules/perception/onboard/component/BUILD
设置配置文件
配置文件有dag文件和launch文件,dag文件定义模块依赖关系,launch文件定义模块启动。
4 启动组件
cyber_launch start apollo/modules/perception/production/launch/perception_all.launch
于是就启动了perception组件
Lidar模块详解
1 目录结构
lidar
├── app //接口,以前的CNN分割,现在的PointPillars检测,以及分类跟踪
│ ├── BUILD
│ ├── lidar_app_lidar_pipeline_test.cc
│ ├── lidar_obstacle_detection.cc
│ ├── lidar_obstacle_detection.h
│ ├── lidar_obstacle_segmentation.cc
│ ├── lidar_obstacle_segmentation.h
│ ├── lidar_obstacle_tracking.cc
│ ├── lidar_obstacle_tracking.h
│ └── proto
├── common
├── lib
│ ├── classifier
│ ├── detection
│ ├── dummy
│ ├── ground_detector
│ ├── interface
│ ├── map_manager
│ ├── object_builder
│ ├── object_filter_bank
│ ├── pointcloud_preprocessor
│ ├── roi_filter
│ ├── scene_manager
│ ├── segmentation
│ └── tracker
├── README.md
└── tools
2 入口
launch文件:
Apollo/modules/perception/production/launch/perception_lidar.launch
对应的dag文件:
Apollo/modules/perception/production/dag/dag_streaming_perception_lidar.dag
其中包括DetectionComponent, RecognitionComponent, FusionComponent, V2XFusionComponent四个组件类,即检测,识别跟踪、融合、车联网融合。单对于lidar模块,主要就是检测和识别跟踪两个组件类的具体实现,融合和车联网融合是lidar模块输出结果的后续处理。
3 处理过程
DetectionComponent(检测) >> RecognitionComponent(识别跟踪)
3.1 DetectionComponent类
输入原始点云,输出雷达处理结果
参数初始化
处理函数:点云预处理
模型推理:过滤范围外点云并将点云转换为一维数组 >> 推理输出box和type >> 保存box结果和类别属性
3.2 RecognitionComponent
输入雷达处理结果,输出传感器处理结果发给融合fusion
·参数初始化
·跟踪·调整分割物体的时间戳
·对lidar2World做平移得到sensor2local转换矩阵,即局部世界坐标系
·分开前景和背景,转换成其他格式障碍物
·关联匹配过程
·卡尔曼滤波器,量测更新航迹
·收集跟踪结果,应该是用于发布到下游·分类
Radar
1 目录结构
.
├── app
│ ├── BUILD
│ ├── radar_obstacle_perception.cc //框架实现
│ └── radar_obstacle_perception.h
├── common
│ ├── BUILD
│ ├── radar_util.cc
│ ├── radar_util.h
│ └── types.h
└── lib
├── detector
├── dummy
├── interface
├── preprocessor
├── roi_filter
└── tracker
2 入口
雷达组件的定义都在融合的dag文件中
Apollo/modules/perception/production/dag/dag_streaming_perception.dag
3 RadarDetectionComponent
3.1 RadarDetectionComponent::Init()
初始化参数
3.2 RadarDetectionComponent::InternalProc()
输入原始雷达信息,输出雷达处理结果
4 ContiArsPreprocessor
Apollo/modules/perception/radar/lib/preprocessor/conti_ars_preprocessor/conti_ars_preprocessor.cc
雷达预处理
5 RadarObstaclePerception
Apollo/modules/perception/radar/app/radar_obstacle_perception.cc
核心处理函数包括检测、ROI过滤、跟踪。
红绿灯检测任务流程
下图来源于自动驾驶 Apollo 源码分析系列,感知篇(四):将红绿灯检测和识别代码细致走读一遍(byfrank909).
1 基础流程
modules/perception/onboard/component/trafficlights_perception_component.cc
①Init()
②InitConfig()
③InitAlgorithmPlugin()
④InitCameraFrame()
⑤InitCameraListeners()
⑥InitV2XListener()
1. 1 Initconfig
配置文件以proto文件保存,在
modules/perception/production/conf/perception/camera/trafficlights_perception_component.config
中定义,这个文件会将一些变量抽出来做成了配置文件形式。
1.2 InitAlgorithmPlugin
初始化算法插件,相关核心代码都在这里进行初始化。红绿灯检测分为三个部分:前处理、算法处理、后处理
1.3 Init CameraFrame
Apollo 把 Camera 中相关的数据定义为 CameraFrame。
CameraFrame 是一个 Struct,也不单单只为 TrafficLight 服务,它是通用的,可以应对车道线检测、目标检测、红绿灯检测任务。
1.4 Init CameraListeners
代码在初始化 CameraFrame 之后,进行了关键的一步,就是初始化 CameraListeners。
因为 Camera 可能有几个,所以,Listener 也对应有几个。
值得注意的地方是,运用了 C++ 11 中的 std::function 和 std::bind 模板,主要作用就是用来设置回调函数。
在这里,回调函数是 onReceiveImage,当 channel 中有数据来临时,camera reader 触发 onReceiveImage 函数,而红绿灯检测就自此开始。
1.5 onReceiveImage
流程如下:
1、updateCameraSelection
①通过时间戳查询车辆的位姿。
②通过给 hd map 输入位置和时间戳,来查询地图中的红绿灯。
③需要注意的是 hd map 中查询得到的红绿灯用 Signal 表示。
④算法将 Signal 加工得到 TrafficLight。
⑤TrafficLight 会保存 ROI 信息。
⑥ROI 是利用相机模型计算公式,将红绿灯距离车辆的距离通过内外参投影到对应的相机成像图片上。
⑦camera 选择好后,需要进行信息同步。
2、处理synclnformation,保证红绿灯检测有序进行
3、将接收到的image信息存储到CameraFrame中
4、验证红绿灯预测
5、调用 traffic_light_pipeline.Perception,相当于一个TrafficLightCameraPerception对象。TrafficLightCamera 里面 detector_,recognizer_,tracker_ 是 3 个核心算法对象,分别对应红绿灯的检测、识别、跟踪。它们都是基于神经网络。感知相关的模型都存在一个 Models 目录中:
apollo/modules/perception/production/data/perception/camera/models
各类检测器代码实现存放在
apollo/modules/perception/camera/lib/traffic_light
推理引擎比如torchdet、torchnet、obstacle存放在
apollo/modules/perception/inference
中,通过工厂方法引擎(在/production/data/perception/camera/models/traffic_light_detection/detection.pt)中的model_type可以设置合适的推理引擎。
6、检测好的红黄绿灯信息通过writer发送到对应的channel中去。
2 其他任务
比如车道线检测、Lidar障碍物检测等也可以在学习红绿灯检测之后触类旁通,明白大致流程。
详细可见自动驾驶(byfrank909).
融合Fusion基本流程
目录结构
── fusion
├── app 入口
├── base 定义的数据类(需清晰了解)
├── common 证据推理,IF,KF等方法
└── lib
├── data_association
│ └── hm_data_association 关联匹配算法
├── data_fusion
│ ├── existence_fusion
│ │ └── dst_existence_fusion 存在性证据推理更新
│ ├── motion_fusion
│ │ └── kalman_motion_fusion 卡尔曼更新运动属性
│ ├── shape_fusion
│ │ └── pbf_shape_fusion 更新形状属性
│ ├── tracker
│ │ └── pbf_tracker 航迹类
│ └── type_fusion
│ └── dst_type_fusion 类别证据推理更新
├── dummy 虚拟?暂不知道
├── fusion_system
│ └── probabilistic_fusion 概率融合入口
├── gatekeeper
│ └── pbf_gatekeeper 门限
│ └── proto
└── interface
1 Fusion模块启动
1、
modules/perception/production/dag/dag_streaming_perception.dag
中定义该模块
2、
/apolomodules/perception/productio/conf/percepption/fusion_conponent_conf.pb.txt
中配置该模块,比如使用ProbabilisticFusion方法融合、定义参与融合的传感器、将融合结果存放在obstacles中
2 初始化FusionComponent
modules/perception/onboard/component/fusion_component.cc
init方法,加载config参数等、初始化component涉及的算法
3 核心方法处理流程
核心方法Proc(),其中的核心方法是InternalProc,调用fusion中Process函数,跟踪到Fuse函数。
其中Fuse函数主要流程为
·保存新增数据
·提取要参与融合的历史数据
·执行融合操作·前景目标融合跟踪
·背景目标融合跟踪
·移除已经丢失的目标·整理融合之后的目标。
4 发送结果
将融合之后的数据发送出去。
参考
[1]自动驾驶(byfrank909).
[2]apollo perception by GoodluckTian
[3]apollo介绍之Perception模块(十七)by王方浩