ROS2系列 (5) : 使用功能包组织C++节点
ROS2系列 (5) : 使用功能包组织C++节点
在ROS2中,C++是实现高性能节点的核心选择之一。本文将深入讲解如何创建、配置、构建和运行C++类型的ROS2功能包,解析其结构与构建逻辑,并对比C++与Python节点的运行差异,同时详解ROS2环境变量机制。
一、创建C++功能包
使用ros2 pkg create命令创建C++功能包,指定构建类型为ament_cmake:
ros2 pkg create demo_cpp_pkg --build-type ament_cmake --license Apache-2.0
--build-type ament_cmake:选择适用于C++的ament_cmake构建系统。--license Apache-2.0:指定许可证类型。
执行后生成的目录结构如下(结合示例图片):
demo_cpp_pkg/
├── include/demo_cpp_pkg/ # 存放C++头文件的目录
├── src/ # 存放C++源文件的目录
│ └── cpp_node.cpp # 待编写的C++节点源文件
├── CMakeLists.txt # CMake构建配置核心文件
├── LICENSE # 许可证文件
└── package.xml # 功能包元信息配置文件
二、C++功能包结构解析
| 文件/目录 | 作用说明 |
|---|---|
include/demo_cpp_pkg/ | 存放C++头文件,用于模块间的接口声明与类定义。 |
src/ | 存放C++源文件,包含节点的业务逻辑实现。 |
CMakeLists.txt | 定义编译规则、依赖查找、可执行文件生成等构建逻辑,是C++功能包的核心配置文件。 |
package.xml | 声明功能包的名称、版本、维护者、依赖等元信息。 |
LICENSE | 定义代码的使用、修改和分发权限(本文示例为Apache-2.0)。 |
三、编写C++节点代码
在src/目录下创建cpp_node.cpp,编写基础C++节点逻辑:
#include "rclcpp/rclcpp.hpp"int main(int argc, char **argv)
{rclcpp::init(argc, argv); // 初始化rclcpp客户端库auto node = std::make_shared<rclcpp::Node>("cpp_node"); // 创建名为“cpp_node”的节点RCLCPP_INFO(node->get_logger(), "你好 C++ 节点!"); // 输出INFO级日志rclcpp::spin(node); // 保持节点运行(直到手动终止)rclcpp::shutdown(); // 关闭rclcpp,释放资源return 0;
}
四、配置package.xml添加依赖
打开package.xml,添加C++客户端库rclcpp的依赖声明:
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><!-- 其他元信息(名称、版本、维护者等) --><license>Apache-2.0</license><depend>rclcpp</depend> <!-- 声明运行时依赖:ROS2 C++客户端库rclcpp --><test_depend>ament_copyright</test_depend> <!-- 测试阶段依赖(版权检查) --><test_depend>ament_clang_format</test_depend> <!-- 测试阶段依赖(代码格式检查) --><!-- 其他配置 -->
</package>
五、配置CMakeLists.txt(重点:ament_cmake与ament_target_dependencies)
打开CMakeLists.txt,配置编译规则与依赖:
cmake_minimum_required(VERSION 3.8)
project(demo_cpp_pkg)# 查找ament_cmake构建工具和rclcpp包
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)# 编译src/cpp_node.cpp为可执行文件cpp_node
add_executable(cpp_node src/cpp_node.cpp)# 为可执行文件添加依赖(ROS2推荐方式,替代传统target_link_libraries)
ament_target_dependencies(cpp_node rclcpp)# 将可执行文件安装到lib/${PROJECT_NAME}目录,使ros2 run能找到它
install(TARGETScpp_nodeDESTINATION lib/${PROJECT_NAME}
)ament_package() # 标记为ament包,完成构建配置
ament_target_dependencies(节点名 依赖名):是ROS2中C++功能包的核心配置指令,它会自动处理rclcpp的头文件路径和库链接,即使混合使用传统CMake指令,此方式也能适配ROS2环境。install(...):将可执行文件安装到lib/${PROJECT_NAME}目录,确保ros2 run能定位到节点。
六、构建功能包:colcon build vs 传统CMake
6.1 推荐:使用colcon build构建
在工作空间根目录执行:
colcon build
成功后终端输出类似:
Starting >>> demo_cpp_pkg
Starting >>> demo_python_pkg
Finished <<< demo_cpp_pkg [0.41s]
Finished <<< demo_python_pkg [0.73s]
Summary: 2 packages finished [0.85s]
优势:colcon自动管理多包构建顺序和环境变量,是ROS2工作空间的标准构建方式。
6.2 传统CMake构建(了解即可)
若手动创建build目录并执行CMake:
mkdir build && cd build
cmake ..
make
这种方式虽能编译出可执行文件,但需手动配置环境变量才能被ROS2工具链识别,在ROS2生态中不推荐单独使用。
七、环境变量与运行节点
7.1 直接运行安装后的可执行文件
构建完成后,可执行文件位于install/demo_cpp_pkg/lib/demo_cpp_pkg目录。通过ldd命令可查看其依赖的库是否正常链接:
ldd install/demo_cpp_pkg/lib/demo_cpp_pkg/cpp_node
若依赖(如librclcpp.so)均正常链接,可直接运行:
install/demo_cpp_pkg/lib/demo_cpp_pkg/cpp_node
终端输出节点日志:
[INFO] [1680684100.228612032] [cpp_node]: 你好 C++ 节点!
7.2 环境变量AMENT_PREFIX_PATH与ros2 run
执行source命令配置环境变量:
source install/setup.bash
该命令会修改AMENT_PREFIX_PATH环境变量,将功能包的安装路径加入ROS2的包查找路径。可通过以下命令查看:
echo $AMENT_PREFIX_PATH
输出类似:
/home/xxx/install/demo_cpp_pkg:/opt/ros/humble
此时可通过ros2 run运行节点:
ros2 run demo_cpp_pkg cpp_node
也可通过ros2 pkg prefix命令查看功能包的安装前缀目录:
ros2 pkg prefix demo_cpp_pkg
输出为功能包的安装根目录(如/home/xxx/install/demo_cpp_pkg)。
八、C++与Python节点运行差异解析
C++节点的可执行文件可直接运行,而Python节点通常需要额外配置环境,核心原因是:
| 特性 | C++节点(编译型) | Python节点(解释型) |
|---|---|---|
| 依赖处理 | 编译时将依赖库链接到可执行文件中(可通过ldd验证) | 运行时需通过PYTHONPATH查找依赖模块 |
| 运行前提 | 只需可执行文件本身(依赖库已链接) | 需配置PYTHONPATH或source环境脚本,让解释器找到模块 |
九、总结
本文详细讲解了ROS2中C++功能包的创建、结构、配置、构建与运行流程,重点解析了ament_cmake构建系统的ament_target_dependencies指令、环境变量AMENT_PREFIX_PATH的作用,以及C++与Python节点的运行差异。掌握这些内容后,你可以高效开发高性能C++ ROS2节点,并深入理解其底层构建逻辑。
