第三章:源码编译与工程结构

说实话,源码编译这件事,我见过太多人在这里卡住了。明明文档写得清清楚楚,但就是编译不过。我自己刚接触 Autoware 和 Apollo 时也踩过不少坑,今天就把这些经验掰开揉碎讲给你听。

3.1 Autoware 源码下载与编译

Autoware 的源码托管在 GitHub 上,地址是 https://github.com/autowarefoundation/autoware。我个人习惯用 git clone --recursive 来拉取,因为 Autoware 依赖很多子模块,一条命令全搞定。

git clone --recursive https://github.com/autowarefoundation/autoware.git
cd autoware

嗯,这里要注意:网络不好的时候,子模块容易拉取失败。我曾经遇到过某个子模块死活下不下来,后来发现是公司网络屏蔽了部分域名。解决办法是手动修改 .gitmodules 文件,把 https 换成 git 协议,或者直接挂代理。

编译 Autoware 推荐用 colcon,这是 ROS2 的官方构建工具。命令很简单:

colcon build --symlink-install

为什么加 --symlink-install?说白了就是方便调试。你改了 Python 脚本或者 launch 文件,不用重新编译,直接生效。我刚开始不知道这个参数,每次改个参数都要等十几分钟重新编译,后来同事提醒了我,瞬间感觉打开了新世界。

注意:Autoware 对 ROS2 版本有严格要求。目前推荐使用 ROS2 Humble,搭配 Ubuntu 22.04。如果你用 ROS2 Galactic 或者 Foxy,可能会遇到依赖冲突。我试过在 Foxy 上硬编,结果折腾了两天,最后还是乖乖换了系统。

编译过程中如果报错,别慌。大部分错误都是缺少依赖包。你可以用 rosdep 来安装:

rosdep install -y --from-paths src --ignore-src --rosdistro humble

这个命令会自动检测缺少的依赖并安装。不过要注意,rosdep 有时候会漏掉一些非 ROS 的依赖,比如 libpcap-dev、libboost-all-dev 这些。我建议你提前装好:

sudo apt install -y libpcap-dev libboost-all-dev libeigen3-dev

3.2 Apollo 源码下载与编译

Apollo 的源码在 https://github.com/ApolloAuto/apollo。它的编译方式和 Autoware 完全不同,用的是 Docker 容器化方案。说白了,就是百度把编译环境打包成了一个 Docker 镜像,你只需要拉下来就能用。

git clone https://github.com/ApolloAuto/apollo.git
cd apollo
bash docker/scripts/dev_start.sh
bash docker/scripts/dev_into.sh
./apollo.sh build_opt

这里有个坑:dev_start.sh 会拉取一个很大的 Docker 镜像(大概 5-6GB),网速慢的话可能要等很久。我建议你提前在晚上或者周末跑这个命令,别等到演示前才拉。

进入 Docker 容器后,./apollo.sh build_opt 是编译优化版本。如果你需要调试,可以用 ./apollo.sh build_dbg。我个人习惯先用 build_opt 确认能编译通过,再切到 build_dbg 加调试信息。

小技巧:Apollo 编译时默认会使用所有 CPU 核心,如果你的电脑配置一般(比如只有 8GB 内存),建议限制一下并行数。可以在 apollo.sh 里找到 --jobs 参数,改成 --jobs=4,不然内存很容易爆掉。

编译完成后,你会看到 output/ 目录下生成了很多二进制文件和库。Apollo 的编译产物是分模块的,比如 planning、control、perception 等,每个模块都有独立的可执行文件。

3.3 工程目录结构解析

两个项目的目录结构差异很大,但核心逻辑是相通的。我画了一张图帮你理解:

Autoware 目录结构 src/ — 源码目录 planning/ — 规划模块 control/ — 控制模块 perception/ — 感知模块 localization/ — 定位模块 install/ — 编译产物 launch/ — 启动文件 config/ — 配置文件 map/ — 地图数据 Apollo 目录结构 modules/ — 模块目录 planning/ — 规划模块 control/ — 控制模块 perception/ — 感知模块 localization/ — 定位模块 docker/ — Docker 相关 scripts/ — 脚本工具 output/ — 编译输出 data/ — 数据与地图

你看,两个项目的模块划分其实很像,都有 planning、control、perception、localization 这些核心模块。区别在于组织方式:Autoware 用 ROS2 的 workspace 结构,Apollo 用自己定义的模块结构。

具体来说,Autoware 的 src/ 下面每个模块都是一个独立的 ROS2 包,有自己 package.xml 和 CMakeLists.txt。而 Apollo 的 modules/ 下面每个模块是一个独立的目录,内部有 BUILD 文件(Bazel 构建系统用)。

核心区别:
  • Autoware 使用 ROS2 的 colcon 构建,模块间通过 ROS2 的 topic/service 通信
  • Apollo 使用 Bazel 构建,模块间通过 CyberRT 框架通信
  • Autoware 的配置文件是 YAML 格式,放在 config/ 下
  • Apollo 的配置文件是 protobuf 格式,放在模块内部的 conf/ 下

我个人觉得,如果你熟悉 ROS2,上手 Autoware 会快很多。但 Apollo 的 CyberRT 性能更好,延迟更低。我在实际项目中做过对比,同样一个规划算法,在 Apollo 上跑比在 Autoware 上快大概 15-20%。当然,这跟具体实现也有关系。

最后说一个我踩过的坑:两个项目的坐标系定义不一样。Autoware 默认用 ENU(东-北-天),Apollo 默认用 FLU(前-左-天)。如果你做协同开发,一定要在数据接口层做坐标系转换,不然定位数据直接对接会出大问题。

避坑指南:我曾经在 Autoware 和 Apollo 之间直接传定位数据,结果车辆在模拟器里原地打转。查了两天才发现是坐标系没对齐。后来我在中间加了一个坐标转换节点,问题就解决了。建议你在设计系统架构时,就把坐标系转换作为一个独立模块来考虑。

好了,源码编译和工程结构就讲到这里。记住,编译只是第一步,真正重要的是理解每个模块的作用和它们之间的协作关系。下一章我们会深入代码,看看各个模块是怎么跑起来的。

可可精品资料库