ROS2 相比较于 ROS1 在编译方式上比较类似,但是在内部功能实现上却发生了很大的改变,比如构建工具从 catkin_make 更换为了 colcon, 在构建的选择上更加灵活,更容易集成更多的工具,甚至兼容非 ROS package 的工程构建。基础的 cmake 升级为了基于 cmake 封装的 ament_cmake, 为开发者减少了更多的繁琐的 cmake 配置,使开发者能够更好专注于代码的开发。这里介绍 ROS2 编译的几个关键步骤以及涉及到的几个关键的 package, 使得大家能够全面的了解到 ROS2 的整个编译系统是怎么工作的。
ROS2 编译流程与 ROS1 基本一致,ros_buildfarm 工作的流程也与这个基本类似,只是实现比较复杂,核心的流程如下图所示:
如上图所示,整个流程可以概括为几个步骤:
接下来的章节会讲解每个模块的作用以及各部分与 ros package 是怎样衔接起来的。
colcon 是 ROS2 编译,测试等主要的工具,使用方式延续了 ROS1 的风格,降低了切换后的上手难度,同样,ROS2 的工作空间推荐与 ROS1 保持一样的目录结构:
├── build # 编译时自动生成,包含编译的中间文件
├── install # 编译时自动生成,包含编译的结果:可执行文件,库文件,message 头文件等
├── log # 编译时的日志,方便在编译失败时查找问题(ros2 新增)
└── src
├── ros_package1 # 开发者的代码
├── ros_package2
├── ros_package3
......
注意:执行 colcon 命令需要在 workspace
目录,因为默认生成的 build
,install
,log
文件夹会与 colcon 执行文件夹保持同级,这一点是与 ROS1 不同的
colcon 最常用的有以下几个命令:
colcon build
这个是最基本命令,默认是选用 ninja 作为构建方式并且使用 8线程 进行代码的编译。 编译的结果在install
文件夹中是以 package 为单位存放的,这个与 catkin_make_isolated
作用类似。
colcon build --merge-install
这个与 catkin_make
功能一样,是将编译的结果进行合并安装,比如头文件都放在 install/include
目录下, 库文件都放在 install/lib
文件夹下等。
colcon build --symlink-install
将编译的结果以软链接的方式进行安装,这个在程序开发的过程中非常实用。比如如果是 python 的 ros package, 后续将不需要再重新 colcon build, 直接修改源码就可以再次运行,加快了开发的效率。同样对于 C++ 工程而言,如果你是修改 rclcpp 或者系统中已经安装的同名的文件包的话,在编译时搜寻的头文件将是自己 workspace
下的,而不是系统目录下的头文件(/opt/ros/xx/include
),这点与 ROS1 中的 catkin_make 中的 devel 开发方式保持一致。
colcon build --packages-select
编译指定的 ros package, 类似于 ROS1 的白名单的功能。
colcon build --packages-ignore
忽略编译指定的 ros package。同样也可以在 ros_package 目录下创建 COLCON_IGNORE
空文件以忽略编译。
colcon build --cmake-args -Dxxx
在编译的时候指定特定的 cmake 变量的值。
colcon build --parallel-workers
在编译的时候指定同时编译的最大线程数,默认为 8,对于性能好的机器来说,可以适当的增加这个值来加快编译速度。
rosdep是 ROS 软件包依赖管理的命令行工具,可以为开发人员在编译,部署时解决开发的软件包编译及运行依赖的问题,最常见的就是解决 xxxConfig.cmake not found 的问题。
rosdep 的工作步骤一般如下:
rosdep init
初始化远程服务器的地址
rosdep update
将 ros package 的依赖关系缓存在本地
rosdep install --from-paths src --ignore-src src -y
通过查询每一个 ros_package 下的 package.xml
文件中的值来确定要下载的依赖包并进行安装
例如:在 ROS2 代码示例 examples 中 rclcpp/topics/minimal_publisher
这个目录下的 package.xml
中
<build_depend>rclcppbuild_depend>
<build_depend>std_msgsbuild_depend>
<exec_depend>rclcppexec_depend>
<exec_depend>std_msgsexec_depend>
<test_depend>ament_lint_autotest_depend>
<test_depend>ament_lint_commontest_depend>
rosdep 会读取 xxx_depend 中的值来判断本地是否存在相应的依赖,如果没有的话,rosdep 会选择合适的方式去下载依赖文件。
rosdistro 可以理解为一个简单的数据库,里面存储了 ros package 的依赖关系,目前在 github 上以 git 仓库的方式维护,在 rosdep update 的时候会将里面的信息缓存在本地,所以在网速不好的情况下,可以将这个仓库镜像到本地以提高 rosdep update 的速度。
另外,在自己开发的过程中往往会有自己创建的 ros 软件包,这些软件包可能不在 rosdistro 的维护列表内,这样可能会在 rosdep install 的时候出现解析不到正确的依赖而失败,这个时候一个可行的解决办法是将自己的软件包添加到 rosdistro 仓库中已解决 rosdep install 的问题。
一个简单的例子如下:
/etc/ros/rosdep/sources.list.d/
目录下添加一个名为 50-my-default.list
的文件50-my-default.list
添加以下内容yaml file:///home/user/.ros/rosdep.yaml
rosdep.yaml
文件, 并写入以下内容rosdep_name: # 自己定义的软件包的名字
ubuntu: # 发行版系统类型
apt: # 下载方式 apt, pip 等
packages: [ debian-package-name, other-debian-package-name] # 依赖 deb 包的名字
详细的 rosdep_yaml 可以参考 http://docs.ros.org/en/independent/api/rosdep/html/rosdep_yaml_format.html
bloom 是一个打包工具,可以将代码制作成 deb, rpm 包,方便的安装到目标机器上进行测试,避免了直接拷贝文件带来的操作繁琐,容易出错的问题,一般情况下 bloom 是不随 ROS2 基础包一并安装的,bloom 的安装方式如下:
sudo apt-get install python3-bloom fakeroot
bloom 的工作方式:
参考操作命令:
cd <ros package 的目录下>
bloom-generate rosdebian --os-name <系统名字> --ros-distro <ros版本名字>
fakeroot debian/rules binary
ROS2: https://docs.ros.org/en/humble/index.html#
colcon: https://colcon.readthedocs.io/en/released/index.html
rosdep: https://github.com/ros-infrastructure/rosdep.git
rosdistro: https://github.com/ros/rosdistro.git
bloom: https://github.com/ros-infrastructure/bloom.git