万字详解Apollo,全网Apollo笔记整理和学习

0 参考资料

0.1 Apollo各模块系列笔记记录

模块 参考文章
Cyber apollo介绍之cyber设计(五) - 知乎 (zhihu.com)
apollo介绍之Cyber框架(十) - 知乎 (zhihu.com)
apollo介绍之Cyber框架(十一) - 知乎 (zhihu.com)
apollo介绍之Cyber定时器(十二) - 知乎 (zhihu.com)
apollo介绍之Cyber Component(十三) - 知乎 (zhihu.com)
apollo介绍之Cyber Data(十四) - 知乎 (zhihu.com)
apollo介绍之Cyber Scheduler调度(十五) - 知乎 (zhihu.com)
apollo介绍之Cyber Async异步调用(十六) - 知乎 (zhihu.com)
apollo介绍之cyber启动(十九) - 知乎 (zhihu.com)
Map&HD-Map apollo 百度高精地图的产品解析及经验挑战_xiaoma_bk的博客-CSDN博客_百度高精度地图
apollo 百度高精地图的现状与挑战_xiaoma_bk的博客-CSDN博客_百度高精地图
apollo 关于高精地图ROI过滤器的解析_xiaoma_bk的博客-CSDN博客_地图roi
apollo 看不见的“传感器”——高精度地图_xiaoma_bk的博客-CSDN博客
apollo 相对地图:基于人工驾驶路径的实时地图生成_xiaoma_bk的博客-CSDN博客
apollo 自动驾驶中的GNSS/融合定位技术_xiaoma_bk的博客-CSDN博客_自动驾驶融合定位
【Apollo 6.0项目实战】HD-Map模块_Travis.X的博客-CSDN博客_apollo hdmap
Apollo 高精地图解析 (qq.com)
apollo 高精地图解析_xiaoma_bk的博客-CSDN博客_apollo 地图
apollo Apollo介绍之Map模块_xiaoma_bk的博客-CSDN博客_apollo map
Apollo 5.0 高精度地图OpenDRIVE 规范 (qq.com)
Apollo 6.0 pnc_map解析 - 知乎 (zhihu.com)
Apollo-reading-map - 掘金 (juejin.cn)
apollo_learning/opendrive_adapter.md at master · chucklqsun/apollo_learning (github.com)
开发者说|Apollo简易制图过程 (baidu.com)
Apollo课程学习2——高精地图HD Map_Albert的博客-CSDN博客_apollo hdmap
百度Apollo无人驾驶高精度地图的制作和opendrive格式详细讲解 - 知乎 (zhihu.com)
知乎:王方浩
地图转换工具开发杂谈 - 知乎 (zhihu.com)
高精度地图制作 - 知乎 (zhihu.com)
高精度地图制作(二) - 知乎 (zhihu.com)
高精度地图制作(三) - 知乎 (zhihu.com)
apollo介绍之map模块(二) - 知乎 (zhihu.com)
apollo简易制图过程(二十) - 知乎 (zhihu.com)
apollo高精度地图可视化(二十二) - 知乎 (zhihu.com)
apollo高精度地图制作(二十三) - 知乎 (zhihu.com)
apollo高精度地图标注(二十四) - 知乎 (zhihu.com)
GitHub-Issues
apollo1.5 创建添加HD map · Issue #641 · ApolloAuto/apollo (github.com)
Perception Apollo学习笔记7-感知融合_hello1268的博客-CSDN博客_感知融合
Planning Apollo 7.0 规划算法框架解析 - 知乎 (zhihu.com)
【机器人】无人车-运动规划-Apollo6.0-planning模块代码框架梳理(一)--整体结构 - 知乎 (zhihu.com)
【机器人】无人车-运动规划-Apollo6.0-planning模块代码框架梳理(二)--PlanningComponent - 知乎 (zhihu.com)
Apollo Planning Frame_落羽归尘的博客-CSDN博客
分享回顾 Apollo 轨迹规划技术分享 (qq.com)
Prediction 如何学习百度apollo无人驾驶预测模块? - 知乎 (zhihu.com)
apollo预测模块分享(二十一) - 知乎 (zhihu.com)
Routing Apollo 导航模块记录(routing模块) - 知乎 (zhihu.com)
Transform 百度Apollo无人驾驶图解传感器地球之间的坐标关系以及如何转换 - 知乎 (zhihu.com)
百度Apollo智能驾驶进阶课程--第三章 百度Apollo定位技术
Apollo项目坐标系研究_知行合一2018的博客-CSDN博客_apollo 坐标系
三、Apollo自定位技术详解(入门技术与基础知识)_一只小麻团的博客-CSDN博客_apollo定位
DreamView 【Apollo 6.0项目实战】Dreamview的使用_Travis.X的博客-CSDN博客_apollo dreamview
调试 vscode中Apollo代码调试方法_hello1268的博客-CSDN博客_apollo 调试

0.2 Apollo优秀教程合集

