Files
ROS2_learn/doc/80-package-build.md
T
2026-08-05 18:17:25 +08:00

12 KiB

80 · 包构建机制 colcon / ament(完全指南)

目标:理解 ROS2 一个包从源码到 ros2 run 能找到的完整流程,能自己写 ament_python / ament_cmake 包。


目录


1. 工作空间结构

ros2_ws/                      ← 工作空间根
├── src/                      ← 包源码(你写代码的地方)
│   ├── pkg_a/                ← 一个 ROS 包
│   ├── pkg_b/
│   └── ...
├── build/                    ← colcon build 中间产物
├── install/                  ← colcon install 产物(ros2 唯一识别)
├── log/                      ← build/test 日志
└── ...

install/ 是唯一能被 ros2 命令识别的目录。每次进新 shell 必须:

source install/setup.bash

2. 包类型

ROS2 有两种主流 build_type:

build_type 文件 用途
ament_python setup.py + package.xml Python 包
ament_cmake CMakeLists.txt + package.xml C++ 包
ament_cmake_python 两者混合 复杂项目

3. package.xml(包身份证)

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd"?>
<package format="3">
  <name>my_pkg</name>
  <version>0.1.0</version>
  <description>...</description>
  <maintainer email="x@y.com">Name</maintainer>
  <license>Apache-2.0</license>

  <depend>rclpy</depend>           <!-- 构建 + 运行都需 -->
  <build_depend>rosidl_default_generators</build_depend>
  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>
字段 含义
<depend> 构建 + 运行
<build_depend> 仅构建
<exec_depend> 仅运行
<test_depend> 仅测试
<build_type> ament_python / ament_cmake

4. ament_python 包详解

4.1 目录结构

py_pubsub/
├── package.xml
├── setup.py              ← 标准 setuptools
├── setup.cfg             ← ament_python 脚本目录约定
├── resource/
│   └── py_pubsub         ← 空文件,ament_index marker(必填!)
├── py_pubsub/            ← Python 模块
│   ├── __init__.py
│   └── *.py
├── launch/
│   └── *.py
└── test/
    └── test_*.py

4.2 setup.py

from setuptools import find_packages, setup

package_name = 'py_pubsub'

