Apollo 系统传感器是以 Lidar 为主的,本文整理在 Apollo 6.0 中 Lidar 的基本代码流程。

1. 从 Component 出发

因为有了之前红绿灯检测代码分析的经验,我们自然能够知道感知任务先从它的 component 开始。

lidar 检测的 component 是
modules/perception/onboard/component/detection_component.cc

梳理代码可以得到基础的流程框架:

1.1 initConfig

initConfig 从本地目录中读取 proto 文件,然后配置变量。
那么,如何知道从哪里读取呢?
modules/perception/production/dag/dag_streaming_perception_lidar.dag
在 dag 目录下有配置。

我们只需找到 lane_detection_component.config 文件。

/apollo/modules/perception/production/conf/perception/lidar/velodyne128_detection_conf.pb.txt

配置文件说明了激活高精度地图,然后检测的结果存放在 DetectionObjects 这个 channel。

1.2 initAlgorithmPlugin

代码非常简单,创建一个 LidarObstacleDetection 对象,然后赋值给 detector_ 并初始化。
我们应该能够察觉到 LidarObstacleDetection 是算法核心实现类,后面我们将重点关注它。

1.3 Proc 和 InternalProc

Proc 方法中内部调用了 InternalProc 。

InternalProc 的逻辑非常简单,主要是做一个消息结构体的转换。

in_message --> out_message

实际上就是

PointCloud --> LidarFrameMessage

点云数据到 LidarFrame 数据的转换。

实际上通过 detector_->Process() 完成。

我们可以把目光移到 LidarObstacleDetection 这个类上

2. detector_->Process() 算法逻辑

路径是:

modules/perception/lidar/app/lidar_obstacle_detection.cc

我们阅读代码,可以得到这样的流程图:

其实整个过程非常的清晰,分 2 步走。

1. 点云预处理
2. 点云检测

2.1 点云 Preprocesses() 和 ProcessCommon()

点云预处理比较简单,就是将 PointCloud 中的点云过滤,然后复制到 LidarFrame 结构体对应的 cloud 中。
代码地址:

modules/perception/lidar/lib/pointcloud_preprocessor/pointcloud_preprocessor.cc

代码片断

那好,下面看看 ProcessCommon() 中发生了什么?

这里面又有一个 detector,代码调用了其 Detect() 方法,所有的真相应该可以在这里揭开。

查看变量声明,不难找出 detector 是个什么东西。


detector 是由 PointPillarsDetection 实现的。

2.2 PointPillarsDetection

代码路径:

modules/perception/lidar/lib/detection/lidar_point_pillars/point_pillars_detection.cc

Apollo 6.0 中激光雷达检测算法是由 PointPillar 模型实现的,我之前有文章介绍了其模型设计思想:自动驾驶激光点云 3D 目标检测 PointPillar 论文简述

在本文我关注于 Lidar 整体检测流程而不是 PointPillar 模型思想,所以不会过多介绍 PointPillar 本身,有兴趣的同学可以查看我上面的链接。

Detect() 方法代码比较多,这里没法直接张贴,根据代码注释绘制了流程图。

点云送到模型检测前要经过 downsample 步骤。
downsample 还经过 2 次:

  • DownSamplePointCloudBeams
  • DownSampleByVoxelGrid

    在这里 downsample_factor 是大于 1 的整数,是下采样的因子,有点像卷积操作中的 stride,每隔 downsample_factor 取一点,最终减少了总体点云数据量。

下采样之后,要进入 fuse 阶段。
fuse 的是当前的点云和之前的点云。

融合也不代表所有的历史点云都参与融合。

// before fusingwhile (!prev_world_clouds_.empty() &&frame->timestamp - prev_world_clouds_.front()->get_timestamp() >FLAGS_fuse_time_interval) {prev_world_clouds_.pop_front();}

超过 FLAGS_fuse_time_interval 就直接被剔除。


把过滤掉无效点云的历史数据全部加入当前点云当中。
问题:为什么点云需要前后数据的融合呢?
在代码中我直接看不明白,但我个人的猜测是:

无论是历史数据还是当前测量的数量,其实都存在误差,两者融合就有些像训练神经网络前处理中的数据增强,这样能够有效减少数据误差同时提升神经网络模型做点云检测的准确性和稳定性。

当然,这只是我个人的猜想,有不同理解的同学可以留言一起参与讨论。

数据融合之后,再做一些 shuffle 之类的操作就直接送到推断引擎中去做前向推断了,最后又通过神经网络输出的结果得到最终的检测目标。


推断引擎应用的是工厂模式,之前车道线检测的文章已经分析过,这里不再赘述。
倒是对 PointPillar 模型本身感兴趣的同学可以看下:

可以看到模型文件是 onnx 格式的,之前有的模型是 caffe2,有的是 libtorch,这说明 Apollo 框架确实强大。

最后的 GetObjects() 方法中代码比较长,就不张贴了。
大致内容是取得 Object 的方向、边框、类别。

到此,Lidar 检测的代码流程基本上介绍完毕。

总结

