第二章:ROS2核心概念深度解析
说实话,很多新手学ROS2,一上来就被这些概念搞懵了。节点、话题、服务、动作、参数……听着像是一堆术语,其实它们就是机器人系统的「五根柱子」。我做了这么多年机器人系统,可以负责任地告诉你:把这五个东西搞明白,ROS2你就掌握了七成。
2.1 节点(Node)——系统的「细胞」
节点是什么?说白了,就是ROS2系统里最小的独立执行单元。每个节点负责一件事,比如控制电机、处理激光雷达数据、发布里程计信息。
我个人习惯把节点想象成「人」。一个团队里,有人负责看路,有人负责开车,有人负责导航。每个节点各司其职,互不干扰。
核心要点:节点是独立的可执行进程,拥有自己的命名空间和生命周期。
创建节点其实很简单,看个例子:
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()
嗯,这里要注意:rclpy.spin() 会让节点一直运行,直到你按 Ctrl+C 停止。我在项目中遇到过有人忘记调用 spin(),结果节点刚启动就退出了,数据根本没发出去。
2.2 话题(Topic)——异步通信的「广播」
话题是ROS2里最常用的通信方式。它就像广播电台——发布者只管发,订阅者只管收,双方不需要知道对方的存在。
你想想看,为什么需要这种模式?因为机器人系统里,传感器数据是持续产生的。激光雷达每秒扫描10次,你总不能每次都去「请求」它吧?话题就是解决这个问题的。
| 特性 | 说明 |
|---|---|
| 通信模式 | 发布/订阅(Publisher/Subscriber) |
| 数据流向 | 单向,一对多 |
| 实时性 | 异步,非阻塞 |
| 典型场景 | 传感器数据、状态信息 |
发布话题的代码也很直观:
# 发布者
self.publisher_ = self.create_publisher(String, 'chatter', 10)
msg = String()
msg.data = 'Hello ROS2'
self.publisher_.publish(msg)
# 订阅者
self.subscription = self.create_subscription(
String, 'chatter', self.listener_callback, 10)
那个数字「10」是队列大小。我曾经因为设成1,导致高速数据丢失——新数据把没来得及处理的老数据覆盖了。建议根据你的数据频率来调这个值。
2.3 服务(Service)——同步通信的「问答」
话题是广播,服务就是「打电话」。你问一句,对方答一句,有来有回。适合那些需要确认结果的场景,比如「请把机械臂移动到位置A,然后告诉我是否成功」。
服务由两部分组成:客户端(Client)和服务端(Service)。客户端发送请求,服务端处理并返回响应。
我的经验:服务适合低频、需要确认的操作。如果你每秒要调用几百次,那还是用话题吧。服务是同步阻塞的,调用多了系统会卡死。
# 服务端定义
from example_interfaces.srv import AddTwoInts
class AddService(Node):
def __init__(self):
super().__init__('add_service')
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_callback)
def add_callback(self, request, response):
response.sum = request.a + request.b
return response
2.4 动作(Action)——带反馈的「长任务」
动作是ROS2里最「高级」的通信方式。它结合了话题和服务的特点:像服务一样有目标,像话题一样能持续反馈进度。
举个例子:让机器人从A点走到B点。你不可能发一个服务请求就完事了——你得知道它走到哪了,有没有撞到东西,能不能中途取消。动作就是为这种场景设计的。
动作有三个核心部分:
- 目标(Goal):告诉机器人要做什么
- 反馈(Feedback):实时汇报进度
- 结果(Result):最终执行结果
避坑指南:我曾经在项目里用服务来实现导航任务,结果机器人走到一半卡住了,服务端一直没返回,整个系统都阻塞了。后来换成动作,完美解决。记住:任何耗时超过1秒的操作,都该用动作。
2.5 参数(Parameter)——系统的「配置开关」
参数就是节点的配置项。比如PID控制器的Kp值、激光雷达的扫描频率、电机的最大速度……这些值如果写死在代码里,每次改都要重新编译,太麻烦了。
ROS2的参数系统支持动态配置。你可以在运行时修改参数,节点会立即响应。
# 声明参数
self.declare_parameter('max_speed', 1.0)
self.declare_parameter('pid_kp', 0.5)
# 获取参数
max_speed = self.get_parameter('max_speed').value
pid_kp = self.get_parameter('pid_kp').value
# 动态修改(命令行)
# ros2 param set /my_node max_speed 2.0
我个人习惯把所有可调参数都放到YAML配置文件里,启动时一次性加载。这样调试的时候改参数特别方便,不用改代码。
2.6 五大概念的关系图谱
下面这张图是我自己总结的,能帮你理清这五个概念之间的关系:
从这张图你能看出来:节点是的核心。话题、服务、动作、参数,都是节点之间通信的手段。选哪个,取决于你的场景。
总结一下我的选择原则:
- 持续数据流(传感器、状态)→ 话题
- 一次请求一次响应(开关、查询)→ 服务
- 长时间任务需要反馈(导航、机械臂)→ 动作
- 运行时配置(调参、设置)→ 参数
嗯,这五个概念你吃透了,ROS2的骨架就算搭起来了。后面我们讲通信机制的时候,会深入到QoS、DDS这些底层细节。但今天先把这五个「老朋友」记住,后面就好办了。