教程 链接
Apollo学习笔记 daohu527/dig-into-apollo: Apollo notes (Apollo学习笔记) - Apollo learning notes for beginners. (github.com)
Apollo官方教程 Apollo
百度技术培训中心 百度技术培训中心 - 百度技术让你更强 (baidu.com)
知乎:王方浩 apollo介绍(一) - 知乎 (zhihu.com)
apollo介绍之map模块(二) - 知乎 (zhihu.com)
apollo介绍之localization模块(三) - 知乎 (zhihu.com)
apollo介绍之planning模块(四) - 知乎 (zhihu.com)
apollo介绍之Routing模块(六) - 知乎 (zhihu.com)
apollo介绍之Transform模块(七) - 知乎 (zhihu.com)
apollo介绍之Canbus模块(八) - 知乎 (zhihu.com)
apollo介绍之Control模块(九) - 知乎 (zhihu.com)
apollo介绍之Perception模块(十七) - 知乎 (zhihu.com)
apollo介绍之audio模块(十八) - 知乎 (zhihu.com)
apollo预测模块分享(二十一) - 知乎 (zhihu.com)
知乎:自动驾驶Player 自动驾驶算法详解(2) : prescan联合simulink进行ADAS算法的仿真 - 知乎 (zhihu.com)
自动驾驶算法详解(3) : LQR算法进行轨迹跟踪,lqr_speed_steering_control( )的python实现 - 知乎 (zhihu.com)
自动驾驶算法详解(4): 横向LQR、纵向PID控制进行轨迹跟踪以及python实现 - 知乎 (zhihu.com)
自动驾驶算法详解(5): 贝塞尔曲线进行路径规划的python实现 - 知乎 (zhihu.com)
自动驾驶算法详解(6):Astar算法原理以及路径规划应用在python与ros平台实现 - 知乎 (zhihu.com)
Apollo Planning决策规划代码详细解析 (1):Scenario选择 - 知乎 (zhihu.com)
自动驾驶Player:Apollo Planning决策规划代码详细解析 (2):Scenario执行
自动驾驶Player:Apollo Planning决策规划代码详细解析 (3):stage执行
自动驾驶Player:Apollo Planning决策规划代码详细解析 (4):Stage逻辑详解
自动驾驶Player:Apollo Planning决策规划代码详细解析 (5):规划算法流程介绍
自动驾驶Player:Apollo Planning决策规划代码详细解析 (6):LaneChangeDecider
自动驾驶Player:Apollo Planning决策规划代码详细解析 (7): PathReuseDecider
自动驾驶Player:Apollo Planning决策规划代码详细解析 (8): PathLaneBorrowDecider
自动驾驶Player:Apollo Planning决策规划代码详细解析 (9): PathBoundsDecider
自动驾驶Player:Apollo Planning决策规划代码详细解析 (11): PathAssessmentDecider
自动驾驶Player:Apollo Planning决策规划代码详细解析 (12): PathDecider
Apollo Planning决策规划算法代码详细解析 (13): RuleBasedStopDecider
Apollo Planning决策规划算法代码详细解析 (14):SPEED_BOUNDS_PRIORI_DECIDER
Apollo Planning决策规划算法代码详细解析 (15): 速度动态规划SPEED_HEURISTIC_OPTIMIZER 上
Apollo Planning决策规划算法代码详细解析 (16):SPEED_HEURISTIC_OPTIMIZER 速度动态规划中
Apollo Planning决策规划算法代码解析 (17):SPEED_HEURISTIC_OPTIMIZER 速度动态规划下
知乎:iGear Apollo Canbus模块记录(上) - 知乎 (zhihu.com)
Apollo Canbus模块记录(下) - 知乎 (zhihu.com)
Apollo系统监控模块解析(上篇) - 知乎 (zhihu.com)
Apollo系统监控模块解析(下篇) - 知乎 (zhihu.com)
Apollo控制模块记录 - 知乎 (zhihu.com)
Apollo规划模块(一):scenario - 知乎 (zhihu.com)
Apollo规划模块(二):stage - 知乎 (zhihu.com)
Apollo规划模块-task - 知乎 (zhihu.com)
Apollo 感知模块(一):Radar Perception - 知乎 (zhihu.com)
Apollo规划模块详解:算法实现-9类交通规则(上) - 知乎 (zhihu.com)
Apollo规划模块详解:算法实现-9类交通规则(下) - 知乎 (zhihu.com)
Apollo规划模块详解(一):整体架构+算法说明 - 知乎 (zhihu.com)
Apollo规划模块详解(二):算法实现-数据检查及更新 - 知乎 (zhihu.com)
Apollo规划模块详解(五):算法实现-lane change decider - 知乎 (zhihu.com)
Apollo规划模块详解(六):算法实现-path lane borrow decider - 知乎 (zhihu.com)
Apollo规划模块详解(七):算法实现-path bounds decider 上篇 - 知乎 (zhihu.com)
CSDN:Albert Apollo课程学习1——无人驾驶与Apollo平台概述_Albert的博客-CSDN博客
Apollo课程学习2——高精地图HD Map_Albert的博客-CSDN博客_apollo hdmap
Apollo课程学习3——定位_Albert的博客-CSDN博客
Apollo课程学习4——感知_Albert的博客-CSDN博客_apollo 感知
Apollo课程学习5——规划_Albert的博客-CSDN博客_apollo 二次规划
Apollo课程学习6——控制_Albert的博客-CSDN博客
Apollo课程学习7——ROS_Albert的博客-CSDN博客
Apollo 课程学习8——开发套件循迹_Albert的博客-CSDN博客
Apollo 课程学习9——demo仿真实践_Albert的博客-CSDN博客
CSDN:hello1268 Apollo学习笔记1-ESD_CAN调试_hello1268的博客-CSDN博客
Apollo学习笔记2-docker安装_hello1268的博客-CSDN博客
Apollo学习笔记3-定位模块配置_hello1268的博客-CSDN博客
Apollo学习笔记5-横、纵向控制_hello1268的博客-CSDN博客_横向控制和纵向控制
Apollo学习笔记6-lidar感知_hello1268的博客-CSDN博客_apollo lidar
Apollo学习笔记7-感知融合_hello1268的博客-CSDN博客_感知融合
CSDN:Travis.X 【Apollo 6.0算法解析】Apollo EM Planner_Travis.X的博客-CSDN博客_apollo em planner
【Apollo 6.0算法解析】Planning模块简介_Travis.X的博客-CSDN博客_apollo planning
【Apollo 6.0项目实战】Apollo 6.0安装_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】Canbus模块_Travis.X的博客-CSDN博客_canbus
【Apollo 6.0项目实战】Control模块_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】Dreamview的使用_Travis.X的博客-CSDN博客_dreamview
【Apollo 6.0项目实战】HD-Map模块_Travis.X的博客-CSDN博客_apollo hdmap
【Apollo 6.0项目实战】LGSVL 高精地图使用教程_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】LGSVL 与 Apollo 6.0联合仿真教程_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】Localization模块_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】Perception模块_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】Planning模块_Travis.X的博客-CSDN博客
【Apollo 6.0项目实战】Prediction模块_Travis.X的博客-CSDN博客_apollo预测模块
【Apollo 6.0项目实战】Routing模块_Travis.X的博客-CSDN博客_apollo routing
【Apollo 6.0学习笔记】定位_Travis.X的博客-CSDN博客_apollo 定位
【Apollo 6.0学习笔记】感知_Travis.X的博客-CSDN博客
【Apollo 6.0学习笔记】高精地图_Travis.X的博客-CSDN博客_高精地图
【Apollo 6.0学习笔记】Apollo Cyber RT介绍_Travis.X的博客-CSDN博客_apollo cyber
【Apollo 6.0学习笔记】Apollo 6.0软硬件框架_Travis.X的博客-CSDN博客_apollo6.0运行硬件
【Apollo 6.0学习笔记】Apollo模块_Travis.X的博客-CSDN博客
【Apollo 6.0学习笔记】Channel数据格式_Travis.X的博客-CSDN博客_apollo 数据格式
【Apollo 6.0学习笔记】Cyber RT API使用_Travis.X的博客-CSDN博客
CSDN:自动驾驶小学生 无人驾驶汽车进阶-43篇笔记
CSDN:sw_helloworld Apollo专栏-付费29.9
CSDN:weixin_49024732 Apollo系列博客

