ROS2 Package 结构与编译 ROS2 官方文档
概述 ROS2 Package 是代码组织的基本单元。每个 Package 至少包含:
package.xml - 包元数据(名称、版本、依赖、维护者)
构建系统文件(CMakeLists.txt 或 setup.py)
CMake vs Python Package 对比
方面
CMake Package
Python Package
构建文件
CMakeLists.txt
setup.py + setup.cfg
语言
C/C++(可包含 Python)
纯 Python
编译
编译为二进制
解释执行(无需编译)
build_type
ament_cmake
ament_python
节点位置
src/ 目录
<package_name>/ 目录
入口点
CMakeLists.txt 定义
setup.py entry_points 定义
典型目录结构 CMake Package 1 2 3 4 5 6 7 8 9 my_cpp_pkg/ ├── CMakeLists.txt ├── package.xml ├── src/ │ └── my_node.cpp ├── include/ │ └── my_cpp_pkg/ │ └── header.hpp └── launch/
Python Package 1 2 3 4 5 6 7 8 9 10 my_py_pkg/ ├── setup.py ├── setup.cfg ├── package.xml ├── my_py_pkg/ │ ├── __init__.py │ └── my_node.py ├── launch/ # 启动文件 ├── resource/ # 包发现标记文件 └── test/ # 测试文件(不会被安装)
Python Package 特殊目录说明
目录
用途
安装位置
launch/
启动文件
install/<pkg>/share/<pkg>/launch/
resource/
包发现标记(空文件)
install/<pkg>/share/ament_index/resource_index/packages/
test/
测试文件
不安装,仅用于 colcon test
在 setup.py 中配置:
1 2 3 4 5 data_files=[ ('share/ament_index/resource_index/packages' , ['resource/my_pkg' ]), ('share/' + package_name, ['package.xml' ]), ('share/' + package_name + '/launch' , glob('launch/*.py' )), ]
编译与可执行文件位置 编译命令 1 2 colcon build colcon build --symlink-install
Workspace 结构 1 2 3 4 5 6 7 8 9 10 workspace/ ├── build/ # 中间构建文件 ├── install/ # 最终安装文件 │ └── <package_name>/ │ ├── lib/<package_name>/ │ │ └── <executable> # 可执行文件位置 │ └── share/<package_name>/ │ ├── launch/ │ └── package.xml └── src/ # 源代码
运行节点 1 2 source install/setup.bashros2 run <package_name> <executable_name>
Launch 文件编写 基本结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from launch import LaunchDescriptionfrom launch_ros.actions import Nodedef generate_launch_description (): return LaunchDescription([ Node( package='package_one' , executable='node_one' , name='custom_name' , parameters=[{'param1' : 'value1' }], remappings=[('/old_topic' , '/new_topic' )], output='screen' , ), Node( package='package_two' , executable='node_two' , ), ])
Node 常用参数
参数
用途
package
包名
executable
可执行文件名
name
覆盖节点名
namespace
命名空间前缀
parameters
参数列表或 yaml 文件路径
remappings
Topic/Service 重映射
output
'screen' 显示输出,'log' 仅记录
arguments
命令行参数
包含其他 Launch 文件 1 2 3 4 5 6 7 8 9 10 11 12 13 from launch.actions import IncludeLaunchDescriptionfrom launch.launch_description_sources import PythonLaunchDescriptionSourcefrom ament_index_python.packages import get_package_share_directoryimport osdef generate_launch_description (): other_launch = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(get_package_share_directory('other_pkg' ), 'launch' , 'other.launch.py' ) ) ) return LaunchDescription([other_launch])
运行 Launch 文件 1 ros2 launch <package_name> <launch_file.py>
接口包(Interface Package) 专门定义自定义 msg/srv/action 的包,必须使用 ament_cmake。
目录结构 1 2 3 4 5 6 7 8 9 my_interfaces/ ├── CMakeLists.txt ├── package.xml ├── msg/ │ └── MyMessage.msg ├── srv/ │ └── MyService.srv └── action/ └── MyAction.action
package.xml 关键依赖 1 2 3 4 <buildtool_depend > ament_cmake</buildtool_depend > <build_depend > rosidl_default_generators</build_depend > <exec_depend > rosidl_default_runtime</exec_depend > <member_of_group > rosidl_interface_packages</member_of_group >
CMakeLists.txt 关键配置 1 2 3 4 5 6 7 8 find_package (rosidl_default_generators REQUIRED)rosidl_generate_interfaces(${PROJECT_NAME} "msg/MyMessage.msg" "srv/MyService.srv" "action/MyAction.action" DEPENDENCIES geometry_msgs std_msgs )
在其他包中使用 1 2 <depend > my_interfaces</depend >
1 2 3 4 from my_interfaces.msg import MyMessagefrom my_interfaces.srv import MyServicefrom my_interfaces.action import MyAction
注意事项
接口包(msg/srv/action)必须使用 CMake,不能用纯 Python 包
--symlink-install 对 Python 包开发很有用,修改后无需重新编译
resource/ 目录中的标记文件是 ament_python 包发现机制必需的
Launch 文件支持 .py、.xml、.yaml 三种格式,Python 格式最灵活