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 节点,代码第一行是:
cpp#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中,你写:cpp# 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
<?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 目录下执行:
bash
catkin_lint . # 检查package.xml语法是否正确
rospkg info my_package # 查看包的元信息(验证是否识别)
以下是一段package.xml,读者可以自行解读,
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 特有语法。
XML
# 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 ,读者可以自行解读,
XML
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 节点) |
常见扩展场景
-
编译多个节点
XML# 编译第一个节点 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后添加:XMLadd_message_files(FILES MyMsg.msg) # 自定义msg文件 add_service_files(FILES MySrv.srv) # 自定义srv文件 generate_messages(DEPENDENCIES std_msgs) # 生成msg/srv的代码在 ROS 工作空间(catkin_ws)根目录执行:
bashcatkin_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。
总结
package.xml是元信息文件,核心作用是声明包名、版本、依赖,让 ROS 识别包的基本信息。CMakeLists.txt是编译规则文件,核心作用是指定编译源文件、链接依赖库、生成可执行文件(ROS 节点)。- 两个文件是 ROS 功能包的 "标配",且依赖声明、包名必须保持一致,否则会导致编译 / 运行错误。