本系列博客旨在记录自己在学习百度无人驾驶开源框架Apollo的心得和体会,欢迎大家阅读和点赞,并提出宝贵意见,大家相互学习,如需转载,请注明出处,谢谢!
这篇文章主要介绍Apollo 5.0感知模块中的融合模块。由于不同传感器各有优缺点,传感器融合的必要性不言而喻,Apollo融合模块做的是目标级融合,即首先不同传感器自己先进行目标检测检测和目标跟踪,得到目标序列后作为融合模块的输入,进行进一步的目标推理,从而得到更加准确可靠的感知结果。
在上一篇文章Apollo 5.0源码学习笔记(一)| 感知模块 | 感知框架总览我提到了感知模块所有子模块的入口类都定义在modules/perception/onboard/component
文件夹下对应源文件中,如融合模块的入口类就是定义在modules/perception/onboard/component/fusion_component.h
中的FusionComponent
类。
输入: SensorFrameMessage
类型消息;
输出: PerceptionObstacles
类型消息;
FusionComponent
类的参数配置protobuf
文件为:modules/perception/onboard/proto/fusion_component_config.proto
,具体参数实现定义在文件modules/perception/production/conf/perception/fusion/fusion_component_conf.pb.txt
中:
fusion_method: "ProbabilisticFusion"
fusion_main_sensor: "velodyne128"
object_in_roi_check: true
radius_for_roi_object_check: 120
output_obstacles_channel_name: "/apollo/perception/obstacles"
output_viz_fused_content_channel_name: "/perception/inner/visualization/FusedObjects"
从配置参数可以看出,融合的主传感器设置为velodyne128,融合方法使用的是ProbabilisticFusion,发布融合后目标障碍物消息的话题名为/apollo/perception/obstacles
。
FusionComponent
类主要负责接收融合所需要的来自不同传感器的目标序列消息,然后利用ProbabilisticFusion
融合类完成实际融合工作,得到融合后感知结果,最后把融合结果在FusionComponent
类中发布,供其他模块使用。
在利用不同传感器感知结果来进行目标级融合时,会涉及到对很多单个目标、数据帧所有目标以及多帧目标等数据的存储问题,因此会定义很多数据结构来完成这个工作,这给阅读源码带来了很多困惑,因此此处首先对这些基础自定义数据结构进行一个简单总结,方便后面的解释。
这些基础类主要定义在fusion/base
文件夹下:
SensorObject类——某单一传感器的一个目标,其实就是包含了某个传感器的相关属性定义和一个base::Object
成员变量;
SensorFrame类——某传感器的一帧所有目标数据,定义了std::vector
成员变量;
Sensor类——某传感器历史多帧信息,定义有std::deque
类型成员变量,并提供获取最新数据帧的一些接口函数;
SensorDataManager类——最终在ProbabilisticFusion
类中作为成员变量用来存储
键值对,即存储多个传感器的多帧历史信息的类,定义有std::unorderd_map
成员变量,作为ProbabilisticFusion
类的数据输入缓存;
Track类——单个跟踪目标,在该类中完成大部分跟踪目标状态更新工作;
Scene类——前景和背景跟踪目标的管理,定义有std::vector
和std::vector
;
PbfTracker类——单个跟踪目标,也是主要的融合算法发生过程所在,定义了不同的融合算法类。
融合主要过程是通过ProbabilisticFusion
类完成的,该类定义在modules/perception/fusion/lib/fusion_system/probabilistic_fusion/probabilistic_fusion.h
中,该类继承自BaseFusionSystem
类。下面按照一些主要函数进行分别解析。
主要是对该类进行一些参数配置,并根据这些配置的参数,来实例化具体的算法类。
参数配置protobuf
文件定义在modules/perception/proto/probabilistic_fusion_config.proto
,具体实例化的参数定义在modules/perception/production/data/perception/fusion/probabilistic_fusion.pt
中:
use_lidar: true
use_radar: true
use_camera: true
tracker_method: "PbfTracker"
data_association_method: "HMAssociation"
gate_keeper_method: "PbfGatekeeper"
prohibition_sensors: "radar_front"
max_lidar_invisible_period: 0.25
max_radar_invisible_period: 0.50
max_camera_invisible_period: 0.75
max_cached_frame_num: 50
可以看出实际融合的传感器包括lidar、radar和camera,以及实际使用的跟踪算法、数据关联算法、门限保持方法的具体类名,另外还定义了其他一些参数。
目的:创建新跟踪目标
prohibition_sensors: "radar_front"
在modules/perception/production/data/perception/fusion/probabilistic_fusion.pt
文件中定义;
首先判断当前检测帧是否是prohibition_sensors
中一种,如果是,则不用来创建跟踪目标,可以看出,不用radar
来创建跟踪目标。
如果真实需要创建新的跟踪目标,首先从TrackPool
中获取共享指针track
,然后利用当前检测结果Initialize该Track跟踪目标之后添加到scenes_
中;
然后创建一个PbfTracker
,Init该track,添加到成员变量trackers_
中,即trackers_
保存PbfTracker
序列,PbfTracker
中存储的是TrackPtr
;
由于track一直是同一个指针,其实scenes_和trackers_存储的是同一跟踪目标序列,分开在不同的类中对跟踪目标进行更新。
PbfTracker::Init
函数通过调用InitMethods
函数,从而利用track
指针构造了每个算法类,例如motion_fusion_等,这样就直接能够在
motion_fusion_`中通过指针更新track的内容了。
新版本的融合类没有把所有有关跟踪目标更新操作都放在
PbfTracker
类中了,而是在PbfTracker类中保存一个Track
指针,由各个motion_fusion_
、shape_fusion_
等类共同保存该指针(即是同一个跟踪目标),因此把更新操作分担给了其他各个功能类完成,在Track
中只是进行匹配上传感器的信息更新和管理。
主要保存目标属性的成员变量:Track::fused_object_
是FusedObjectPtr
类型,其主要保存的变量是ObjectPtr
。
目的:更新匹配对跟踪目标
利用匹配上的检测目标,更新跟踪目标。
调用的是PbfTracker::UpdateWithMeasurement
函数,依次完成存在性、运动、形状和类型的融合;
最后调用track_->UpdateWithSensorObject,在该函数内部,主要是利用当前匹配的检测目标,来更新跟踪目标中存储的当前检测目标map内容,一共存储了lidar_objects_
,radar_objects_
和camera_objects_
三种;
函数内部依次调用:
1、DstExistanceFusion::UpdateWithMeasurement:
利用DS理论完成对跟踪目标存在性的判定,设置Track中的toic_p_、existance_prob_属性;
2、KalmanMotionFusion::UpdateWithMeasurement:
利用Kalman滤波,完成对目标状态滤波,设置Track中的
anchor_point、center、velocity、acceleration、center_uncertainty、velocity_uncertainty、acceleration_uncertainty属性;
3、PbfShapeFusion::UpdateWithMeasurement:
根据匹配的测量量,完成对目标的形状推理,设置Track中的size、direction、theta、polygon属性,同时也更新了Track的center、anchor_point属性;
4、DstTypeFusion::UpdateWithMeasurement:
利用DS理论,完成对跟踪目标的type、sub_type、type_probs属性更新