2. ROS2核心概念速通:节点、话题、服务、动作、参数,以及它们与Apollo的对应关系

好,咱们直接进入正题。这一章我打算带你快速过一遍ROS2的五大核心概念——节点、话题、服务、动作、参数。你可能会问,为什么学Apollo要先搞ROS2?

其实很简单。Apollo的底层通信框架,说白了就是基于ROS1魔改的。而ROS2作为新一代标准,设计更现代、更可靠。我当年从ROS1迁移到ROS2时,最大的感受就是——「嗯,这才对嘛」。搞懂了ROS2,再看Apollo的Cyber RT,你会发现很多设计思路是相通的。

2.1 节点(Node)—— 系统的「细胞」

节点是ROS2里最小的可执行单元。每个节点负责一个具体的功能,比如感知、规划、控制。

我的理解:节点就像公司里的员工。每个员工只干自己那摊事,但大家通过消息沟通,协同完成大项目。

在ROS2里启动一个节点很简单:

# Python示例
import rclpy
from rclpy.node import Node

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

def main(args=None):
    rclpy.init(args=args)
    node = MyNode()
    rclpy.spin(node)
    rclpy.shutdown()
个人经验:我刚开始写节点时,总喜欢把所有逻辑塞到一个节点里。后来发现调试起来特别痛苦。建议你按功能拆分成多个小节点,每个节点只做一件事,做好一件事。

Apollo对应关系:Apollo里的每个模块(如Planning、Control)本质上就是一个大节点。只不过Apollo用的是Cyber RT框架,节点叫CyberNode。但设计思想完全一致——模块化、独立运行、消息驱动。

2.2 话题(Topic)—— 异步通信的「广播」

话题是ROS2里最常用的通信方式。发布者往话题里发消息,订阅者从话题里收消息。一对多、异步、非阻塞。

你想想看,这就像电台广播。主播(发布者)只管播,听众(订阅者)只管听。主播不知道谁在听,听众也不知道主播长啥样。但大家通过同一个频道(话题名)连接起来。

# 发布者
self.publisher_ = self.create_publisher(String, 'topic_name', 10)

# 订阅者
self.subscription = self.create_subscription(
    String, 'topic_name', self.callback, 10)
避坑指南:我曾经在项目里遇到过话题名拼写错误导致通信失败的问题。ROS2不会报错,只是默默收不到消息。排查了整整一下午……后来我养成了一个习惯:所有话题名都定义成常量,统一管理。

Apollo对应关系:Apollo的Cyber RT里,话题叫Channel。比如/apollo/planning/trajectory就是一个Channel,Planning模块往里面发轨迹,Control模块订阅它。本质上和ROS2的话题一模一样。

2.3 服务(Service)—— 同步通信的「问答」

服务是同步的请求-响应模式。客户端发请求,服务端处理完返回结果。适合那些需要立即得到结果的场景,比如「查询当前车速」、「设置某个参数」。

我个人习惯把服务比作「打电话」。你拨号(发请求),对方接听(处理),然后你们对话(返回结果)。通话期间,你只能等着,不能干别的。

# 服务端
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_callback)

# 客户端
self.cli = self.create_client(AddTwoInts, 'add_two_ints')
req = AddTwoInts.Request()
req.a = 3
req.b = 5
future = self.cli.call_async(req)
注意:服务是同步的,如果服务端处理时间过长,客户端会一直阻塞。我在做高实时性系统时,一般避免用服务,改用话题或动作。

Apollo对应关系:Apollo里也有类似的服务机制,叫Service。但Apollo用得不多,因为自动驾驶场景里,大多数通信都是异步的、流式的。服务更多用于调试和配置。

2.4 动作(Action)—— 带反馈的「长任务」

动作是ROS2里最复杂的通信方式。它本质上是「服务+话题」的组合。客户端发起一个目标,服务端执行过程中不断发反馈,最终返回结果。

举个例子:你让自动驾驶车辆「从A点开到B点」。这是一个长任务,你希望知道执行进度(比如「已行驶50%」),而不是傻等。动作就是干这个的。

# 动作服务端
self._action_server = ActionServer(
    self, Fibonacci, 'fibonacci', self.execute_callback)

# 动作客户端
self._action_client = ActionClient(self, Fibonacci, 'fibonacci')
goal_msg = Fibonacci.Goal()
goal_msg.order = 10
self._action_client.send_goal_async(goal_msg)
我的经验:动作在ROS2里设计得非常优雅。我做过一个路径规划任务,用动作实现了「规划中→规划完成→执行中→执行完成」的全流程反馈。调试时特别直观。

Apollo对应关系:Apollo里没有直接对应的「动作」概念。但它的Task机制(比如RoutingTask)本质上就是动作——发起一个导航任务,持续接收状态反馈,最终完成。

2.5 参数(Parameter)—— 运行时配置的「旋钮」

参数是ROS2里用来动态配置节点行为的机制。你可以把参数想象成设备的「旋钮」——运行时拧一下,行为就变了,不用重启。

比如,你可以通过参数调整PID控制器的Kp值,或者切换感知算法的模型版本。

# 声明参数
self.declare_parameter('my_param', 'default_value')

# 获取参数
param = self.get_parameter('my_param').value

# 动态设置参数(通过命令行)
ros2 param set /my_node my_param new_value
避坑指南:我曾经在参数类型上栽过跟头。ROS2的参数类型是强类型的,你声明了整数,传字符串就会报错。建议你声明参数时,明确指定类型和默认值。

Apollo对应关系:Apollo的Cyber RT里,参数叫Parameter,用法几乎一样。Apollo的模块启动时,会加载一个配置文件(比如planning_config.pb.txt),里面就是一堆参数。运行时也可以通过cyber_launch动态修改。

2.6 核心概念对比一览

ROS2概念 通信模式 Apollo对应 典型场景
节点(Node) — CyberNode 感知、规划、控制等模块
话题(Topic) 异步发布/订阅 Channel 传感器数据、轨迹消息
服务(Service) 同步请求/响应 Service 查询状态、触发操作
动作(Action) 异步+反馈 Task机制 路径规划、泊车任务
参数(Parameter) 键值对配置 Parameter 算法参数、模块配置

2.7 知识体系总览

下面这张图,是我自己梳理的ROS2核心概念与Apollo的对应关系。你可以把它当作一张「地图」,后续学习时随时回来对照。

ROS2核心概念与Apollo对应关系 ROS2 Apollo Cyber RT 节点 (Node) CyberNode 对应 话题 (Topic) Channel 对应 服务 (Service) Service 对应 动作 (Action) Task机制 对应 参数 Parameter 对应 ROS2的五大核心概念,在Apollo中都有对应的实现

嗯,这一章的内容就到这里。ROS2的这五个概念,你只要搞懂了,再看Apollo的Cyber RT源码,会发现很多似曾相识的东西。下一章我们会动手搭建联调环境,到时候这些概念都会用上。

一句话总结:节点是「人」,话题是「广播」,服务是「问答」,动作是「长任务」,参数是「旋钮」。记住这个比喻,你就掌握了ROS2的精髓。

可可精品资料库