1 什么是Apollo

参考文章
百度Apoll无人驾驶高精度地图的制作和opendrive格式详细讲解 - 知乎 (zhihu.com)
apollo高精地图的数据元素分类以及阿波罗地图规范和opendrive规范的区别 - 知乎 (zhihu.com)
社群分享内容 Apollo相对地图:基于人工驾驶路径的实时地图生成 (qq.com)

1.1 简介

Apollo是百度的自动驾驶开源框架,根据自动驾驶的功能划分为不同的模块。

  • 定位 - 比如GPS,但是GPS的精度只有米级别。有几个场景会不太合适,比如你在桥洞里,GPS信号不好的情况,另外还有一种情况是,停车的时候,你要知道前后车的距离,另外比如在雪天或者路况复杂的情况,这些情况下,仅有的GPS信号可能不能满足我们的要求,因此无人车又增加了激光雷达来测量周围环境的距离,而且可以精确到厘米。 因此产生了高精地图的需求,高精地图可以把周围的3D环境都记录下来,这样我们就可以通过3D图像来匹配周围的场景,来找到自己的位置,而且高精地图还可以记录比地图多的多的东西,比如红绿灯的位置,交通标志,左转还是右转道.通过高精地图我们不仅可以知道道路情况,还可以知道车辆需要获取的一些其他信息,让车辆知道自己的实时位置。
  • 感知 - 我们总是希望车辆行驶在马路中间,这样更加安全,这就需要追踪到道路的路牙线,而道路随时会出现拐弯,那么追踪路牙线就用到了图像处理技术,另外还要感知到什么是车辆,什么是行人,主要涉及到图像的语义分割,感知是自动驾驶中最难,而且最具有挑战性的一块,因为只有感知到周围的行人,车辆,以及突发状况,才能为后面规划线路。
  • 规划 - 目前已经知道当前道路情况,而且也已经感知到前面的车辆或者行人,如何去规划我们的行驶线路呢,这里需要解决的就是2个点之间的线路,而且行驶中途可能会出现新的情况,又需要重新规划线路,还有一种情况是,通过高精地图,我们已经知道前面需要转弯了,我们可以提前调整线路来适应这种需求。
  • 控制 - 现在已经规划出了一条线路,剩下的就是控制汽车,按照已经规划好的线路行驶,而且如果遇到突发状况,需要立即停车,而且控制汽车能够按照预定的线路不会出现很大的偏离,这就是控制要做的事情。

1.2 结构目录

|-cyber 消息中间件,替换ros作为消息层
|-docker 容器相关
|-docs 文档相关
|-modules 自动驾驶模块,主要的定位,预测,感知,规划都在这里
    |-calibration 校准,主要用于传感器坐标的校准,用于感知模块做传感器融合
    |-canbus 通讯总线,工业领域的标准总线,CanBus 是将控制命令传递给车辆硬件的接口。它还将机箱信息传递给软件系统。
    |-common  本模块中的代码不是针对某一模块的,各个模块得一些共性方法吧
    |-contrib
    |-control 控制模块,根据planning生成的路径对车辆轨迹进行控制,再底层就是发送命令到can总线,实现车辆的控制。控制模块通过产生油门、刹车和转向等控制命令来执行计划的时空轨迹。
    |-data 地图等生成好的数据放在这里
    |-dreamview 仿真,能够对自动驾驶过程中的数据进行回放
    |-drivers 雷达,lidar,GPS, canbus,camera等驱动
    |-guardian 新的安全模块,用于干预监控检测到的失败和action center相应的功能。 执行操作中心功能并进行干预的新安全模块应监控检测故障。
    |-localization 定位,获取汽车的当前位置
    |-map 地图模块
      | -HD-Map 模块类似于库。它不是发布和订阅消息,而是经常用作查询引擎支持,以提供关于道路的特定结构化信息。
定位——定位模块利用各种信息源(如 GPS、LiDAR 和 IMU)来估计自动驾驶汽车的位置。
    |-monitor 监控模块,主要是监控汽车状态,并且记录,用于故障定位,健康检查等
    |-perception 感知,获取汽车当前的环境,行人,车辆,红绿灯等,给planning模块规划线路,感知模块识别自动驾驶汽车周围的环境。感知模块内部包含两个重要的子模块:障碍物检测和交通灯检测。
    |-planning 规划,针对感知到的情况,对路径做规划,短期规划,只规划100-200M的距离,生成好的路径给control模块,规划模块规划自动驾驶汽车要采取的时空轨迹。
    |-prediction 预测,属于感知模块,对运动物体的轨迹做预测,预测模块用来预测与感知障碍物未来的运动轨迹。
    |-routing 导航线路,就是百度地图上查询2点之间的线路,生成的线路短期规划还是planning模块,路由模块告诉自动驾驶汽车通过全局路径到达目的地。
    |-third_party_perception 第三方感知模块
    |-tools 工具
    |-transform 坐标转换,不同坐标系的坐标转换
    |-v2x 顾名思义就vehicle-to-everything,其希望实现车辆与一切可能影响车辆的实体实现信息交互,
          目的是减少事故发生,减缓交通拥堵,降低环境污染以及提供其他信息服务。车路协同技术
|-scripts 脚本
|-third_party 第三方库
|-tools 工具目录

1.3 各模块架构

Apollo 无人驾驶平台是以高精地图和定位模块作为核心。其他的模块都是以这两个模块为基础。

img

img

1.3.1 定位

一种是结合GPS和IMU信息的RTK(Real Time Kinematic实时运动)方法,另一种是融合GPS、IMU和激光雷达信息的多传感器融合方法。

1.3.2 感知

1.3.3 预测

预测模块从感知模块接收障碍物,其基本感知信息包括位置、方向、速度、加速度,并生成不同概率的预测轨迹。

