学习范围:《ROS 2 机器人开发:从入门到实践》第 2 章 2.1.2 C++ 示例
当前目标:用 C++ 写一个最小 ROS 2 节点,对比 Python 节点的结构。

本节要掌握什么

学完这一小节,要能做到:

  • 能写出一个最小 C++ 节点。
  • 能用 colcon build 编译 C++ 功能包。
  • 能运行 C++ 节点,并用 ros2 node list 查看。
  • 能理解 C++ 节点和 Python 节点在结构上的共同点。
为什么还要学 C++ 节点

ROS 2 同时支持 Python 和 C++。实际项目中:

  • 快速原型、测试脚本、高层逻辑常用 Python。
  • 对性能要求高的底层模块(传感器驱动、导航算法、实时控制)常用 C++。

两种语言的 ROS 2 节点生命周期是一样的:初始化 → 创建节点 → 运行 → 关闭。区别只在语法和构建方式。

用 STM32 的经验理解 C++ 节点

以前用 STM32 写 C 代码,对 C++ 的语法不会陌生。做一个类比:

STM32 / C 开发 ROS 2 C++ 开发
main() 函数入口 main() 函数入口
HAL 初始化 rclcpp::init()
while(1) 主循环 rclcpp::spin()
printf 调试 RCLCPP_INFO 日志
Makefile / Keil 工程 CMakeLists.txt + colcon
头文件 #include 头文件 #include "rclcpp/rclcpp.hpp"

STM32 的 while(1) 让程序不停运行;ROS 2 的 rclcpp::spin() 让节点持续等待回调和事件。思路一样,只是粒度不同。

C++ 节点和 Python 节点的对比
对比项 Python 节点 C++ 节点
初始化 rclpy.init() rclcpp::init()
创建节点 Node("name") std::make_shared<rclcpp::Node>("name")
日志输出 node.get_logger().info() RCLCPP_INFO(node->get_logger(), ...)
保持运行 rclpy.spin(node) rclcpp::spin(node)
关闭 rclpy.shutdown() rclcpp::shutdown()
构建方式 直接 python3 xxx.py colcon build → 运行可执行文件
依赖管理 package.xml(ament_python) package.xml + CMakeLists.txt(ament_cmake)

核心生命周期完全一致,只是语言表达不同。

创建 C++ 功能包

ROS 2 的 C++ 代码不能像 Python 那样直接运行一个 .py 文件,需要先创建功能包并编译。

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake cpp_node_pkg --dependencies rclcpp

这条命令会生成一个功能包目录,包含:

  • CMakeLists.txt:CMake 构建配置。
  • package.xml:功能包元数据和依赖声明。
  • src/:源码目录。
  • include/:头文件目录。

--dependencies rclcpp 会自动在 package.xmlCMakeLists.txt 中添加对 rclcpp 的依赖。

编写 C++ 节点代码

在功能包的 src/ 目录下创建 cpp_node.cpp

cd ~/ros2_ws/src/cpp_node_pkg/src
code cpp_node.cpp

写入代码:

#include "rclcpp/rclcpp.hpp"

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    auto node = std::make_shared<rclcpp::Node>("cpp_node");
    RCLCPP_INFO(node->get_logger(), "你好,ROS 2 C++ 节点!");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

配置 CMakeLists.txt

打开 CMakeLists.txt,找到自动生成的可执行文件部分,添加:

add_executable(cpp_node src/cpp_node.cpp)
ament_target_dependencies(cpp_node rclcpp)
install(TARGETS
    cpp_node
    DESTINATION lib/${PROJECT_NAME})

说明:

  • add_executable:告诉 CMake 要编译哪个源文件生成哪个可执行文件。
  • ament_target_dependencies:链接 ROS 2 依赖库。
  • install:把编译好的可执行文件安装到正确位置,这样 ros2 run 才能找到它。
编译

回到工作空间根目录,使用 colcon 编译:

cd ~/ros2_ws
colcon build

编译成功后会看到类似输出:

Starting >>> cpp_node_pkg
Finished <<< cpp_node_pkg [X.XXs]

编译产物在 install/ 目录下。如果只想编译这一个包:

colcon build --packages-select cpp_node_pkg

运行节点

先加载安装目录的环境:

source install/setup.bash

然后运行:

ros2 run cpp_node_pkg cpp_node

说明:

  • cpp_node_pkg:功能包名。
  • cpp_node:CMakeLists.txt 中 add_executable 定义的可执行文件名。

正常输出:

[INFO] [时间戳] [cpp_node]: 你好,ROS 2 C++ 节点!

验证节点

保持第一个终端运行,新开终端:

source ~/ros2_ws/install/setup.bash
ros2 node list

应该看到 /cpp_node。查看节点信息:

ros2 node info /cpp_node

Ctrl+C 结束节点。

常见问题

问题 1:colcon build 报错找不到 rclcpp
确认已安装 ROS 2 C++ 库:

sudo apt install ros-humble-rclcpp

(把 humble 换成你的 ROS 2 版本。)

问题 2:ros2 run 找不到可执行文件
检查两点:

  1. 是否执行了 source install/setup.bash
  2. CMakeLists.txt 中的 install(TARGETS ...) 是否正确配置。

问题 3:编译成功但运行时找不到节点名
检查 add_executableros2 run 用的可执行文件名是否一致。

本节小结

本节完成了第一个 ROS 2 C++ 节点。和 Python 节点对比后可以看到:

初始化 ROS 2 -> 创建节点 -> 让节点运行 -> 关闭 ROS 2

这个生命周期是 ROS 2 所有程序的基础,不管用 Python 还是 C++ 都一样。C++ 多了编译这一步,但也带来了更好的性能和类型安全。后续学习话题、服务等内容时,两种语言的结构都是相通的。

课后练习
  1. 把节点名改成 my_cpp_node,重新编译运行,用 ros2 node list 验证。
  2. 在节点中多加几行 RCLCPP_INFO,输出不同的日志信息。
  3. 试试 RCLCPP_WARNRCLCPP_ERROR,观察日志级别有什么不同。
  4. 对比 Python 和 C++ 节点代码,用自己的话说说两者结构上的共同点。

下一节建议继续学习:2.2 Python 功能包组织。目标是学会用标准的 ROS 2 功能包结构来组织 Python 代码。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