ROS 2 Topic、Service、Action到底有什么区别?一文搞懂机器人三种通信机制
在上一篇《ROS 2 Node节点详解:一个Node从启动到执行,到底发生了什么?》中,我们沿着 Node → Process → Thread → Callback → Executor → Linux Scheduler → CPU 这条链路,对 ROS 2 的运行机制进行了分析。
如果说 Node 解决的是“机器人软件应该如何拆分”的问题,那么接下来就必须解决另一个更加基础的问题:
拆开的这些 Node 之间,到底如何通信?
一台真正的机器人很少只有一个程序。
一个人形机器人可能同时运行视觉感知、语音交互、环境感知、定位、运动规划、关节控制、状态监控等大量模块;一台工业机器人则可能同时存在机器人控制器、伺服驱动、传感器、运动规划、故障诊断等软件模块。
这些模块必须持续交换数据。
例如:
摄像头
↓
视觉Node
↓
目标识别
↓
规划Node
↓
控制Node
↓
执行器
如果所有模块都直接调用彼此的函数,那么系统会快速形成复杂的依赖关系:
A → B
A → C
A → D
B → C
B → D
C → D
当机器人软件规模继续扩大以后,修改一个模块可能影响多个模块,甚至整个系统。
ROS 2的重要价值之一,就是通过统一的通信机制,让不同 Node 之间能够以相对松耦合的方式进行数据交换。
而 ROS 2 最核心的三种通信方式,就是:
Topic、Service、Action。
很多初学者会简单记忆:
Topic用于发布订阅,Service用于请求响应,Action用于长时间任务。
这当然没错。
但如果真正进入机器人开发,就会发现三个问题:
为什么激光雷达应该使用Topic?
为什么某些控制操作更适合Service?
为什么导航任务需要Action,而不是普通Service?
更进一步:
Topic传输的数据到底经过什么机制?
QoS为什么会影响机器人通信?
Reliable和Best Effort到底应该怎么选择?
通信数据及时到达之后,为什么仍然不代表机器人能够及时处理?
这些问题会把我们从 ROS 2 应用层一路带到 DDS,再进一步连接到操作系统实时性。
因此,这一篇我们不只讲“怎么用”,而是从机器人系统设计的角度,真正理解 Topic、Service、Action 之间的区别,以及它们为什么最终会与实时操作系统产生联系。
一、Topic:机器人为什么需要一个持续的数据流?
理解ROS 2通信机制,最容易从Topic开始。
Topic采用的是经典的:
Publish / Subscribe,也就是发布/订阅模型。
假设机器人上有一个激光雷达。
激光雷达不断产生扫描数据。
那么可以设计:
/scan
│
↓
┌───────────────┐
│ Lidar Node │
└───────────────┘
│
Publish
│
↓
ROS 2 Topic
│
┌──────┼───────┐
↓ ↓ ↓
定位Node 建图Node 障碍物Node
激光雷达Node只负责:
“我产生数据。”
至于谁使用数据,它并不需要知道。
定位Node可以订阅。
建图Node可以订阅。
障碍物检测Node也可以订阅。
甚至未来增加一个新的AI感知Node,也可以直接订阅。
这就是Topic最大的价值:
数据生产者与数据消费者解耦。
Topic为什么特别适合传感器?
因为机器人传感器有一个非常明显的特点:
持续产生数据。
例如:
摄像头:
30 FPS
激光雷达:
持续扫描
IMU:
100Hz / 200Hz / 1kHz
关节状态:
持续更新
这些数据天然适合形成一个数据流。
例如:
时间
│
├── t0 → IMU数据
├── t1 → IMU数据
├── t2 → IMU数据
├── t3 → IMU数据
├── t4 → IMU数据
└── t5 → IMU数据
消费者不需要每次主动询问:
“有没有新数据?”
而是:
“有新数据的时候通知我。”
这就是发布/订阅模型。
Topic带来的第一个优势:解耦
假设一个机器人有:
Lidar Node
Localization Node
Mapping Node
Navigation Node
传统方式可能需要:
Lidar → Localization
Lidar → Mapping
Lidar → Navigation
而Topic模式下:
/scan
│
┌───────┼────────┐
↓ ↓ ↓
Localization Mapping Navigation
激光雷达只需要发布一次。
其他Node根据需要订阅。
这使得机器人系统可以不断扩展。
Topic的问题:数据一定要“可靠”吗?
这里开始进入ROS 2一个非常重要的概念:
QoS。
假设激光雷达每秒发送大量数据。
如果网络偶尔丢失一帧:
Frame 100
Frame 101
Frame 102
↓
Frame 103 丢失
↓
Frame 104
对于很多实时传感器数据来说,系统可能并不需要为了Frame 103而停下来等待。
因为机器人马上还会收到:
Frame 104
Frame 105
Frame 106
这种情况下:
最新的数据可能比历史数据更加重要。
这就是为什么机器人通信不能简单地理解成:
“数据一定要一条不漏。”
真正需要考虑的是:
这个数据的业务语义是什么?
对于某些传感器:
实时性 > 完整性
而对于另外一些数据:
完整性 > 延迟
这就是QoS存在的重要原因。
二、Service:为什么机器人有些事情不能使用Topic?
Topic适合持续数据流。
但是机器人系统还有另外一种非常典型的需求:
请求一个操作,然后等待结果。
这时候Service更加合适。
它的模型非常简单:
Client
│
│ Request
↓
Server
│
│ Response
↓
Client
例如:
机器人系统
│
├── 请求:清空地图
│
↓
地图Node
│
└── 返回:成功
或者:
请求:
读取当前参数
↓
参数服务
↓
返回:
参数值
这种通信方式的特点是:
一次请求,对应一次响应。
Service适合什么样的机器人场景?
例如:
参数设置
设置最大速度
设置加速度
设置传感器参数
状态查询
查询设备状态
查询当前配置
简单控制
启动设备
停止设备
复位设备
这些操作通常并不需要持续反馈。
因此Service非常适合。
为什么Service不适合长时间任务?
假设机器人收到一个任务:
“移动到房间B。”
这可能需要20秒。
如果使用Service:
Request
↓
等待20秒
↓
Response
这时候调用者很难知道:
机器人到底走到哪里了?
有没有遇到障碍物?
任务是不是卡住了?
还需要多久?
是否应该取消?
所以对于机器人这种具有明显任务过程的系统来说,Service就显得不够灵活。
这就是Action存在的原因。
三、Action:为什么机器人导航、机械臂运动更适合Action?
Action可以理解为:
专门为长时间、可反馈、可取消的任务设计的通信机制。
它的基本逻辑可以理解成:
Goal
↓
执行
↓
Feedback
↓
执行
↓
Feedback
↓
Result
例如机器人收到:
前往目标位置。
执行过程中可以不断反馈:
Goal:
前往(10,5)
↓
Feedback:
当前位置(2,1)
↓
Feedback:
当前位置(4,2)
↓
Feedback:
当前位置(7,3)
↓
Feedback:
当前位置(9,5)
↓
Result:
目标到达
如果途中出现异常:
障碍物出现
↓
任务暂停
↓
重新规划
甚至可以:
Cancel
取消任务。
这对于机器人非常重要。
Action为什么适合机器人?
因为很多机器人行为本身就是:
持续一段时间才能完成的任务。
例如:
-
导航
-
机械臂移动
-
抓取
-
放置
-
对接
-
巡检
-
路径跟踪
-
复杂动作执行
这些任务通常都有:
开始 → 执行 → 反馈 → 完成/取消
的过程。
所以Action非常符合机器人任务的天然结构。
Topic、Service、Action怎么选择?
可以简单总结成:
| 通信机制 | 核心模型 | 典型场景 |
|---|---|---|
| Topic | 发布/订阅 | 传感器、状态、连续数据 |
| Service | 请求/响应 | 查询、配置、简单操作 |
| Action | Goal/Feedback/Result | 导航、运动、长时间任务 |
但是实际工程中不能只靠“功能名称”选择。
还需要考虑:
-
数据频率
-
延迟
-
可靠性
-
数据是否允许丢失
-
是否需要反馈
-
是否可以取消
-
网络环境
-
CPU负载
-
实时性要求
而这些问题最终又会进入:
DDS与QoS。
四、ROS 2通信为什么离不开DDS?QoS又到底解决什么问题?
如果把ROS 2通信比作一个城市的交通系统,那么Topic、Service和Action更像是不同的交通组织方式。
而DDS则更接近于:
负责底层数据通信的基础设施。
ROS 2采用中间件抽象,将上层ROS 2 API与底层通信实现隔离开。
可以简单理解为:
ROS 2 Application
↓
rclcpp
↓
RMW
↓
DDS
↓
Network / IPC
这样开发者使用ROS 2的时候,并不需要自己处理底层通信的大量细节。
例如:
publisher->publish(msg);
开发者只需要关注:
“我要发布一条消息。”
至于消息如何发现对端、如何传输、如何序列化、如何进行通信管理,则由底层中间件负责。
这也是ROS 2能够支持复杂机器人系统的重要原因之一。
QoS:机器人通信不能只有一种模式
如果所有机器人数据都采用完全相同的通信策略,那么系统很快会出现问题。
例如:
摄像头图像
激光雷达
IMU
控制命令
诊断信息
参数
这些数据的重要性、频率和实时性要求完全不同。
所以ROS 2提供QoS机制,让通信双方能够针对数据类型配置不同的服务质量策略。
其中最常见的就是:
Reliability
主要包括:
Best Effort
Reliable
Best Effort可以理解为:
尽可能快速地把数据送出去,不强调每一条数据都必须成功送达。
Reliable则更加关注:
数据需要可靠到达。
这两种策略没有绝对的“谁更好”。
关键取决于数据是什么。
例如:
高速传感器
↓
Best Effort
可能更加合理。
因为:
旧数据
↓
意义下降
而对于某些关键控制或状态数据:
Reliable
可能更加重要。
Durability:后来加入的节点要不要看到过去的数据?
再比如:
地图
地图并不是每毫秒产生一个完全独立的新数据。
如果一个新的Node刚刚启动,它可能希望获得当前有效的地图信息。
这时候就需要考虑:
数据是否应该被保留?
这就是Durability相关机制需要解决的问题。
History:保留多少历史消息?
例如:
Keep Last 10
表示只保留最近的一定数量消息。
对于高频传感器数据而言,通常没有必要无限保存。
因为:
旧数据
↓
价值降低
但是某些数据可能需要更加完整的历史记录。
因此History也是需要结合实际应用配置的。
Deadline:数据多久应该出现一次?
这对机器人实时性尤其重要。
假设:
IMU
100Hz
理论上:
每10ms
应该有一条数据。
如果突然:
10ms
20ms
40ms
才收到数据,那么系统可能已经出现异常。
Deadline可以帮助系统表达这种时间约束。
这也是QoS与机器人实时系统开始产生直接联系的地方。
五、通信“可靠”不等于机器人“实时”:从ROS 2进一步走向望获rtLinux
现在把整条通信链路重新画出来:
传感器
↓
ROS 2 Node
↓
Topic
↓
QoS
↓
DDS
↓
Executor
↓
Callback
↓
Thread
↓
Linux Scheduler
↓
CPU
看到这里,一个非常重要的问题就出现了:
如果DDS已经把数据可靠地传到了Node,那么机器人是不是就一定能实时处理?
答案并不是。
因为:
通信及时到达 ≠ CPU及时执行。
例如一个激光雷达数据已经到达:
DDS
↓
ROS 2
↓
Callback Ready
但此时CPU正在运行:
AI推理
或者:
图像处理
或者:
网络中断
那么控制Callback仍然需要等待CPU。
因此:
数据延迟
+
调度延迟
+
Callback执行时间
共同决定了机器人任务最终的响应时间。
这就是为什么机器人实时系统不能简单理解为:
“ROS 2通信快,所以机器人就是实时的。”
实际上,机器人实时性至少涉及几个层次:
通信实时性
↓
Executor执行及时性
↓
线程调度及时性
↓
CPU资源确定性
↓
中断响应
↓
内核调度
当机器人控制周期进一步缩短以后,这些问题会越来越明显。
例如机械臂控制:
1ms
甚至更加严格的控制周期。
如果控制任务偶尔受到其他任务影响:
1ms
1ms
1.2ms
1ms
3ms
1ms
那么平均值可能看起来仍然不错。
但实时系统更加关心的是:
最坏情况下发生什么?
这也是实时系统与普通应用系统的重要区别之一。
因此,当ROS 2逐渐从实验室开发环境走向工业机器人、机械臂、人形机器人和智能制造设备之后,系统架构就不能只关注:
ROS 2
+
DDS
还需要进一步关注:
ROS 2
↓
Executor
↓
实时线程
↓
实时调度
↓
CPU核心隔离
↓
IRQ隔离
↓
实时Linux
在这个底层架构中,望获 OS 的 望获rtLinux可以作为实时操作系统层的一种技术选择。
它并不是替代ROS 2。
相反,更合理的理解是:
┌───────────────────────────┐
│ AI / 感知 / 规划 / 控制 │
├───────────────────────────┤
│ ROS 2 │
│ Node / Topic / Action │
│ QoS / Executor │
├───────────────────────────┤
│ DDS / RMW │
├───────────────────────────┤
│ 望获rtLinux │
│ 实时调度 / 核心隔离 / 资源管理 │
├───────────────────────────┤
│ 国产CPU / SoC │
└───────────────────────────┘
ROS 2主要解决:
机器人软件模块之间怎么协作。
DDS主要解决:
数据如何在通信中间件层传输。
Executor解决:
ROS 2的Callback如何组织执行。
而实时操作系统进一步解决:
线程如何获得CPU,以及如何减少关键任务受到其他任务的干扰。
因此,真正面向机器人产品设计时,应该把它看成一条完整的技术链:
应用 → ROS 2 → DDS → Executor → 实时Linux → CPU。
其中任何一层出现瓶颈,都可能最终影响机器人系统的行为。
例如:
Topic设计不合理
↓
数据堆积
QoS配置不合理
↓
通信行为异常
Executor设计不合理
↓
Callback等待
线程优先级不合理
↓
控制任务延迟
CPU资源没有隔离
↓
后台任务干扰
IRQ没有合理分配
↓
中断影响控制
操作系统实时性不足
↓
Worst-case latency增加
这也说明:
机器人实时性从来不是某一个软件组件单独决定的。
它是从应用、通信、中间件、执行器一直到底层操作系统共同形成的系统能力。
写在最后:Topic、Service、Action只是开始
如果只是ROS 2入门,那么记住:
Topic
→ 发布/订阅
Service
→ 请求/响应
Action
→ 长时间任务
已经足够。
但如果真正进入机器人产品研发,就需要进一步理解:
Topic
↓
QoS
↓
DDS
↓
Executor
↓
Callback
↓
Thread
↓
Scheduler
↓
CPU
因为机器人系统真正复杂的地方,不是:
“数据能不能传过去。”
而是:
数据传过去以后,能不能在规定的时间内被正确处理。
这就是机器人软件从普通分布式应用走向实时系统时最大的变化之一。
例如对于摄像头、激光雷达等高频数据,系统可能更加关注数据吞吐和新鲜度;对于机器人控制任务,则更加关注执行周期、最大延迟和抖动;对于导航Action,则需要考虑任务过程、反馈和取消;对于工业机器人,还需要进一步考虑长期稳定运行、故障恢复和资源隔离。
因此,ROS 2通信机制本身只是机器人实时系统的一部分。
当我们继续向下研究,就会进入一个更加核心的问题:
ROS 2中的数据已经到了,为什么Callback还是可能不能及时执行?
答案就在Executor和操作系统调度机制中。
下一篇我们将进一步进入ROS 2非常核心、同时也非常容易被低估的技术组件:
《ROS 2 QoS到底是什么?Reliability、Durability、History、Deadline一次讲清楚》
我们会从QoS的底层逻辑出发,分析不同QoS策略对机器人传感器、控制、导航以及实时通信的影响,并进一步讨论:
为什么“Reliable”并不意味着“实时”?
这也会成为后续深入 ROS 2实时性、实时Linux、CPU核心隔离以及望获rtLinux 的重要技术基础。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)