1.3.4 路由

路由模块依赖于路由拓扑文件,通常称为Apollo中的routing_map.*。路由地图可以通过命令来生成。

1.3.5 规划

1.3.6 控制

1.4 编译

apollo采用的是bazel来进行编译。

2 Cyber

参考文章
apollo介绍之cyber设计(五) - 知乎 (zhihu.com)
apollo介绍之Cyber框架(十) - 知乎 (zhihu.com)
apollo介绍之Cyber框架(十一) - 知乎 (zhihu.com)
apollo介绍之Cyber定时器(十二) - 知乎 (zhihu.com)
apollo介绍之Cyber Component(十三) - 知乎 (zhihu.com)
apollo介绍之Cyber Data(十四) - 知乎 (zhihu.com)
apollo介绍之Cyber Scheduler调度(十五) - 知乎 (zhihu.com)
apollo介绍之Cyber Async异步调用(十六) - 知乎 (zhihu.com)
apollo介绍之cyber启动(十九) - 知乎 (zhihu.com)

Cyber是百度Apollo推出的替代Ros的消息中间件,自动驾驶中的各个模块通过Cyber进行消息订阅和发布,同时Cyber还提供了任务调度、录制Bag包等功能。

2.1 Cyber实现的功能

cyber提供的功能概括起来包括2方面:

  1. 消息队列 - 主要作用是接收和发送各个节点的消息,涉及到消息的发布、订阅以及消息的buffer缓存等。
  2. 实时调度 - 主要作用是调度处理上述消息的算法模块,保证算法模块能够实时调度处理消息。

除了这2方面的工作,cyber还需要提供以下2部分的工作:

  1. 用户接口 - 提供灵活的用户接口
  2. 工具 - 提供一系列的工具,例如bag包播放,点云可视化,消息监控等

img

总结起来就是,cyber是一个分布式收发消息,和调度框架,同时对外提供一系列的工具和接口来辅助开发和定位问题。其中cyber对比ROS来说有很多优势,唯一的劣势是cyber相对ROS没有丰富的算法库支持。

3 Audio

audio模块是Apollo 6.0新增加的模块,主要的用途是通过声音来识别紧急车辆(警车,救护车,消防车)。目前的功能还相对比较简单,只能识别单个紧急车辆,同时需要环境风速低于20mph。

4 Canbus

4.1 Canbus模块介绍

控制器局域网 (Controller Area Network,简称CAN或者CAN bus) 是一种车用总线标准。被设计用于在不需要主机(Host)的情况下,允许网络上的节点相互通信。采用广播机制,并利用标识符来定义内容和消息的优先顺序,使得canbus的扩展性良好,同时不基于特殊类型(Host)的节点,增加了升级网络的便利性。 这里的Canbus模块其实可以称为Chassis模块,主要的作用是反馈车当前的状态(航向,角度,速度等信息),并且发送控制命令到车线控底盘,可以说Canbus模块是车和自动驾驶软件之间的桥梁。由于这个模块和”drivers/canbus”的联系紧密,因此也一起在这里介绍。 Canbus模块是车和自动驾驶软件之间的桥梁,通过canbus驱动(drivers/canbus)来实现将车身信息发送给apollo上层软件,同时接收控制命令,发送给汽车线控底盘实现对汽车的控制。

那么canbus模块的输入是什么?输出是什么呢?

在这里插入图片描述

可以看到canbus模块:

  • 输入 - 1. ControlCommand(控制命令)
  • 输出 - 1. Chassis(汽车底盘信息), 2. ChassisDetail(汽车底盘信息详细信息)

Canbus模块的输入是control模块发送的控制命令,输出汽车底盘信息,这里apollo的上层模块被当做一个can_client来处理,实现接收和发送canbus上的消息。

Canbus模块的目录结构如下:

├── BUILD                    // bazel编译文件
├── canbus_component.cc      // canbus主入口
├── canbus_component.h
├── canbus_test.cc           // canbus测试
├── common                   // gflag配置
├── conf                     // 配置文件
├── dag                      // dag依赖
├── launch                   // launch加载
├── proto                    // protobuf文件
├── testdata                 // 测试数据
├── tools                    // 遥控汽车和测试canbus总线工具
└── vehicle                  //

5 Control

5.1 Control模块简介

Apollo控制模块的逻辑相对比较简单,控制模块的作用是根据规划(planning模块)生成的轨迹,计算出汽车的油门,刹车和方向盘信号,控制汽车按照规定的轨迹行驶。采用的方法是根据汽车动力和运动学的知识,对汽车进行建模,实现对汽车的控制。目前apollo主要用到了2种控制方式:PID控制和模型控制。

首先我们需要搞清楚control模块的输入是什么,输出是什么?

input.jpg

可以看到control模块:

  • 输入 - Chassis(车辆状态信息), LocalizationEstimate(位置信息), ADCTrajectory(planning模块规划的轨迹)
  • 输出 - ControlCommand(油门,刹车,方向盘)

Control模块的目录结构如下:

├── BUILD      // bazel编译文件
├── common     // PID和控制器的具体实现     --- 算法具体实现
├── conf       // 配置文件                 --- 配置文件
├── control_component.cc  // 模块入口
├── control_component.h
├── control_component_test.cc
├── controller           // 控制器         --- 具体的控制器实现
├── dag                  // dag依赖
├── integration_tests    // 测试
├── launch               // launch加载
├── proto                // protobuf文件,主要是各个控制器的配置数据结构
├── testdata             // 测试数据
└── tools                // 工具类

6 Guardian

6.1 简介

Guardian模块的主要作用是监控自动驾驶系统状态,当出现模块为失败状态的时候,会主动切断控制命令输出,并且刹车。

7 Localization

7.1 Localization模块简介

localization模块主要实现了以下2个功能:

  1. 输出车辆的位置信息(planning模块使用)
  2. 输出车辆的姿态,速度信息(control模块使用)

其中apollo代码中分别实现了3种定位方法:

  1. GNSS + IMU定位
  2. NDT定位(点云定位)
  3. MSF(融合定位)

MSF方法参考论文”Robust and Precise Vehicle Localization Based on Multi-Sensor Fusion in Diverse City Scenes”

7.2 代码目录

下面是localization的目录结构,在查看具体的代码之前最好看下定位模块的readme文件:

├── common          // 声明配置(flags),从conf目录中读取相应的值
├── conf            // 配置文件存放目录
├── dag             // cyber DAG流
├── launch          // cyber的配置文件,依赖DAG图(这2个和cyber有关的后面再分析)
├── msf             // 融合定位(gnss,点云,IMU融合定位)
│   ├── common
│   │   ├── io
│   │   ├── test_data
│   │   └── util
│   ├── local_integ
│   ├── local_map
│   │   ├── base_map
│   │   ├── lossless_map
│   │   ├── lossy_map
│   │   ├── ndt_map
│   │   └── test_data
│   ├── local_tool
│   │   ├── data_extraction
│   │   ├── local_visualization
│   │   └── map_creation
│   └── params
│       ├── gnss_params
│       ├── vehicle_params
│       └── velodyne_params
├── ndt                         // ndt定位
│   ├── map_creation
│   ├── ndt_locator
│   └── test_data
│       ├── ndt_map
│       └── pcds
├── proto                   // 消息格式
├── rtk                     // rtk定位
└── testdata                // imu和gps的测试数据

通过上述目录可以知道,定位模块主要实现了rtk,ndt,msf这3个定位方法,分别对应不同的目录。proto文件夹定义了消息的格式,common和conf主要是存放一些配置和消息TOPIC。

8 Map

8.1 Map模块简介

其实我们只需要知道map模块的主要功能是“加载openstreet格式的地图,并且提供一系列的API给其他模块使用”。

8.2 Map目录结构

本章主要介绍下apollo代码的map模块,map的代码目录结构如下:

├── data           // 生成好的地图
│   └── demo
├── hdmap          // 高精度地图
│   ├── adapter    // 从xml文件读取地图(openstreet保存格式为xml)
│   │   └── xml_parser
│   └── test-data
├── pnc_map        // 给规划控制模块用的地图
│   └── testdata
├── proto          // 地图各元素的消息格式(人行横道,车道线等)
├── relative_map   // 相对地图
│   ├── common
│   ├── conf
│   ├── dag
│   ├── launch
│   ├── proto
│   ├── testdata
│   │   └── multi_lane_map
│   └── tools
├── testdata       // 测试数据?
│   └── navigation_dummy
└── tools          // 工具

apollo的高精度地图采用了opendrive格式,opendrive是一个统一的地图标准,这样保证了地图的通用性。其中map模块主要提供的功能是读取高精度地图,并且转换成apollo程序中的Map对象。直白一点就是说把xml格式的opendrive高精度地图,读取为程序能够识别的格式。 map模块没有实现的功能是高精度地图的制作。

8.3 HD-Map

参考文章
apollo 百度高精地图的产品解析及经验挑战_xiaoma_bk的博客-CSDN博客_百度高精度地图
apollo 百度高精地图的现状与挑战_xiaoma_bk的博客-CSDN博客_百度高精地图
apollo 关于高精地图ROI过滤器的解析_xiaoma_bk的博客-CSDN博客_地图roi
apollo 看不见的“传感器”——高精度地图_xiaoma_bk的博客-CSDN博客
apollo 相对地图:基于人工驾驶路径的实时地图生成_xiaoma_bk的博客-CSDN博客
apollo 自动驾驶中的GNSS/融合定位技术_xiaoma_bk的博客-CSDN博客_自动驾驶融合定位
【Apollo 6.0项目实战】HD-Map模块_Travis.X的博客-CSDN博客_apollo hdmap
Apollo 高精地图解析 (qq.com)
apollo 高精地图解析_xiaoma_bk的博客-CSDN博客_apollo 地图
apollo Apollo介绍之Map模块_xiaoma_bk的博客-CSDN博客_apollo map
Apollo 5.0 高精度地图OpenDRIVE 规范 (qq.com)
Apollo 6.0 pnc_map解析 - 知乎 (zhihu.com)
Apollo-reading-map - 掘金 (juejin.cn)
apollo_learning/opendrive_adapter.md at master · chucklqsun/apollo_learning (github.com)
开发者说|Apollo简易制图过程 (baidu.com)
Apollo课程学习2——高精地图HD Map_Albert的博客-CSDN博客_apollo hdmap
百度Apollo无人驾驶高精度地图的制作和opendrive格式详细讲解 - 知乎 (zhihu.com)
知乎:王方浩
地图转换工具开发杂谈 - 知乎 (zhihu.com)
高精度地图制作 - 知乎 (zhihu.com)
高精度地图制作(二) - 知乎 (zhihu.com)
高精度地图制作(三) - 知乎 (zhihu.com)
apollo介绍之map模块(二) - 知乎 (zhihu.com)
apollo简易制图过程(二十) - 知乎 (zhihu.com)
apollo高精度地图可视化(二十二) - 知乎 (zhihu.com)
apollo高精度地图制作(二十三) - 知乎 (zhihu.com)
apollo高精度地图标注(二十四) - 知乎 (zhihu.com)
GitHub-Issues
apollo1.5 创建添加HD map · Issue #641 · ApolloAuto/apollo (github.com)

由于apollo的hd map制作没有开放,所以目前hd map的生成是需要向百度提需求的。 如果想自己制作的话,apollo有提供建议如下:

  • 原始数据采集(视觉、激光雷达、GPS等)以及处理。
  • 地图数据生成。从步骤一生成的数据通过算法或者人工的方式获取地图数据。
  • 地图格式组织。将地图数据转换为Apollo的高精度地图格式(可以参照base_map.xml格式,其他的地图都可以从base_map.xml生成)。
  • 注意:这三个步骤的工具均需要自己开发,如果只是小规模的简单测试,也可以参照base_map.xml格式手工组织数据。
  1. 将HD map加入apollo1.5:

有两个方法,一个是通过添加一个新的目录,使用apollo系统;一个是替换原有目录下的地图文件。

  1. 新加一个hd map:
  • 在/apollo/modules/map/data目录下,创建一个目录new_map。
  • 将生成的hd map放入new_map中,如有配置文件,可以参考sunnyvale_office目录下的配置文件。
  • 编译,执行bash apollo.sh build。
  • 然后执行bash scripts/hmi.sh。
  • 打开ip:8887,在选择地图的下拉框中就可以看到新加入的hd map了。
  • 直接copy new_garage 重命名为new_garage_2测试的,测试通过。
  • 注1:编译的时候,应该相当于将/apollo/modules/map/data/new_map注册到系统中去,以便启动hmi时,前端网页可以定位到/apollo/modules/map/data/new_map目录,进而加载其中的文件。也因此,可以有第二个方法加入hd map。
  1. 利用现有的地图目录,加入地图:
  • 假设apollo1.5中,已经添加了new_map,此时只需要替换目录下的hd map所有的文件,这样不需要编译,即可使用新的hd map。