通过梳理代码可以发现

  1. Apollo 是个很厉害的自动驾驶框架,各个感知任务的 Component 工作流差不多一样,有固定的套路,这也让大家能够比较轻松地学习它,可以一个模块一个模块地学。
  2. Apollo 支持现有的神经网络模型导入并灵活配置,比如 Lidar 用 PointPillar,以后有新的模型也可以比较容易替换。
  3. 算法是自动驾驶一部分,我们经常看见论文中讲得模型有多厉害,但实际编码中还需要前处理、后处理过程,这其实就是传统的代码能力,所以,大家不要小看自动驾驶,在嵌入式平台上跑,算法模型重要,代码更加重要,两者是相辅相成的。不要轻代码重算法,也不要重代码轻算法。当然,如果团队够大,大家各司其职就好了,这一部分的压力是要系统架构师承担的。

自动驾驶 Apollo 源码分析系列,感知篇(七):Lidar 障碍物检测基本流程相关推荐

  1. 自动驾驶 Apollo 源码分析系列,感知篇(六):车道线 Dark SCNN 算法简述及车道线后处理代码细节简述

    本文大纲 自动驾驶中的车道线检测思路 SCNN 算法思想 Apollo 中对应的 dark scnn 代码逻辑 dark scnn 模型结构 SCNN 方向的简化 heatmap 对应代码逻辑 灭点提 ...

  2. 自动驾驶 Apollo 源码分析系列,感知篇(八):感知融合代码的基本流程

    说起自动驾驶感知系统,大家都会谈论到感知融合,这涉及到不同传感器数据在时间.空间的对齐和融合,最终的结果将提升自动驾驶系统的感知能力,因为我们都知道单一的传感器都是有缺陷的.本篇文章梳理 Apollo ...

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

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

  4. 自动驾驶 Apollo 源码分析系列,系统监控篇(二):Monitor模块如何监控硬件

    前面的文章有分析,Monitor 模块监控的内容分为 Hardware 和 Software 两位. 本篇分析硬件监控部分. 首先,可以观察一下 Apollo 官方文档给出的硬件连接图. 跟自动驾驶本 ...

  5. 自动驾驶 Apollo 源码分析系列,感知篇(九):感知融合中的数据关联细节

    前一篇文章讲了,Apollo 6.0 中融合的代码逻辑流程,但那是基于软件的角度进行梳理和分析的,这一篇文章基于上篇的成果进一步对算法进行更详细的分析,因为代码量奇大,所以本文重点讨论数据关联的一些细 ...

  6. 自动驾驶 Apollo 源码分析系列,系统监控篇(四):Monitor模块如何监控进程 Process 的存活状态?

    本篇文章分析 Apollo 中监控模块中监控进程状态的相关代码. 1. ProcessMonitor ProcessMonitor 是一个普通的定时器组件,内部函数也只是常规的 RunOnce 和 U ...

  7. 百度自动驾驶apollo源码解读4:/cyber/task 模块

    在这里就不贴源代码,太占空间了,源码连接:https://github.com/ApolloAuto/apollo/tree/master/cyber/task cyber下面的task包是使用cyb ...

  8. jQuery-1.9.1源码分析系列(十六)ajax——ajax处理流程以及核心函数

    先来看一看jQuery的ajax核心处理流程($.ajax) a. ajax( [url,] options )执行流程 第一步,为传递的参数做适配.url可以包含在options中 //传递的参数只 ...

  9. 【Apollo源码分析】系列的第三部分【prediction】_slamcode的博客 -CSDN博客

    [Apollo源码分析]系列的第三部分[prediction]_slamcode的博客 -CSDN博客

最新文章

  1. python3.5.3下载安装教程_在Python3.5下安装和测试
  2. Java中BigInteger的各种方法详解
  3. php中的strncmp,PHP中strncmp()函数比较两个字符串前2个字符是否相等的方法
  4. java 类 关系_总结Java类关系
  5. 年度回忆录(2011.12----2012.09)
  6. SQL varchar数据类型深入探讨
  7. VIVADO时序约束及STA基础
  8. 如何将Node.js Streaming MapReduce引入Amazon EMR
  9. 简单理解php的socket编程
  10. 【集群仿真】基于matlab匈牙利算法无人机队形重构集群仿真【含Matlab源码 1498期】
  11. gx works2 版本号_GX Works2下载 GX Works2(PLC编程软件) v1.89C 中文安装版(附序列号+安装教程) 下载-脚本之家...
  12. oracle连接no listener
  13. 企业AD域管理利弊_如何避免企业AD域管理中的各种弊端?
  14. 基于Servlet和jsp的小说网站系统
  15. 倒计时 css,css实现倒计时效果
  16. Windows 10 build Error !include: could not find: ****StdUtils.nsh
  17. 混凝土静力受压弹性模量试验计算公式_混凝土静力受压弹性模量试验机测试步骤...
  18. 云主机、云服务器、VPS的区别性能比较
  19. uva 12325(宝箱, 枚举问题);
  20. qt连接mysql数据库 mac_Mac系统下Qt 4.8编译连接数据库(Oracle,MySql)

热门文章

  1. CSS文字溢出处理,背景图片处理
  2. 构建鸢尾花决策树模型
  3. Oracle新建的用户看不到表,Oracle 创建用户及数据表的方法
  4. hibernate查询方法query.setResultTransformer
  5. 情人节 python
  6. 4路poe硬盘录像机功率?
  7. memwatch检测内存泄漏例子
  8. 苹果被罚每天交2.5万美元;“同一天出生的你”募捐遭质疑;途牛回应裁员风波丨价值早报
  9. PLC数据通过无线远程传输到电脑上。也支持力控组态王远程读取,也支持云组态
  10. 微信号 可以改了 !!! 真事 !!