在上一篇博客中,我们掌握了 ROS2 环境配置、命令行启动程序、CMake 编译工具的使用,解决了如何运行ROS2程序的问题。而今天我们深入底层核心,讲解 ROS2 最基础、最重要的核心单元——节点(Node)。
所有 ROS2 机器人功能,无论是建图、导航、视觉识别、电机控制,本质上都是由一个个独立的节点协同完成。可以说:学会写节点,才算真正入门 ROS2 开发。
本文将从零讲解节点核心概念,搭配可直接复制运行的 C++ 源码,手把手教你完成「编写节点→配置编译规则→编译程序→运行调试」完整闭环,适配 Humble/Iron/Jazzy 全版本。
一、什么是 ROS2 节点?(通俗理解)
1. 节点的定义
在 ROS2 中,节点(Node)是执行单一特定功能的最小可执行单元,是编译后可以独立运行的程序。
我们可以把机器人系统类比成一个团队,每个节点就是一个独立的工作人员:
雷达节点:专门负责采集环境雷达数据
相机节点:专门负责采集图像画面
导航节点:专门负责路径规划、点位导航
电机控制节点:专门负责控制机器人运动
每个节点各司其职、独立运行,通过话题、服务等方式互相通信,最终实现机器人的完整功能。
2. 节点的核心优势
模块化解耦:单个节点故障不会导致整个系统崩溃,稳定性更强
可复用性高:写好的节点可直接复用在不同机器人项目中
调试简单:可单独启动、单独调试某个功能模块
3. 节点、功能包、可执行文件的关系
很多新手容易混淆三者关系,这里做清晰梳理:
功能包(Package):存放源码、配置文件的文件夹,是项目管理单元
节点源码:我们编写的 .cpp 代码,是节点的原始程序
节点(可执行文件):源码经过 CMake 编译后生成的可运行程序,也就是我们用ros2 run启动的程序
二、自定义节点开发前置准备
默认你已经配置好 ROS2 环境、创建好了工作空间ros2_ws,我们先创建一个全新的自定义功能包,用于存放我们的第一个节点。
1. 创建自定义功能包
进入工作空间 src 目录,创建依赖 rclcpp(ROS2 C++ 核心库)的功能包:
cd ~/ros2_ws/src ros2 pkg create my_first_node --build-dependencies rclcpp命令释义:创建名为my_first_node的功能包,默认依赖 C++ 节点核心库 rclcpp。
2. 创建源码文件夹
进入功能包,新建 src 文件夹(规范存放源码文件):
cd ~/ros2_ws/src/my_first_node mkdir src三、手把手编写第一个 ROS2 C++ 节点
我们编写一个最简单的日志输出节点,实现节点启动后循环打印日志,验证节点正常运行。在src目录下新建文件hello_node.cpp,写入以下完整源码。
1. 完整节点源码(可直接复制)
// 引入ROS2 C++核心头文件 #include "rclcpp/rclcpp.hpp" // 主函数,程序入口 int main(int argc, char ** argv) { // 1. 初始化ROS2节点环境 rclcpp::init(argc, argv); // 2. 创建一个节点,命名为 hello_world_node auto node = std::make_shared<rclcpp::Node>("hello_world_node"); // 3. 循环输出日志(每秒打印一次) rclcpp::Rate loop_rate(1.0); // 设置频率1Hz while (rclcpp::ok()) // 节点正常运行时循环 { // 打印INFO级别日志 RCLCPP_INFO(node->get_logger(), "成功运行第一个ROS2节点!Hello ROS2!"); loop_rate.sleep(); // 休眠,控制循环频率 } // 4. 关闭节点环境 rclcpp::shutdown(); return 0; }2. 代码逐行核心解析(新手必看)
#include "rclcpp/rclcpp.hpp":引入 ROS2 C++ 节点核心库,所有 C++ 节点必须包含该头文件rclcpp::init(argc, argv):初始化 ROS2 通信环境,是节点运行的第一步std::make_shared<rclcpp::Node>("hello_world_node"):创建节点实例,hello_world_node 是节点名称,全局唯一rclcpp::Rate loop_rate(1.0):设置循环运行频率,1.0代表1秒执行一次rclcpp::ok():判断节点是否处于正常运行状态,按下 Ctrl+C 后终止循环RCLCPP_INFO:ROS2 标准日志打印函数,替代普通 printf,可输出日志级别、时间戳rclcpp::shutdown():关闭节点,释放资源,程序结束
四、配置 CMakeLists.txt 编译规则(关键步骤)
写完源码后,必须配置编译规则,告诉 CMake 如何编译源码、生成可执行文件、安装运行文件。打开功能包根目录的CMakeLists.txt,替换为以下完整配置(衔接上一篇博客的CMake知识点)。
cmake_minimum_required(VERSION 3.8) project(my_first_node) # 查找依赖包 find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) # 编译可执行节点:源码文件 + 生成的节点名 add_executable(hello_node src/hello_node.cpp) # 绑定节点依赖 ament_target_dependencies(hello_node rclcpp) # 安装节点,让ros2 run可以识别 install(TARGETS hello_node DESTINATION lib/${PROJECT_NAME} ) ament_package()核心重点:add_executable定义了最终的可执行文件名hello_node,后续启动节点需要使用该名称。
五、编译+运行节点完整流程
1. 编译功能包
返回工作空间根目录,执行编译命令:
cd ~/ros2_ws colcon build --packages-select my_first_node2. 加载环境变量
编译完成后必须加载环境,否则无法识别新节点:
source install/setup.bash3. 启动自定义节点
使用上一篇博客的ros2 run命令启动单个节点:
ros2 run my_first_node hello_node4. 运行效果
终端会每秒循环打印日志,代表节点运行成功:
[INFO] 成功运行第一个ROS2节点!Hello ROS2!
按下Ctrl+C即可关闭节点。
六、验证节点状态(调试实操)
保持节点运行,新开终端加载环境,通过调试命令验证节点状态:
# 查看所有运行节点 ros2 node list # 查看节点详细信息 ros2 node info /hello_world_node可以看到我们创建的hello_world_node节点,证明节点注册、运行完全正常。
七、新手开发常见报错避坑
编译成功但无法启动节点:CMakeLists 未配置 install 安装规则,节点未部署到运行目录,重新配置并清理缓存编译
提示节点不存在:编译后未执行 source 环境变量,或可执行文件名输入错误
代码报错:rclcpp未定义:package.xml 和 CMakeLists 中未添加 rclcpp 依赖
节点启动瞬间闪退:代码缺少循环逻辑,节点执行完毕后自动退出,需添加 while 循环常驻运行
八、总结与进阶方向
通过本文,我们彻底理解了 ROS2 节点的核心概念,同时完成了从0编写、配置、编译到运行的完整节点开发流程。这是所有 ROS2 进阶开发的基础,后续的话题通信、服务通信、参数配置、传感器开发,都是在节点的基础上延伸拓展。
简单复盘核心要点:
节点是ROS2最小可执行功能单元,模块化分工运行
C++节点开发核心四步:建包→写源码→配CMake→编译运行
必须初始化、注册节点、循环常驻、最后关闭节点
下一篇我们可以基于该节点,讲解ROS2话题通信,实现节点之间的数据收发,真正实现多节点协同工作。