9 Monitor

9.1 简介

monitor模块主要是监控硬件和软件状态,当出现故障的时候,显示故障原因,并且输出状态给guardian模块进行紧急处理。

10 Perception

参考文章
Apollo学习笔记7-感知融合_hello1268的博客-CSDN博客_感知融合

10.1 Perception模块简介

在这里插入图片描述

主要用到的传感器类型包括相机、激光雷达和毫米波雷达,相机和激光雷达的目标检测部分都是利用深度学习网络完成,然后都进行了目标跟踪,最后设计了一个融合模块,用来融合三种传感器跟踪后的目标序列,获得更加稳定可靠的感知结果

首先简单看下perception的目录结构:

.
├── BUILD
├── Perception_README_3_5.md
├── README.md
├── base           // 基础类
├── camera         // 相机相关,相机检测           --- 子模块流程
├── common         // 公共目录
├── data           // 相机的内参和外参
├── fusion         // 传感器融合
├── inference      // 深度学习推理模块
├── lib            // 一些基础的库,包括线程、时间等
├── lidar          // 激光雷达相关         --- 子模块流程
├── map            // 高精度地图
├── model          // 深度学习模型
├── onboard        // 各个子模块的入口,组件文件结构和组件类的实现     --- 子模块入口
├── production     // 感知模块入口(深度学习模型也存放在这里)--- 通过cyber启动子模块
├── proto          // 数据格式,protobuf
├── radar          // 毫米波               --- 子模块流程
├── testdata       // 上述几个模块的测试数据
└── tool           // 离线测试工具

下面介绍几个重要的目录结构:

  • production目录 - 感知模块的入口在production目录,通过lanuch加载对应的dag,启动感知模块,感知模块包括多个子模块,在onboard目录中定义。
  • onboard目录 - 定义了多个子模块,分别用来处理不同的传感器信息(Lidar,Radar,Camera)。各个子模块的入口在onboard目录中,每个传感器的流程大概相似,可以分为预处理,物体识别,感兴趣区域过滤以及追踪
  • inference目录 - 深度学习推理模块,我们知道深度学习模型训练好了之后需要部署,而推理则是深度学习部署的过程,实际上部署的过程会对模型做加速,主要实现了caffe,TensorRT和paddlepaddle3种模型部署。训练好的深度模型放在”modules\perception\production\data”目录中,然后通过推理模块进行加载部署和在线计算。
  • camera目录 - 主要实现车道线识别,红绿灯检测,以及障碍物识别和追踪
  • radar目录 - 主要实现障碍物识别和追踪(由于毫米波雷达上报的就是障碍物信息,这里主要是对障碍物做追踪)。
  • lidar目录 - 主要实现障碍物识别和追踪(对点云做分割,分类,识别等)。
  • fusion目录 - 对上述传感器的感知结果做融合。

整个模块的流程如图:

在这里插入图片描述

可以看到感知模块由production模块开始,由fusion模块结束。

10.2 融合流程

主要流程如下:

在这里插入图片描述

比较全的流程如下:

在这里插入图片描述

11 Planning

参考文章
Apollo 7.0 规划算法框架解析 - 知乎 (zhihu.com)
【机器人】无人车-运动规划-Apollo6.0-planning模块代码框架梳理(一)--整体结构 - 知乎 (zhihu.com)
【机器人】无人车-运动规划-Apollo6.0-planning模块代码框架梳理(二)--PlanningComponent - 知乎 (zhihu.com)
Apollo Planning Frame_落羽归尘的博客-CSDN博客
分享回顾 Apollo 轨迹规划技术分享 (qq.com)

11.1 Planning模块简介

规划(planning)模块的作用是根据感知预测的结果,当前的车辆信息和路况规划出一条车辆能够行驶的轨迹,这个轨迹会交给控制(control)模块,控制模块通过油门,刹车和方向盘使得车辆按照规划的轨迹运行。 规划模块的轨迹是短期轨迹,即车辆短期内行驶的轨迹,长期的轨迹是routing模块规划出的导航轨迹,即起点到目的地的轨迹,规划模块会先生成导航轨迹,然后根据导航轨迹和路况的情况,沿着短期轨迹行驶,直到目的地。这点也很好理解,我们开车之前先打开导航,然后根据导航行驶,如果前面有车就会减速或者变道,超车,避让行人等,这就是短期轨迹,结合上述的方式直到行驶到目的地。

11.2 routing与planning的关系

routing模块规划的路径是planning模块规划轨迹的输入信息 来源之一,能够协助planning规划出安全,可靠的行驶轨迹。

planning模块通常根据传感器输入(激光雷达、视觉摄像头等)规划出车辆当前时刻需要的一条行驶轨迹,但是一些特殊场景下,如大雾天气、夜晚、匝道进出口等,由于输入信息缺失,不能规划出安全行驶轨迹,此时可以根据routing规划导航路径,结合高精地图信息,能够得到一条满足行驶的轨迹。

11.3 planning 的输入输出

熟悉Apollo CyberRT框架的小伙伴都知道在该框架下,输入输出由Reader和Writer构成,并定义在每个模块的component文件中。除此之外,CyberRT框架定义了两种模式,分别为消息触发和时间触发,而planning中采用的为消息触发,因此必须接到特定的上游消息后,才会进入内部主逻辑,而消息触发的上游消息,定义为component中Process()函数的入参。

planning的上下游关系总结为下图:

img

这里再重复一下,planning的输入分为Reader和Process()入参的原因在于,planning依赖于Process()的三个上游输入,只有同时接到这三个输入,才会触发planning的主逻辑,即是planning正常启动的必要条件。而Reader则不是,其中部分上游还依赖于配置参数是否打开,具体可以查看Apollo的源码。

planning的输出就比较简单了,主要是给控制的ADCTrajectory数据,包含了一条带时间、速度的轨迹点集,具体的格式定义可以查看对应的proto文件。

12 Prediction

参考文章
如何学习百度apollo无人驾驶预测模块? - 知乎 (zhihu.com)
apollo预测模块分享(二十一) - 知乎 (zhihu.com)

