第1章:ROS2核心概念与基础回顾

各位同学好,我是你们这门课的老朋友。今天咱们先不急着上手写代码,而是把ROS2最核心的几个概念再过一遍。你可能会说:「这些我早就会了」。嗯,我理解,但多机器人协同开发里,很多坑恰恰就出在这些基础概念上。我当年带团队做第一个多机器人项目时,就因为对动作通信理解不深,差点让两台机器人在仓库里「打架」。

所以,咱们花点时间,把节点、话题、服务、动作、参数这五兄弟,以及launch文件,彻底聊透。

1.1 节点:ROS2的最小执行单元

节点是什么?说白了,就是一个可以独立运行的进程。每个节点只负责一件事,比如控制左轮、处理激光雷达数据、做路径规划。我个人的习惯是:一个传感器对应一个节点,一个执行器对应一个节点,一个算法模块也对应一个节点。这样出了问题,定位特别快。

核心要点:ROS2的节点是分布式的,节点之间通过DDS(数据分发服务)通信。这意味着节点可以运行在同一台电脑上,也可以分布在不同的机器人上。

创建节点其实很简单。用Python的话,几行代码就搞定:

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()

if __name__ == '__main__':
    main()

我的小技巧:节点命名一定要有规律。我习惯用「机器人名_功能名」的格式,比如robot1_nav、robot2_arm。在多机器人系统里,命名混乱会让你调试到怀疑人生。

1.2 话题:最常用的通信方式

话题是ROS2里最核心的通信机制。它是一种发布/订阅模式——发布者往话题里扔数据,订阅者从话题里取数据。你想想看,这就像电台广播,主播只管播,听众只管听,双方不需要知道对方是谁。

我在项目中遇到过一个问题:两个节点订阅了同一个话题,但接收到的数据时间戳不一样。后来发现,是因为一个节点用了Best Effort可靠性,另一个用了Reliable。所以,多机器人系统里,话题的QoS设置一定要统一。

QoS策略 说明 适用场景
Reliable 保证数据送达,可能重传 控制指令、关键状态
Best Effort 尽力送达,可能丢包 传感器数据、图像流
Keep Last 只保留最近N条消息 大多数场景

发布话题的代码示例:

class Talker(Node):
    def __init__(self):
        super().__init__('talker')
        self.publisher = self.create_publisher(String, 'chatter', 10)
        timer_period = 0.5
        self.timer = self.create_timer(timer_period, self.timer_callback)

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello from robot1'
        self.publisher.publish(msg)

1.3 服务:请求-响应模式

话题是单向的,服务是双向的。服务就像你打电话问客服:「帮我查一下订单状态」,客服查完告诉你结果。这种一问一答的模式,适合那些需要即时响应的操作。

举个例子,机器人A想获取机器人B的当前位置。用话题的话,B得一直发,A一直收,浪费带宽。用服务就简单了:A发个请求,B回复一次,完事。

避坑指南:我曾经在项目里用服务来做高频状态查询,结果导致系统响应越来越慢。为什么?因为服务是同步阻塞的,调用方会一直等回复。高频场景,请用话题。

服务定义文件(.srv)长这样:

# GetRobotPose.srv
---
geometry_msgs/Pose pose

1.4 动作:带反馈的长时间任务

动作是ROS2里最「高级」的通信方式。它结合了话题和服务的特点:像服务一样有目标,像话题一样有反馈。适合那些需要执行一段时间、并且你希望随时知道进度的任务,比如导航到某个点、机械臂抓取物体。

动作有三个阶段:

  • 目标发送:客户端告诉服务端「我要做什么」
  • 反馈循环:服务端不断告诉客户端「我做到哪了」
  • 结果返回:任务完成,返回最终结果

我记得第一次用动作做多机器人协同搬运时,就靠反馈机制实时调整两台机器人的速度,才没让货物掉下来。

1.5 参数:节点的配置开关

参数就是节点的配置项。比如机器人的最大速度、激光雷达的扫描频率、PID控制器的系数。把这些值做成参数,就不用每次改代码了。

我建议你把所有「可能会变」的值都做成参数。比如:

self.declare_parameter('max_speed', 1.0)
self.declare_parameter('robot_id', 'robot_1')

speed = self.get_parameter('max_speed').value

我的习惯:参数文件用YAML格式,每个机器人一份。这样换机器人时,只需要换参数文件,代码完全不用动。

1.6 Launch文件:一键启动的艺术

当你的系统有十几个节点时,一个个开终端敲命令?别闹了。Launch文件就是用来一次性启动所有节点的。

ROS2的Launch文件用Python写,比ROS1的XML灵活得多。你可以写条件判断、循环、甚至嵌套启动其他launch文件。

一个简单的launch文件示例:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='my_robot_pkg',
            executable='robot_node',
            name='robot1_node',
            parameters=[{'robot_id': 'robot1'}]
        ),
        Node(
            package='my_robot_pkg',
            executable='sensor_node',
            name='lidar_node'
        ),
    ])

嗯,这里要注意:多机器人系统里,launch文件最好按机器人分模块。每个机器人一个launch文件,再写一个总launch文件把它们串起来。这样调试单个机器人时,就不用启动整个系统了。

小结

这一章我们回顾了ROS2的五大核心概念。说白了,它们就是ROS2的「五虎上将」,各有所长:

  • 节点是基础单元
  • 话题用于持续数据流
  • 服务用于即时请求
  • 动作用于长时间任务
  • 参数用于配置管理
  • Launch文件用于系统集成

下一章,我们会把这些概念真正用到多机器人场景里。到时候你会发现,单机ROS2和多机ROS2,完全是两个世界。做好准备吧。


公众号:蓝海资料掘金营,微信deep3321