3. ROS2 核心概念:Node、Topic、Service、Action、Parameter
好,咱们进入正题。ROS2 的五个核心概念——Node、Topic、Service、Action、Parameter——说白了就是机器人系统里最基础的通信和配置手段。你想想看,一个机器人要动起来,传感器要发数据,电机要收指令,这些部件之间怎么说话?就是靠这五样东西。
我刚开始接触 ROS 的时候,觉得概念太多,容易混。后来带项目多了,发现其实就一句话:Node 是执行单元,Topic 是广播通道,Service 是同步请求,Action 是异步任务,Parameter 是静态配置。下面我一个一个拆开讲。
核心一句话:ROS2 的通信模型,本质上就是「谁(Node)通过什么方式(Topic/Service/Action)传递什么数据(Message)」。Parameter 是例外,它不负责通信,只负责配置。
3.1 Node(节点)—— 一切功能的执行单元
Node 是 ROS2 系统里最小的独立功能单元。每个 Node 负责一件事,比如读取激光雷达、控制电机、处理图像。我习惯把 Node 比作「工人」——每个工人只干自己的活,大家通过通信机制协作。
创建 Node 很简单,Python 里继承 rclpy.node.Node 就行:
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()
个人经验:我建议每个 Node 只做一件事。比如「底盘控制」和「激光雷达处理」拆成两个 Node,而不是揉在一起。这样调试时,哪个 Node 崩了,系统其他部分还能跑。我在项目里见过一个 Node 写了两千行,最后谁都不敢动——千万别这么干。
3.2 Topic(话题)—— 一对多的广播通道
Topic 是 ROS2 里最常用的通信方式。发布者(Publisher)往 Topic 里发数据,订阅者(Subscriber)接收数据。一个 Topic 可以有多个发布者和多个订阅者,典型的「广播模式」。
举个例子,激光雷达节点发布 /scan 话题,导航节点订阅它。中间谁发谁收,互不关心。
# 发布者
self.publisher_ = self.create_publisher(String, 'chatter', 10)
# 订阅者
self.subscription = self.create_subscription(
String, 'chatter', self.listener_callback, 10)
避坑指南:我曾经在项目里把 Topic 的 QoS 设置错了,导致订阅者收不到数据。ROS2 的 QoS 策略(Reliability、Durability 等)必须匹配,否则通信会静默失败。默认的 qos_profile_default 够用,但如果你用 SensorDataQoS,记得两边保持一致。
3.3 Service(服务)—— 同步的请求-响应
Topic 是单向广播,Service 是双向同步。客户端发请求,服务端处理完返回响应。适合「问一句,答一句」的场景,比如「给我当前坐标」或「切换导航模式」。
Service 的定义用 .srv 文件,包含请求和响应两部分:
# AddTwoInts.srv
int64 a
int64 b
---
int64 sum
服务端实现:
def add_two_ints_callback(self, request, response):
response.sum = request.a + request.b
return response
self.srv = self.create_service(AddTwoInts, 'add_two_ints', add_two_ints_callback)
注意:Service 是同步阻塞的。如果服务端处理时间太长,客户端会一直等。我建议 Service 只用于耗时小于 100ms 的操作。超过这个时间,请用 Action。
3.4 Action(动作)—— 异步的长任务
Action 是 ROS2 里处理「长时间任务」的方案。比如让机器人走到某个点,这个过程可能持续几秒甚至几分钟。Action 有三个阶段:
- Goal:客户端发送目标
- Feedback:服务端持续反馈进度
- Result:任务完成,返回最终结果
Action 的定义用 .action 文件:
# NavigateToPose.action
# Goal
geometry_msgs/PoseStamped target_pose
---
# Result
bool success
string message
---
# Feedback
float32 progress_percentage
我记得第一次用 Action 时,觉得它比 Service 复杂。但后来做导航项目,发现没有 Feedback 根本没法调试——你总得知道机器人走到哪了吧?
我的习惯:只要任务可能超过 1 秒,我就用 Action。哪怕只是「打开机械爪」这种简单动作,用 Action 也能在卡住时通过 cancel 机制中断。Service 一旦卡住,整个节点就挂了。
3.5 Parameter(参数)—— 运行时的配置开关
Parameter 不是通信机制,而是配置机制。每个 Node 可以有一组参数,比如 PID 系数、传感器频率、机器人名字。参数可以在启动时设置,也可以在运行时动态修改。
# 声明参数
self.declare_parameter('robot_name', 'turtlebot')
self.declare_parameter('max_speed', 0.5)
# 获取参数
robot_name = self.get_parameter('robot_name').value
max_speed = self.get_parameter('max_speed').value
启动时传参:
ros2 run my_package my_node --ros-args -p robot_name:=my_robot -p max_speed:=1.0
避坑指南:我曾经在参数里写了一个字符串,结果因为编码问题导致节点崩溃。ROS2 的参数类型是强类型的,int、double、string、bool、array 都支持,但别混用。另外,动态修改参数时记得加回调函数,否则改了等于没改。
3.6 五个概念的对比
最后,我用一张表帮你理清这五个概念的区别。这张表我每次培训都会用,你直接拿去用就行。
| 概念 | 通信模式 | 是否同步 | 典型场景 | 数据流向 |
|---|---|---|---|---|
| Node | 无(执行单元) | — | 功能模块 | — |
| Topic | 发布/订阅 | 异步 | 传感器数据、状态广播 | 单向 |
| Service | 请求/响应 | 同步 | 查询状态、触发短操作 | 双向 |
| Action | 目标/反馈/结果 | 异步 | 导航、机械臂运动 | 双向+进度 |
| Parameter | 配置读写 | 同步 | 参数调优、系统配置 | 节点内部 |
嗯,到这里五个核心概念就讲完了。你想想看,其实 ROS2 的通信模型并不复杂——Topic 用来发高频数据,Service 用来做短查询,Action 用来跑长任务,Parameter 用来调配置。Node 就是装这些东西的容器。