一、核心概念扫盲:节点、话题、服务、动作到底是什么?

好,咱们直接进入正题。

很多刚接触 ROS2 的朋友,一上来就被这四个概念搞懵了。节点、话题、服务、动作——名字听着挺唬人,其实说白了,就是机器人系统里不同模块之间「说话」的几种方式。

我刚开始学的时候也绕了好一阵子。后来在项目里踩过坑,才真正理解它们各自该用在什么场景。今天我就用最直白的方式,把这四个东西给你讲透。

1.1 节点(Node)—— 机器人里的「小工人」

节点是什么?你可以把它想象成一个独立工作的小工人。

每个节点只负责一件事。比如:

  • 一个节点专门读取激光雷达数据
  • 一个节点专门做路径规划
  • 一个节点专门控制电机

它们各干各的,互不干扰。但机器人要干活,这些节点之间必须能「说话」。这就引出了后面的通信方式。

我个人习惯:写 ROS2 程序时,我会把每个功能模块拆成一个独立节点。比如做导航,我就分三个节点:传感器采集、定位、路径规划。这样哪个环节出问题,一眼就能定位到。

小技巧:节点名最好起得有意义。别用 node1、node2 这种名字。我见过有人用 lidar_reader、path_planner,半年后回来看代码,自己都看得懂。

1.2 话题(Topic)—— 像「广播」一样发消息

话题是 ROS2 里最常用的通信方式。它的工作模式,说白了就是「发布-订阅」。

想象一下:

  • 有一个节点在广播消息(发布者)
  • 其他节点可以选择收听(订阅者)
  • 发布者不知道谁在听,订阅者也不知道谁在发

这种模式的好处是——松耦合。节点之间不需要知道对方的存在。

举个例子

# 发布者:发布激光雷达数据
ros2 topic pub /scan sensor_msgs/LaserScan "{...}"

# 订阅者:接收激光雷达数据
ros2 topic echo /scan

我在项目中遇到过一个问题:多个节点同时订阅同一个话题,结果数据量太大,CPU 飙到 90%。后来发现是发布频率设得太高。嗯,这里要注意——话题的发布频率要合理,不是越快越好。

避坑指南:我曾经把话题的发布频率设到 100Hz,结果订阅节点处理不过来,消息队列越积越多,最后内存爆了。后来我改成 20Hz,一切正常。记住:发布频率要匹配订阅者的处理能力。

1.3 服务(Service)—— 像「打电话」一样一问一答

话题是单向广播,服务就不一样了。服务是「请求-响应」模式。

你想想看:

  • 客户端发起请求:「帮我算一下这个坐标的路径」
  • 服务端处理请求,返回结果:「路径算好了,给你」
  • 客户端必须等结果,才能继续往下走

这种模式适合那些需要即时响应的操作。

代码示例

# 客户端请求
ros2 service call /compute_path nav_msgs/GetPlan "{start: ..., goal: ...}"

# 服务端响应
# 返回路径数据

我建议:服务适合「一次性」的操作。比如:

  • 查询机器人当前状态
  • 设置某个参数
  • 执行一次计算

但如果你需要持续接收数据,那就别用服务了,用话题更合适。

个人经验:有一次我写了一个服务,客户端每秒钟请求一次。结果服务端忙不过来,整个系统卡住了。后来改成话题发布,问题解决。记住:服务不是用来做高频通信的。

1.4 动作(Action)—— 像「发快递」一样有进度反馈

动作是 ROS2 里最复杂的通信方式,但也是最强大的。

它结合了话题和服务的特点:

  • 像服务一样:有目标(请求)和结果(响应)
  • 像话题一样:可以持续反馈进度
  • 还能随时取消任务

你想想看,机器人执行一个任务,比如「从 A 点走到 B 点」:

  • 你发出目标:「走到 B 点」
  • 机器人边走边反馈:「走到 30% 了...走到 60% 了...」
  • 如果中途发现障碍,你可以取消任务:「别走了,回来」

这就是动作的典型应用场景。

代码示例

# 发送动作目标
ros2 action send_goal /navigate_to_pose nav2_msgs/NavigateToPose "{pose: ...}"

# 反馈进度
# 收到反馈:当前进度 30%
# 收到反馈:当前进度 60%
# 最终结果:到达目标点

小技巧:动作的反馈频率也要控制。我一般设成 1-2Hz,既能知道进度,又不会占用太多带宽。频率太高的话,反馈消息本身就成了负担。

1.5 四者对比:什么时候用哪个?

好,咱们来总结一下。我做了个表格,方便你对照:

通信方式 模式 适用场景 典型例子
话题 发布-订阅 持续数据流 传感器数据、状态信息
服务 请求-响应 一次性操作 查询状态、设置参数
动作 目标-反馈-结果 长时间任务 导航、机械臂控制
节点 独立进程 功能模块 传感器驱动、算法模块

我个人习惯这样选:

  • 如果数据是持续产生的,用话题
  • 如果是一次性请求,用服务
  • 如果是长时间任务,需要进度反馈,用动作
  • 每个功能模块,拆成一个独立节点

避坑指南:我曾经在一个项目里,用服务来实现传感器数据的传输。结果客户端每 10 毫秒请求一次,服务端根本处理不过来。后来改成话题发布,CPU 占用从 80% 降到了 10%。记住:高频数据流,永远用话题。

好了,这四个核心概念,咱们今天就聊到这儿。下一章我会带你手写一个节点,真正跑起来看看效果。到时候你就知道,这些概念在实际代码里是怎么用的了。