2. ROS2核心概念

ROS2的通信架构建立在六个核心概念之上:节点(Node)、话题(Topic)、服务(Service)、动作(Action)、参数(Parameter)与图命名空间(Graph Namespace)。理解这六者的关系,是掌握ROS2系统架构的基石。它们共同构成了一个去中心化的“计算图”(Computation Graph),图中的每一个节点都是独立运行的可执行单元,彼此通过不同的通信模式协作。

核心原理:六要素的分工与协作

ROS2采用去中心化的节点通信模型,没有中心服务器。节点之间通过DDS(数据分发服务)中间件直接通信。为了适应不同场景,ROS2提供了四种通信原语:

  • 话题(Topic):用于连续、单向、多对多的数据流传输。发布者(Publisher)发送数据,订阅者(Subscriber)接收数据,双方互不感知对方存在。典型场景:传感器数据、里程计、图像流。
  • 服务(Service):用于一次性、双向、同步的请求-响应交互。客户端(Client)发送请求并阻塞等待服务器(Server)应答。典型场景:开关某个传感器、查询机器人状态。
  • 动作(Action):用于长时间、可取消、带反馈的任务执行。客户端发送目标(Goal),服务器执行过程中持续发送反馈(Feedback),最终返回结果(Result)。典型场景:导航到目标点、机械臂抓取。
  • 参数(Parameter):节点运行时可动态读取或修改的配置项,本质是键值对。典型场景:PID增益、最大速度限制。

下图展示了这四种通信模式在机器人系统中的典型连接关系:

图命名空间 /robot1(Graph Namespace) /camera_node 发布图像话题 /lidar_node 发布点云话题 /navigation_node 订阅传感器数据 提供导航动作服务 /arm_controller 执行抓取动作 提供关节状态服务 /monitor_node 订阅状态话题 /image_raw /scan /arm_control (Action) /get_status (Service) /camera_param /robot_status 话题(连续单向) 服务(请求-响应) 动作(目标-反馈-结果) 参数(动态配置)

方法流程:创建与运行一个最小通信系统

以Python为例,创建一个发布-订阅系统需要以下步骤。首先,在功能包中定义节点文件:

# talker.py(发布者节点)
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Talker(Node):
    def __init__(self):
        super().__init__('talker')
        self.pub = self.create_publisher(String, 'chatter', 10)
        self.timer = self.create_timer(1.0, self.timer_callback)

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello ROS2'
        self.pub.publish(msg)
        self.get_logger().info(f'发布: {msg.data}')

def main(args=None):
    rclpy.init(args=args)
    node = Talker()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

运行两个节点后,可以使用ros2 node list查看节点,用ros2 topic echo /chatter验证数据流。核心流程为:初始化 → 创建节点 → 创建发布者/订阅者 → 回调处理 → 销毁节点。

案例场景:多传感器融合的导航系统

假设一个移动机器人需要同时处理激光雷达、摄像头和惯性测量单元(IMU)数据。架构设计如下:

节点名称通信模式话题/服务名数据类型方向
/camera_node话题/image_rawsensor_msgs/Image发布
/lidar_node话题/scansensor_msgs/LaserScan发布
/imu_node话题/imu/datasensor_msgs/Imu发布
/fusion_node话题/fusion/posegeometry_msgs/PoseStamped订阅+发布
/nav_node动作/nav/goalnav2_msgs/NavigateToPose动作服务器
/map_server服务/map/loadnav_msgs/GetMap服务服务器

该系统中,话题负责高频传感器数据的实时流转,动作负责导航这类长时任务,服务用于按需加载地图。每个节点通过参数调整自身行为,例如/fusion_node的参数filter_type可切换卡尔曼滤波或粒子滤波算法。

误区与复盘:命名空间与通信模式的选择

常见误区一:混淆话题与服务的使用场景。初学者常试图用服务传输高频传感器数据,导致请求-响应阻塞,系统吞吐量急剧下降。服务适合低频、需要确认的交互,而话题适合高频、允许丢失部分数据的场景。

复盘建议:当需要“持续不断的数据流”时,优先选择话题;当需要“一问一答的指令”时,选择服务;当任务耗时超过数秒且需要中途取消时,必须使用动作。

常见误区二:忽略图命名空间的作用。在多机器人系统中,如果不使用命名空间,两个机器人的同名节点(如/camera_node)会发生冲突。正确做法是为每个机器人分配独立命名空间:

# 启动机器人1时
ros2 run my_pkg camera_node --ros-args -r __ns:=/robot1
# 启动机器人2时
ros2 run my_pkg camera_node --ros-args -r __ns:=/robot2

此时,两个节点分别对应/robot1/camera_node和/robot2/camera_node,它们的话题也自动隔离为/robot1/image_raw与/robot2/image_raw。命名空间不仅避免冲突,还便于使用ros2 bag按机器人分别录制数据,以及通过--remap规则灵活重映射通信端点。

复盘总结:在设计ROS2系统时,应首先画出计算图草图,明确每个节点的输入输出是“流”还是“请求”,再决定通信原语。参数应集中管理,避免硬编码。命名空间从第一天就应规划,而不是等到多机联调时再补救。这六个概念相互配合,构成了ROS2灵活、可扩展的架构基础。