3. ROS2 核心概念详解

这一章我们聊聊 ROS2 里最基础的四个概念:节点、话题、服务、动作。说白了,你写任何机器人程序都绕不开它们。我刚开始接触 ROS2 的时候,觉得这些概念有点绕,但后来发现——理解它们就像学会用扳手和螺丝刀,后面就顺手了。

Node 节点 Topic 发布/订阅 Service 客户端/服务器 Action 客户端/服务器 ROS2 核心通信骨架:节点通过话题/服务/动作交互

3.1 节点(Node)—— 程序的“细胞”

节点就是 ROS2 里最小的执行单元。每个节点负责一件事,比如读取激光雷达、控制电机、处理定位。我个人习惯把节点想象成一个独立的小工人,各干各的,互相通过“通信管道”说话。

创建节点(Python 示例)

import rclpy
from rclpy.node import Node

class MyRobotNode(Node):
    def __init__(self):
        super().__init__('my_robot_node')
        self.get_logger().info('节点已启动!')

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

你想想看,一个机器人可能有几十个节点同时运行。我曾经在一个项目中同时跑了 30 多个节点,那时候才体会到节点拆分的好处——哪个崩了不影响其他,重启单个就行。

3.2 话题(Topic)—— 发布与订阅

话题是 ROS2 里最常用的通信方式。一个节点发布消息,其他节点订阅。就像电台广播,发布者不管谁在听,订阅者只管收。

避坑指南: 我曾经因为话题名打错一个字母,调试了半小时。后来我习惯把所有话题名写在常量文件里,用的时候导入,再也没犯过。

# 发布者
self.publisher_ = self.create_publisher(String, 'chatter', 10)
# 订阅者
self.subscription = self.create_subscription(String, 'chatter', self.callback, 10)

话题的 QoS(质量服务设置)也很关键。我记得有一次机器人走偏,就是因为订阅的传感器数据丢包了,调了 QoS 的可靠性才解决。

3.3 服务(Service)—— 一问一答

服务适合“请求-响应”模式,比如你让机械臂移动到某个位置,它告诉你“到位了”或者“出错”。服务分客户端和服务器,客户端发请求,服务器回响应。

角色行为典型场景
服务端 (Server)接收请求,返回响应控制机械臂、查询状态
客户端 (Client)发送请求,等待响应调用服务、获取结果
# 服务端示例
self.srv = self.create_service(SetBool, 'set_led', self.callback)

# 客户端示例
self.cli = self.create_client(SetBool, 'set_led')
while not self.cli.wait_for_service(timeout_sec=1.0):
    self.get_logger().info('等待服务...')
req = SetBool.Request()
req.data = True
future = self.cli.call_async(req)

嗯,这里要注意:服务调用是同步或异步的。我建议用异步,不然容易阻塞整个节点。

3.4 动作(Action)—— 长任务的好帮手

动作和服务有点像,但动作适合耗时长的任务,比如导航到某个点、执行一段轨迹。动作有反馈(feedback),你可以实时知道进度。

我曾经踩过的坑: 动作服务器忘记设置超时,结果客户端一直等,最后整个系统卡住。记得给动作加上超时和取消逻辑。

# 动作服务器(简化)
from action_tutorials_interfaces.action import Fibonacci

class FibonacciActionServer(Node):
    def __init__(self):
        super().__init__('fibonacci_server')
        self.action_server = ActionServer(
            self, Fibonacci, 'fibonacci', self.execute_callback)

    async def execute_callback(self, goal_handle):
        # 执行长任务,发送反馈
        feedback_msg = Fibonacci.Feedback()
        # ... 业务逻辑
        goal_handle.succeed()
        return Fibonacci.Result()

动作客户端可以取消任务、接收反馈。我个人觉得动作是 ROS2 里最优雅的设计,特别适合机器人这种需要“边做边汇报”的场景。

3.5 四个概念怎么选?

一句话总结:

  • 话题:持续的数据流,比如传感器数据、里程计。
  • 服务:短请求-响应,比如开关灯、设置参数。
  • 动作:长任务+反馈,比如导航、机械臂轨迹。
  • 节点:以上所有通信的载体。

你想想看,一个机器人系统就是把这些概念组合起来。我刚开始做项目时,总想把所有逻辑塞到一个节点里,后来拆成多个节点,用话题和服务通信,代码清晰多了。

核心要点回顾

  • 节点是基本单元,一个进程可以包含多个节点。
  • 话题用于广播式通信,一对多。
  • 服务用于同步请求-响应。
  • 动作支持异步、反馈、取消,适合长时间任务。