setup(
    name=package_name,
    version='0.1.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        ('share/' + package_name + '/launch', ['launch/*.py']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='xs',
    maintainer_email='dev@example.com',
    description='Python talker/listener demo for ROS2 Humble',
    license='Apache-2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'talker   = py_pubsub.publisher_member_function:main',
            'listener = py_pubsub.subscriber_member_function:main',
        ],
    },
)

关键点:

  • data_files 必须把 package.xml + launch/ 拷到 share/<pkg>/
  • resource/<pkg> 空文件 → ament_index marker(必填!)
  • entry_points/console_scripts 暴露 ros2 run 可执行名

4.3 setup.cfg

[develop]
script_dir=$base/lib/py_pubsub
[install]
install_scripts=$base/lib/py_pubsub

控制 console_scripts 装到 $base/lib/<pkg>/,ROS2 启动器能找到。


5. ament_cmake 包详解

5.1 目录结构

cpp_pubsub/
├── package.xml
├── CMakeLists.txt
├── src/
│   └── *.cpp
├── include/                ← 公开头文件(可选)
├── launch/
│   └── *.py
├── test/
│   └── test_*.cpp
└── config/                 ← YAML 配置(可选)

5.2 CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(cpp_pubsub VERSION 0.1.0)

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 17)
endif()

# GCC/Clang 编译警告
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

include_directories(include)

# 节点可执行
add_executable(talker src/publisher_member_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)

add_executable(listener src/subscriber_member_function.cpp)
ament_target_dependencies(listener rclcpp std_msgs)

# 装到 install/lib/<pkg>/
install(TARGETS talker listener DESTINATION lib/${PROJECT_NAME})

# launch 文件装到 share/<pkg>/launch/
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}/)

# 测试
if(BUILD_TESTING)
  find_package(ament_cmake_gtest REQUIRED)
  ament_add_gtest(test_pub_sub test/test_pub_sub.cpp)
  ament_target_dependencies(test_pub_sub rclcpp std_msgs)
endif()

ament_package()    必填!

关键:

  • ament_target_dependencies(<target> pkg1 pkg2) 同时设置 include path 和 link
  • install(TARGETS ...) 把可执行装到 install
  • install(DIRECTORY launch ...) 把 launch 装到 share
  • ament_package() 末尾必填

6. colcon build 内部流程

colcon build --symlink-install --packages-select <pkg>

按依赖顺序,每个包:

┌──────────────────────────────────────────────────────────┐
│ 1. 发现 src/<pkg>/ 下的 package.xml                     │
│ 2. 读 <export><build_type>,决定 build type            │
│ 3. 调用对应 build_type 的 hook:                         │
│      ament_python  → python setup.py build + install     │
│      ament_cmake   → cmake + make + ament_package       │
│ 4. 写 ament_index 标记 (share/ament_index/...)           │
│ 5. 把产物装到 install/<pkg>/                           │
└──────────────────────────────────────────────────────────┘

--symlink-install:

  • Python:源码软链到 install,改源码立即生效(不用重 build)
  • C++:可执行仍硬编,但 launch / config 文件软链

7. ament_index 与 ros2 工具发现

ros2 run / launch / pkg executables / topic info 等命令都靠 ament_index:

  • 启动时扫 install/<pkg>/share/ament_index/resource_index/packages/<pkg> 文件
  • 找到包路径后,扫 install/<pkg>/lib/<pkg>/ 找可执行
  • install/<pkg>/share/<pkg>/launch/ 找 launch 文件

手动重建索引(极少需要):

# 索引在 install/share/ament_index/ 里,正常情况下 colcon build 自动维护
ros2 doctor --report    # 看索引健康

8. 依赖解析与 rosdep

package.xml<depend> 让 colcon 自动排构建顺序:

  • 你的 py_pubsub 依赖 rclpy,rclpy 是 apt 包,colcon 跳过
  • py_srv 依赖 example_interfaces,同上
  • colcon 只 build 我们 src/ 下的包

rosdep 是 apt 包管理:

sudo rosdep init && rosdep update
sudo rosdep install -i --from-paths src/   # 装齐所有 apt 依赖

本仓库基础镜像 osrf/ros:humble-desktop 已装齐所有 ROS2 客户端,不需要额外 rosdep


9. 自定义消息 / 服务 / Action(进阶)

需要:

  1. 在包内建 msg/srv/action/ 目录
  2. .msg / .srv / .action 文件
  3. package.xml 加:
    • <build_depend>rosidl_default_generators</build_depend>
    • <exec_depend>rosidl_default_runtime</exec_depend>
  4. CMakeLists.txtrosidl_generate_interfaces(${PROJECT_NAME} ${MSG_FILES} ...)
  5. setup.py data_files('share/<pkg>/msg': ['msg/*.msg'], ...)
  6. ament_python 需要单独 rosidl(混合构建)

本仓库只用 example_interfaces 自带的 Fibonacci / AddTwoInts(由 ROS2 系统包提供),避开这个复杂度。


10. 常见构建错误 + 解决

10.1 Could not find a package configuration file provided by "rclpy"

少装 apt 包:

sudo apt install ros-humble-rclpy   # 镜像外

10.2 Package 'X' not found in colcon build

ament_index 没刷新。重启容器 + source install/setup.bash。

10.3 ament_python install 0 files

setup.pypackages= 不对。检查 py_pubsub/ 下有 __init__.py

10.4 launch 文件未找到

检查 setup.py:

('share/' + package_name + '/launch', ['launch/*.py']),

launch/*.py 是 glob,不是 'launch/foo.py'

10.5 ROS Domain 冲突

ROS_DOMAIN_ID=0 默认。多项目用 ROS_DOMAIN_ID=42 隔离。

10.6 Cyclone DDS 缓存了 CMakeCache

Could not find ROS middleware implementation 'rmw_cyclonedds_cpp' 但又设了 RMW_IMPLEMENTATION=rmw_cyclonedds_cpp → CMake 缓存了。 修法:

rm -rf build install log
colcon build ...

11. 在本仓库里跑

11.1 全部 build

cd /root/ros2_ws
# ❗ --executor sequential 必需:cpp_custom_interface 的 rosidl export cmake 在并行构建时偶发失败
colcon build --symlink-install --executor sequential \
  --packages-select py_pubsub cpp_pubsub py_srv py_action_demo \
    cpp_robot_tf2 py_vision_demo py_params cpp_custom_interface \
    py_lifecycle_composable cpp_qos_demo py_overlay_dds bringup

11.2 增量 build(只编改的)

colcon build

11.3 清理后重 build

rm -rf build install log
colcon build --symlink-install

11.4 单包 build

colcon build --packages-select py_pubsub

12. 进阶:多包 workspace / release 流程

12.1 多 workspace 覆盖

# 用 setup.bash 叠加
source /opt/ros/humble/setup.bash
source /workspace1/install/setup.bash
source /workspace2/install/setup.bash
# 后 source 的覆盖前面

12.2 Release 流程

# 1) bloom-generate 准备 release
sudo apt install python3-bloom
bloom-generate rosdebian --os-only ubuntu:jammy

# 2) 构建 .deb 包
bloom-release --rosdistro humble --track humble --new 0.1.0 my_pkg

# 3) 推送到 ROS 仓库(rosindex / GitHub)

本仓库未发布,如要 release 走标准流程。


接下来读

主题 文档
Launch 文件 70-launch.md
Docker 开发 85-docker.md
测试策略 90-testing.md
三机部署 100-embedded-deployment.md


📖 阅读路径导航

💡 这是仓库 doc/ 下所有文档的推荐阅读顺序。返回 README 总导航

本文预计阅读时间: 40 分钟 📍 当前位置: 第 19 / 24 篇