12.1 简介

预测模块是直接接收的感知模块给出的障碍物信息,这和CV领域的传统预测任务有区别,CV领域的预测任务不需要先识别物体,只需要根据物体的特征,对比前后2帧,然后得出物体的位置,也就说甚至不需要物体识别,业界之所以不这么做的原因是因为检测物体太耗时了。 当然也有先检测物体再做跟踪的,也就是说目前apollo中的物体检测实际上是采用的第二种方法,这也可以理解,反正感知模块一定会工作,而且一定要检测物体,所以何不把这个信息直接拿过来用呢?这和人类似,逐帧跟踪指定特征的对象,就是物体的轨迹,然后再根据现有的轨迹预测物体讲来的轨迹。 预测的轨迹和障碍物信息发送给规划(planning)模块使用。

12.2 整体框架

绿色表示预测模块所依赖的上游模块,包括了规划、定位、感知、Storytelling和高精度地图,下游是规划模块。

红色虚线框内是预测模块的整体逻辑,包含容器(Container),场景(Scenario)、评估器(Evaluator)和预测器(Predictor)。

imgimg

12.2.1 容器 Container

输入上游的一系列信息,输出障碍物、主车和相关联车道信息。

容器存储来自订阅通道的输入数据。目前支持的输入是感知模块的障碍物,车辆定位和车辆规划。

imgimg

12.2.2 场景 Scenario

输入障碍物车状态、主车状态及相关车道信息,输出场景相关联信息。其中interaction(交互标志位)是7.0中新增加的一部分。

imgimg

6.0和7.0的区别

6.0 的思想是将车辆及人过去的状态和位置作为输入,放在神经网络中,得到一个未来的预测,实际上还是拟合函数的核心思想。

7.0中会先根据障碍车的位置判断是不是交互式的车辆(危险等级为ineraction及caution),然后针对交互式的车辆用交互式模型。

如果是其他类型的车辆(normal),使用巡航MLP评估器及路口MLP评估器,对于不在道路上的,使用卡尔曼滤波器。所以因此7.0更加细分了感知障碍物的类别判断,新增的一类使感知预测更加细致,提升点在于有针对性,预测效果也更好。

12.2.3 评估器 Evaluator

评估器对任何给定的障碍分别预测路径和速度。评估器通过使用存储在prediction/data/模型中的给定模型输出路径的概率来评估路径(车道序列)。

将提供三种类型的评估器,包括:

  • 成本评估器:概率是由一组成本函数计算的。
  • MLP评估器:用MLP模型计算概率
  • RNN评估器:用RNN模型计算概率

输入障碍物的信息及场景信息,评估器为机器学习的模型,输出障碍物的轨迹或意图,其中障碍物意图是指障碍物在每个车道序列的概率。

imgimg

障碍物主要分为四类:自行车、行人、车辆、未知障碍物(感知模块中未检测出的)。

在预测模块中,不同的障碍物类型对应不同的评估器和预测器。

12.2.4 预测器(predictor)

预测器生成障碍物的预测轨迹。当前支持的预测器包括:

  • 空:障碍物没有预测的轨迹
  • 单行道:在公路导航模式下障碍物沿着单条车道移动。不在车道上的障碍物将被忽略。
  • 车道顺序:障碍物沿车道移动
  • 移动序列:障碍物沿其运动模式沿车道移动
  • 自由运动:障碍物自由移动
  • 区域运动:障碍物在可能的区域中移动

13 Routing

参考文章
Apollo 导航模块记录(routing模块) - 知乎 (zhihu.com)

13.1 Routing模块简介

Routing类似于现在开车时用到的导航模块,通常考虑的是起点到终点的最优路径(通常是最短路径),Routing考虑的是起点到终点的最短路径,而Planning则是行驶过程中,当前一小段时间如何行驶,需要考虑当前路况,是否有障碍物。Routing模块则不需要考虑这些信息,只需要做一个长期的规划路径即可,过程如下:

introduction

这也和我们开车类似,上车之后,首先搜索目的地,打开导航(Routing所做的事情),而开始驾车之后,则会根据当前路况,行人车辆信息来适当调整直到到达目的地(Planning所做的事情)。

  • Routing - 主要关注起点到终点的长期路径,根据起点到终点之间的道路,选择一条最优路径。
  • Planning - 主要关注几秒钟之内汽车的行驶路径,根据当前行驶过程中的交通规则,车辆行人等信息,规划一条短期路径。

13.2 实现

Apollo的routing模块读取高精地图原始信息,用于根据输入的RoutingRequest信息在base_map中选取匹配最近的点作为导航轨迹的起点和终点 ,读取依据base_map生成的routing_map作为生成topo_graph 的,然后通过AStart算法在拓扑图中搜索连接起始点的最优路径RoutingResponse,作为输出发送出去。

13.2.1 输入信息

routing模块的信息输入包括两个固定信息:高精地图原始信息(base_map)和生成的拓扑图(routing_map),一个外部输入的起始点请求信息(RoutingRequest)。

base_map信息和routing_map信息的读取在http://routing.cc的Init()函数中完成代码如下:

img

RoutingRequest信息是其他模块发送的,RoutingComponent通过继承Component组件,实现Routing模块事件触发,代码如下:

img

13.2.2 处理输入信息

13.2.2.1 从地图中选取最佳匹配点

选择匹配点的函数在http://routing.cc的FillLaneInfoMissing()函数中,代码如下:

img

搜索过程中,存在因车道重叠而增加的lane信息,将该部分车道信息也增加如修正后的请求信息(fixed_requests)中,到此完成输入请求点信息的修正,用于后续进行路径搜索:

img

1.3.2.2 搜索导航路径信息

routing模块的路径搜索功是通过AStart算法完成的,在http://a_start_strategy.cc的Search函数中实现,输入修正后的起点、终点、读取的拓扑地图以及根据起点终点生成的子拓扑图,得到起点到达终点的点集:

img

img

img

完成从起点到达终点的路径搜索后,还需要从中规划出一条完整的轨迹,然后生成可通行区域和Road。

1)规划起始点到达终点路径

在Reconstruct()函数中,从终点到起点进行反向搜索,获取轨迹点:

img

img

2)提取基础可通行区域

将重组得到的一条完整轨迹按照是否需要换道,生成基础可通行区域:

img

img

