ROS Package(功能包)
- ROS Package 是 ROS 中最小的可编译 / 可运行单元,一个机器人功能(比如激光 SLAM、电机控制)通常对应一个或多个 Package。
- 每个 Package 必须包含 package.xml(描述包的元信息)和 CMakeLists.txt(编译构建规则),缺少任何一个都不被 ROS 识别为合法 Package。

ROS中的依赖和CMake库
ROS 里的 “依赖” 本质是:你的功能包想要正常编译、运行,必须依赖的其他软件 / 代码 / 库资源。就像你做一道菜需要食材,你的 ROS 包实现功能也需要 “食材”—— 这些 “食材” 就是依赖。
依赖的分类(对应 package.xml 里的标签)
| 编译时依赖 | 编译代码(catkin_make)时必须有的 “食材”(比如头文件、编译规则) | roscpp(提供 C++ 的头文件)、message_generation(生成 msg 代码) |
| 运行时依赖 | 运行 ROS 节点(rosrun)时必须有的 “食材”(比如动态链接库、可执行程序) | roscpp(提供运行节点的库文件)、rviz(运行可视化工具) |
| 测试时依赖 | 运行 ROS 测试(rostest)时需要的 “食材” | rostest、gtest |
- 头文件(.h/.hpp):比如#include <ros/ros.h> 中的ros.h就是roscpp包提供的头文件,没有它编译代码会报错 “找不到头文件”。
- 库文件(.so/.a):Linux 下的动态 / 静态链接库,比如roscpp会生成libroscpp.so,运行节点时系统需要找到这个库才能启动。
- 可执行程序:比如依赖rviz,本质是依赖rviz包编译出的rviz可执行文件。
- msg/srv 定义文件:比如依赖std_msgs,是依赖它定义的String.msg、Int32.msg等消息格式。
举个直观例子
你写了一个 C++ ROS 节点,代码第一行是:
#include <ros/ros.h> // 用到roscpp的头文件
编译时,编译器需要找到ros.h这个文件(来自roscpp包)—— 这是编译时依赖;运行时,你的节点需要调用roscpp的动态库libroscpp.so—— 这是运行时依赖;如果缺少这两个依赖,要么编译失败,要么运行时提示 “找不到库”。
CMake 库不是 ROS 特有的,是 CMake 构建系统中的核心概念,ROS 基于 CMake 扩展了 catkin,所以会用到这个概念。
1. 先理解 “库(Library)” 的基础
编程中的 “库” 是提前编译好的、可复用的代码集合(对比:可执行文件是直接运行的程序,库是被程序调用的代码)。比如你写的 ROS 节点(可执行文件)会调用roscpp的库,不用自己重新写 “创建节点、发布话题” 的代码。
2. CMake 库的具体含义
在 CMake 中,“CMake 库” 是指:CMake 通过特定指令(如find_package、target_link_libraries)识别、管理、链接的 “库文件”(.so/.a)或 “库配置”。简单说:CMake 库是 CMake 能 “认得到”、能帮你链接到代码里的库资源。
3. CMake 库的核心作用(ROS 场景下)
在 ROS 的CMakeLists.txt中,你写:
# 1. 查找roscpp这个CMake库(本质是找roscpp的编译配置和库文件)
find_package(catkin REQUIRED COMPONENTS roscpp)# 2. 将roscpp的CMake库链接到你的节点
target_link_libraries(my_node ${catkin_LIBRARIES})这两行的核心是:
- find_package(roscpp):CMake 会去系统中找roscpp的 “库配置文件”(比如roscppConfig.cmake),这个文件告诉 CMake:
- roscpp的头文件在哪(比如/opt/ros/noetic/include);
- roscpp的库文件在哪(比如/opt/ros/noetic/lib/libroscpp.so);
- ${catkin_LIBRARIES}:是 CMake 变量,包含了所有找到的 ROS 库(如roscpp、std_msgs)的库文件路径,target_link_libraries会把这些库 “链接” 到你的可执行文件中,让你的节点能调用库的功能。
新手入门时,不用深究 CMake 库的底层实现,只需记住:在 CMakeLists.txt 中,find_package填你依赖的 ROS 包名,target_link_libraries加上${catkin_LIBRARIES},就能正确链接依赖的 CMake 库。
package.xml 解读
package.xml 是包的 “身份证”,用于描述包的元信息(名称、版本、依赖、作者等),ROS 通过它识别包的基本信息和依赖关系。
核心结构(以 ROS Noetic/Melodic 为例,ROS2 格式略有差异)
<?xml version="1.0"?>
<!– 声明ROS版本,noetic对应格式2,kinetic/melodic也常用2 –>
<package format="2">
<!– 1. 必选基础信息 –>
<name>my_package</name> <!– 包名(唯一,小写+下划线) –>
<version>1.0.0</version> <!– 版本号(语义化:主版本.次版本.修订号) –>
<description>My first ROS package</description> <!– 功能描述 –>
<maintainer email="your@email.com">Your Name</maintainer> <!– 维护者(必填) –>
<license>Apache-2.0</license> <!– 许可证(如MIT、BSD、GPL) –>
<!– 2. 依赖声明(核心) –>
<!– build_depend:编译时依赖(比如头文件、CMake库) –>
<build_depend>roscpp</build_depend>
<!– exec_depend:运行时依赖(比如ROS节点运行需要的库) –>
<exec_depend>roscpp</exec_depend>
<!– build_export_depend:编译导出依赖(其他包依赖本包时需要的编译依赖) –>
<build_export_depend>roscpp</build_export_depend>
<!– test_depend:测试时依赖 –>
<test_depend>rostest</test_depend>
<!– 3. 可选信息 –>
<author>Your Name</author> <!– 作者 –>
<url type="website">https://your-url.com</url> <!– 文档/代码地址 –>
</package>
| <name> | 包的唯一标识,命名规则:小写字母 + 下划线(如lidar_driver) |
| <build_depend> | 编译本包需要的依赖(比如roscpp、std_msgs) |
| <exec_depend> | 运行本包节点需要的依赖(大部分场景和build_depend重复) |
| <maintainer> | 必须填写,否则catkin_make会报错,格式:姓名 + 邮箱 |
在 Package 目录下执行:
catkin_lint . # 检查package.xml语法是否正确
rospkg info my_package # 查看包的元信息(验证是否识别)
以下是一段package.xml,读者可以自行解读,
<?xml version="1.0"?>
<package format="2">
<name>imu_filter</name>
<version>0.0.0</version>
<description>imu_filter</description>
<maintainer email="a@a.com">a</maintainer>
<license>BSD</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>tf</build_depend>
<build_depend>tf2</build_depend>
<build_depend>dynamic_reconfigure</build_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>sensor_msgs</exec_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>tf</exec_depend>
<exec_depend>tf2</exec_depend>
<exec_depend>dynamic_reconfigure</exec_depend>
</package>
CMakeLists.txt 解读
CMakeLists.txt 是编译规则文件,告诉 ROS(实际是 catkin 构建系统)如何编译代码、链接库、安装文件等。ROS 基于 CMake 扩展了 catkin,所以文件里既有 CMake 原生语法,也有 catkin 特有语法。
# 1. 声明CMake最低版本(ROS Noetic对应3.0.2+)
cmake_minimum_required(VERSION 3.0.2)
# 2. 声明包名(必须和package.xml的<name>一致)
project(my_package)
# 3. 设置编译选项(可选,解决中文编码、C++版本等问题)
add_compile_options(-std=c++11) # 指定C++11标准
# 4. 查找依赖的ROS包(核心)
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
message_generation # 如果自定义msg/srv,需要加这个
)
# 5. 声明catkin包的导出信息(固定模板)
catkin_package(
INCLUDE_DIRS include # 头文件目录
LIBRARIES ${PROJECT_NAME} # 编译生成的库名
CATKIN_DEPENDS roscpp std_msgs # 依赖的ROS包
# DEPENDS system_lib # 如果依赖非ROS库(如Eigen),加这里
)
# 6. 包含头文件目录(让编译器找到头文件)
include_directories(
include
${catkin_INCLUDE_DIRS} # ROS依赖包的头文件目录
)
# 7. 编译可执行文件(核心:生成ROS节点)
add_executable(my_node src/my_node.cpp) # 源文件→可执行文件
# 链接库(必须加,否则编译报错)
target_link_libraries(my_node
${catkin_LIBRARIES}
)
# 8. 安装(可选:将可执行文件安装到ROS环境)
install(TARGETS my_node
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
# 安装头文件(可选)
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
以下是一段CMakeLists.txt ,读者可以自行解读,
cmake_minimum_required(VERSION 2.8.3)
project(imu_filter)
# 1. 查找所有依赖(顺序固定)
find_package(catkin REQUIRED COMPONENTS
roscpp
sensor_msgs
geometry_msgs
tf
tf2
dynamic_reconfigure
)
# 2. 生成动态参数头文件(仅针对需要的两个滤波器)
generate_dynamic_reconfigure_options(
cfg/MyStuff.cfg
cfg/MyStuff2.cfg
)
# 3. Catkin 包导出配置(顺序固定)
catkin_package(
CATKIN_DEPENDS roscpp sensor_msgs geometry_msgs tf tf2 dynamic_reconfigure
)
# 4. 头文件包含路径(顺序固定)
include_directories(
${catkin_INCLUDE_DIRS}
)
# 5. 第一步:创建可执行目标(严格按「先创建,后操作」)
add_executable(madgwick_imu_filter src/Madgwick_filter.cpp)
add_executable(mahony_imu_filter src/Mahony_filter.cpp)
add_executable(bias_calculator src/bias_calculator.cpp)
# 6. 第二步:添加依赖(仅给需要动态参数的两个目标加)
add_dependencies(madgwick_imu_filter ${PROJECT_NAME}_gencfg ${catkin_EXPORTED_TARGETS})
add_dependencies(mahony_imu_filter ${PROJECT_NAME}_gencfg ${catkin_EXPORTED_TARGETS})
# bias_calculator 无动态参数,无需添加此依赖
# 7. 第三步:链接库(所有目标都需要,顺序在创建和依赖之后)
target_link_libraries(madgwick_imu_filter ${catkin_LIBRARIES})
target_link_libraries(mahony_imu_filter ${catkin_LIBRARIES})
target_link_libraries(bias_calculator ${catkin_LIBRARIES})
| project(my_package) | 声明包名,必须和package.xml的<name>完全一致 |
| find_package() | 查找依赖的 ROS 包,比如roscpp(C++ 接口)、rospy(Python 接口) |
| catkin_package() | 声明本包的导出信息,供其他依赖本包的包使用 |
| add_executable() | 将.cpp源文件编译成可执行文件(ROS 节点) |
| target_link_libraries() | 链接依赖库(ROS 的核心库都在${catkin_LIBRARIES}里) |
注意:
| add_executable() | 将.cpp源文件编译成可执行文件(ROS 节点) |
常见扩展场景
- 编译多个节点
# 编译第一个节点
add_executable(node1 src/node1.cpp)
target_link_libraries(node1 ${catkin_LIBRARIES})
# 编译第二个节点
add_executable(node2 src/node2.cpp)
target_link_libraries(node2 ${catkin_LIBRARIES})自定义 msg/srv 文件:需要在find_package后添加:
add_message_files(FILES MyMsg.msg) # 自定义msg文件
add_service_files(FILES MySrv.srv) # 自定义srv文件
generate_messages(DEPENDENCIES std_msgs) # 生成msg/srv的代码在 ROS 工作空间(catkin_ws)根目录执行:
catkin_make # 编译所有包
# 或指定编译当前包
catkin_make –cmake-args -DCMAKE_BUILD_TYPE=Release –pkg my_package两个文件的关联
- package.xml 中声明的依赖(如roscpp),必须在CMakeLists.txt的find_package中对应包含,否则编译会找不到依赖。
- CMakeLists.txt的project名称必须和package.xml的<name>完全一致,否则 ROS 无法识别包。
- 新增依赖时,两个文件都要修改:先在package.xml加<build_depend>/<exec_depend>,再在CMakeLists.txt加find_package。

