核心概念:节点、话题、服务、动作、参数、节点图与DDS中间件

ROS2 的架构设计围绕“去中心化、语言无关、实时可靠”三大目标展开。要理解 ROS2,不能只记住几个名词,而必须看清这些概念之间的协作关系:节点是执行单元,话题/服务/动作是通信方式,参数是运行时配置,节点图是全局视角,而 DDS 则是这一切通信的底层“高速公路”。本节将逐一拆解这些核心概念,并指出初学者最容易混淆的边界。

一、核心原理:从“进程孤岛”到“分布式协作”

在传统机器人程序中,传感器采集、导航规划、电机控制往往写在一个大进程里,模块间通过函数调用耦合。ROS2 将每个功能模块封装为独立的节点(Node),节点之间通过标准接口通信,从而实现了模块的独立开发、独立重启和跨语言部署。

关键认知:ROS2 中“节点”是计算图的基本单元,一个可执行程序可以包含多个节点,但通常推荐“一个进程一个节点”以便故障隔离。节点通过 rclcpp::Node(C++)或 rclpy.Node(Python)创建。

节点之间不直接调用函数,而是通过四种通信原语协作,它们的适用场景截然不同:

  • 话题(Topic):连续数据流,一对多/多对多,异步通信。适合传感器数据、状态发布。
  • 服务(Service):请求-应答,一对一,同步通信。适合临时查询、触发一次性动作。
  • 动作(Action):带反馈的长时间任务,可取消。适合导航、机械臂运动等耗时操作。
  • 参数(Parameter):节点运行时的配置项,可动态读写。

所有通信数据都封装为接口(Interface),包括话题消息(.msg)、服务定义(.srv)和动作定义(.action)。接口是通信的“语法契约”,必须清晰定义字段类型和含义。

DDS 中间件(数据分发服务) 发现机制 · 可靠/尽力传输 · QoS策略 · 跨语言/跨平台 节点图(计算图) 传感器节点 /camera_node 处理节点 /image_proc 执行节点 /arm_controller /image_raw 话题(发布/订阅) /detected_pose 话题(发布/订阅) /get_status 服务(请求/应答) /move_to_target 动作(目标/反馈/结果) 参数服务器 /camera_node/exposure_time 读写参数 服务服务器 (在处理节点内) 动作服务器 (在执行节点内) ● 节点图 = 所有运行中节点 + 它们之间的通信关系 ● 使用 rqt_graph 可视化查看 ● 每个椭圆代表一个节点,箭头代表话题/服务/动作连接 所有通信经由 DDS 中间件传输

二、方法流程:从创建节点到通信建立

理解概念后,需要掌握实际开发中的标准流程。以 C++ 为例,创建一个发布话题的节点通常遵循以下步骤:

  1. 初始化 ROS2:调用 rclcpp::init() 启动通信层。
  2. 创建节点对象:auto node = std::make_shared<rclcpp::Node>("talker")。
  3. 创建发布者:node->create_publisher<std_msgs::msg::String>("chatter", 10),其中 10 是队列深度。
  4. 编写循环逻辑:在 while (rclcpp::ok()) 中发布消息。
  5. spin 节点:rclcpp::spin(node) 让回调函数得以处理。
// 发布者核心代码片段
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>

int main(int argc, char** argv) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<rclcpp::Node>("talker");
    auto pub = node->create_publisher<std_msgs::msg::String>("chatter", 10);
    rclcpp::WallRate rate(1);  // 1 Hz
    while (rclcpp::ok()) {
        auto msg = std_msgs::msg::String();
        msg.data = "Hello ROS2";
        pub->publish(msg);
        rclcpp::spin_some(node);
        rate.sleep();
    }
    rclcpp::shutdown();
    return 0;
}

调试技巧:使用 ros2 node list 查看当前所有节点,ros2 topic list 查看话题,ros2 topic echo /chatter 监听话题内容。这些命令是验证通信是否建立的第一手段。

三、案例/场景:导航机器人中的概念协作

以一个自主导航机器人为例,观察各概念如何协同工作:

功能模块 节点名称 通信方式 接口类型
激光雷达驱动 /lidar_driver 话题(发布) sensor_msgs/LaserScan
里程计 /odom_publisher 话题(发布) nav_msgs/Odometry
定位模块 /amcl 话题(订阅+发布) geometry_msgs/PoseWithCovarianceStamped
路径规划 /nav2_planner 服务(接收目标) geometry_msgs/PoseStamped
底盘控制 /controller 话题(订阅速度指令) geometry_msgs/Twist
导航任务调度 /nav2_bt 动作(发送目标/接收反馈) nav2_msgs/action/NavigateToPose

当用户下达“去厨房”指令时,动作客户端(如行为树节点)向 /nav2_bt 发送动作目标。导航节点通过话题持续接收激光数据和里程计,通过服务查询地图,计算路径后通过话题发布速度指令给底盘。整个过程,参数用于调整最大速度、加速度等配置,而所有通信都发生在 DDS 之上,即使某个节点崩溃,其他节点仍可继续运行。

四、误区/复盘:常见概念混淆与应对

高频误区 1:把“话题”和“服务”混为一谈。话题是“广播”,发布者不知道谁在订阅;服务是“打电话”,客户端必须等待服务器应答。如果传感器数据用服务传输,会导致严重的阻塞和延迟。

误区 2:忽略 QoS 策略。DDS 的 QoS(服务质量)是 ROS2 通信可靠性的核心。例如,传感器数据适合 BEST_EFFORT(尽力传输,丢帧可接受),而控制指令必须用 RELIABLE(可靠传输)。如果发布者和订阅者的 QoS 不兼容,通信将无法建立。

误区 3:认为“动作”就是“服务+话题”。动作确实内部使用话题和服务实现,但它提供了目标取消和连续反馈的语义,这是普通服务无法直接实现的。动作适合耗时任务,服务适合短查询。

误区 4:忽视节点图的可视化调试。很多初学者直接写代码,从不运行 rqt_graph。实际上,节点图能直观显示通信是否建立、数据流向是否正确,是排查“消息收不到”问题的第一工具。

复盘清单:当通信异常时,按以下顺序排查:

  1. 运行 ros2 node list 确认节点都在线。
  2. 运行 ros2 topic list 确认话题名称拼写一致。
  3. 运行 ros2 topic info /topic_name 查看发布者和订阅者数量。
  4. 检查 QoS 策略是否兼容(ros2 topic info -v)。
  5. 用 rqt_graph 查看实际连接关系。

最后需要强调的是,参数虽然看似简单,但它是节点配置的重要入口。ROS2 参数支持运行时动态更新,例如调整 PID 增益或相机曝光时间,无需重启节点。参数的类型包括整数、浮点、字符串、布尔、数组等,通过 ros2 param set 命令即可修改。