红色的laneID为具有换道属性节点,依据这些特殊节点,将可通行路径进行划分,可通行路径的换道属性为图中标注的属性。

3) 对提取的可通行区域进行扩展

AStart算法搜索得到的是一条唯一可通行路径,路径上存在可以通过换道到达相同目的地的路径,因此需要对得到的路径进行向前、向后两个方向的扩展:

img

img

img

img

红色laneID为向前搜索新增的节点,橙色laneID为向后搜索新增的节点。

13.2.3 生成RoadSegments

遍历扩展得到的可通行区域,依据是否可以通过换道到到达该节点,对扩展的可性行进行道路段构建:

img

img

生成的Response中,包含road,passage,segment信息,为一条指引从起点到达终点的行驶路径的节点索引,roadID为第一个节点对应的道路ID,不包含车道中心线每个位置点信息,所以不能直接用于Planning模块。

将生成的Rosponse信息发送出去,Planning模块接受导航信息,然后生成PNC_Map,指引生成参考线轨迹,用于规划控制。

14 Transform

参考文章
百度Apollo无人驾驶图解传感器地球之间的坐标关系以及如何转换 - 知乎 (zhihu.com)
百度Apollo智能驾驶进阶课程--第三章 百度Apollo定位技术
Apollo项目坐标系研究_知行合一2018的博客-CSDN博客_apollo 坐标系
三、Apollo自定位技术详解(入门技术与基础知识)_一只小麻团的博客-CSDN博客_apollo定位

主要的用途是进行坐标转换。

百度Apollo项目用到了多种坐标系,其中帮助文档提及的坐标系包括:全球地理坐标系(The Global Geographic coordinate system )、局部坐标系—东-北-天坐标(The Local Frame– East-North-Up,ENU)、车身坐标系—右-前-天坐标(The Vehicle Frame —Right-Forward-Up,RFU)、车身坐标系—前-左-天坐标(The Vehicle Frame —Front-Left-Up,FLU)。还有一种Frenet坐标系(又称Frenet–Serret公式),Apollo项目文档未提及,但在Apollo项目的规划模块中得到广泛使用。

14.1 常用的坐标系

坐标系 简述 特点 图示 例子
地心惯性坐标系—i系(ECI) 原点:地球原点;Z轴:沿地轴方向指向北极;X轴、Y轴:位于赤道平面内,与Z轴满足右手法则,并且分别指向两个恒星 X、Y轴指向两颗恒星;不随地球自转而转动;可以作为地球附近传感器输出的惯性坐标系 i系红色坐标系 在研究载体在地球表面附近的运动时,近似看作关性坐标系,如IMU
地心地固坐标系—e系(ECEF) 原点:地球原点;Z轴:沿地轴方向指向北极;X轴:赤道平面与格林威治子午面的交线上;Y轴:在赤道平面,与X轴、Z轴满足右手法则 与地球固定在一起,随地球旋转;假如起始时刻i系与e系重合,二者旋转关系只与时间相关。旋转图示角度,i系与e系重合;地球表面的任意一点可以使用确定的坐标系(x,y,z)表示 e系绿色坐标系 常用的如WGS84坐标系系统
当地水平坐标系—l系 原点:载体所在的地球表面;X、Y轴在当地水平面内分别指向东和北,Z轴垂直向上,与X、Y轴满足右手法则 与地球固连在一起,随地球转动;与e系的旋转关系只与载体所在精度、纬度有关 l系蓝色坐标系 机器人领域的世界坐标系(w系);导航坐标系(n系);“东-北-天(E-N-U)”坐标系
通用横轴墨卡托投影(UTM投影) “等角横轴割圆投影” :椭圆柱割地球于南纬80度、北纬84度两条等高圈,投影后两条相割的经线上没有变形,而中央经线上长度比0.9996。按经度分为60个带,没带6度,从西经180度算起 坐标(x,y)加投影带号才能唯一表示地球表面一点;坐标与经纬度或者ECEF坐标系有确定的转换关系 UTM 平时定位所输出的坐标系
车体坐标系—b系 原点:载体质量中心与载体固连,车体选取原点在后轴中心位置;X轴:沿载体轴向指向右;Y轴:指向前;Z轴:与X、Y轴满足右手法则指向天。(R-F-U右前上坐标系) 与载体固连在一起,随载体一起转动;与n系的旋转关系可以表征载体的当前姿态信息 车体坐标系 /
IMU坐标系 原点:陀螺仪和加速计的坐标原点;X、Y、Z三轴方向分别与陀螺仪和加速计的对于轴向平行 与载体固连在一起,不考虑安装偏角,与载体坐标系重合;与n系的旋转关系可以表征载体的当前姿态信息 IMU坐标系 /
相机坐标系 图中O点为摄像机光心(投影中心),Xc轴和Yc轴与成像平面坐标系的x轴和y轴平行;Zc轴为摄像机的光轴,和图像平面垂直 通常IMU坐标系的原点在世界坐标系的位置是已知的,通过IMU坐标系到相机坐标系的外参,以及IMU坐标系的姿态,可以得到相机坐标系到世界坐标系的转换 相机坐标系 /
激光雷达坐标系 原点:多线束中心旋转轴的交点处,z轴沿轴线向上;X、Y轴如俯视图所示 通过IMU坐标系到激光雷达坐标系的外参,以及IMU坐标系的姿态,可以得到激光雷达坐标系到世界坐标系的转换 激光雷达坐标系 /

无人车定位信息中涉及的坐标系

无人车定位信息设计的坐标系

15 V2X

(img-VZUM2oTg-1657176721093)(image-20220707135435114.png)]

16 DreamView

参考文章
【Apollo 6.0项目实战】Dreamview的使用_Travis.X的博客-CSDN博客_apollo dreamview

DreamView是一个web应用程序,提供如下的功能:

  1. 可视化显示当前自动驾驶车辆模块的输出信息,例如规划路径、车辆定位、车架信息等。
  2. 为使用者提供人机交互接口以监测车辆硬件状态,对模块进行开关操作,启动自动驾驶车辆等。
  3. 提供调试工具,例如PnC监视器可以高效的跟踪模块输出的问题

17 其他优秀内容

参考文章
vscode中Apollo代码调试方法_hello1268的博客-CSDN博客_apollo 调试
posted @ 2022-07-07 14:59  爱是与世界平行  阅读(7878)  评论(0编辑  收藏  举报