2. ROS2基础回顾

在进入多机器人行为树任务编排之前,必须先把 ROS2 的通信骨架重新梳理清楚。行为树本身只是“决策逻辑”,它最终要落到节点、话题、服务、动作、参数和 Launch 文件这些具体机制上。多机器人场景下,命名空间、域 ID、DDS 发现和 QoS 策略会直接决定“谁和谁说话、能不能说上话”。本节用一张通信关系图把六类核心对象串起来,再逐项说明它们在多机编排中的角色。

核心结论:单机 ROS2 靠“默认命名”就能跑通;多机器人必须显式设计命名空间、域 ID 与 QoS,否则会出现“话题同名互相串扰”或“完全发现不到对方”两类典型故障。

一、六类核心对象的分工

ROS2 的计算图由节点(Node)构成,节点之间通过话题、服务、动作三种通信方式交互,参数用于配置节点行为,Launch 文件负责批量启动与编排。它们的关系可以用下面的 SVG 表示:

ROS2 多机器人通信机制关系图 Launch 文件 批量启动 / 命名空间 / 参数注入 节点 A /robot1/nav_node 节点 B /robot2/nav_node 参数 Parameters max_speed / goal_tol 话题 Topic 发布/订阅 · 异步 · 多对多 /scan /odom /cmd_vel 服务 Service 请求/响应 · 同步 · 一对一 /set_mode /clear_costmap 动作 Action 目标/反馈/结果 · 可取消 /navigate_to_pose DDS 中间件 · 域 ID + QoS ROS_DOMAIN_ID 隔离不同机器人组 Reliability / Durability / History 决定匹配

二、话题、服务、动作的选型原则

三者不是可随意替换的,选错会带来阻塞、丢帧或无法取消等问题。判断依据是“是否需要应答、是否长时间执行、是否要中途反馈”。

机制通信模型典型场景多机注意点
话题 Topic发布/订阅,异步,多对多激光、里程计、速度指令同名话题会串扰,必须加命名空间
服务 Service请求/响应,同步,一对一切换模式、清代价地图阻塞调用,勿在回调中长等
动作 Action目标+反馈+结果,可取消导航到点、机械臂抓取行为树最常用的长任务接口
参数 Parameter键值配置,可动态更新速度上限、容差、阈值按机器人分别注入,避免全局覆盖

三、多机器人通信的关键机制

多机器人不是简单地把单机程序复制两份。ROS2 默认使用 DDS 做自动发现,同一网段内所有节点默认互相可见。要让 robot1 和 robot2 各自独立,常用三种隔离手段:

  • 命名空间(Namespace):把节点和话题放进 /robot1、/robot2 前缀,如 /robot1/cmd_vel 与 /robot2/cmd_vel 互不干扰。
  • 域 ID(ROS_DOMAIN_ID):不同域之间完全不发现,适合把不同机器人组彻底隔离,但跨域通信需要桥接。
  • QoS 策略:发布者与订阅者的 Reliability、Durability 必须兼容,否则“话题存在却收不到数据”。传感器常用 Best Effort,控制指令常用 Reliable。
经验法则:同一机器人内部用命名空间区分模块;不同机器人之间若需协同,保持同一域 ID 并用命名空间隔离;若只是同网段测试且互不相关,用不同域 ID 最省心。

四、Launch 文件:多机启动的编排入口

Launch 文件负责一次性拉起多个节点、传入参数、设置命名空间和重映射。多机器人场景下,通常用参数化 Launch,通过参数决定机器人数量与命名空间前缀。

from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration

def generate_launch_description():
    ns = LaunchConfiguration('ns')
    return LaunchDescription([
        DeclareLaunchArgument('ns', default_value='robot1'),
        Node(
            package='nav2_bringup',
            executable='navigation_launch.py',
            namespace=ns,
            parameters=[{'max_speed': 0.5, 'goal_tolerance': 0.1}],
            remappings=[('cmd_vel', 'cmd_vel')],
        ),
    ])

启动两个机器人时,只需分别传入 ns:=robot1 与 ns:=robot2。这样每个机器人拥有独立的 /robotX/cmd_vel、/robotX/odom 等话题,行为树节点再按命名空间去调用对应动作接口。

五、案例:两机编队中的一次“收不到数据”排障

某次两机编队测试中,robot1 的行为树始终收不到 robot2 的位置。排查过程如下:先用 ros2 node list 确认两个节点都在;再用 ros2 topic list 发现只有 /robot1/pose,没有 /robot2/pose;检查 Launch 发现 robot2 的命名空间参数写成了空字符串,导致两个节点都发布到根命名空间,话题互相覆盖。修正命名空间后,再用 ros2 topic echo /robot2/pose 验证数据正常。这个案例说明:多机问题往往不在算法,而在命名与启动配置。

常见误区:① 认为“话题名一样就能通信”,忽略命名空间导致串扰;② 在服务回调里做长时间等待,阻塞执行器;③ 动作目标发出后不处理取消与超时;④ 参数用全局默认值,导致多机器人互相覆盖;⑤ 忽略 QoS,出现“能 list 到话题却收不到消息”。

六、与行为树编排的衔接

行为树中的动作节点最终会调用 ROS2 动作接口,条件节点会订阅话题或读取参数。因此,多机器人行为树的第一步不是画树,而是把命名空间、域 ID、QoS 和 Launch 参数设计清楚。只有通信层稳定、隔离明确,行为树才能可靠地编排多台机器人的协同任务。