前言
本节主要阐述ROS2通信原理并记录自动驾驶开发过程中遇到的一些问题与解决思路。
1. ROS2取消roscore原因
ROS2通信体系的核心价值,不在于把ROS1中的接口重新实现一遍,而在于重新定义了机器人系统中“节点如何发现彼此、数据如何被分发、通信质量如何被约束、系统如何跨机器扩展”的底层范式。ROS1依赖roscore维护全局命名与发现关系,适合实验室原型、单机验证和小规模机器人应用。ROS2面向多机协同、复杂传感器、高频数据流、工业现场部署和长期运行需求,将通信基础迁移到DDS与RTPS之上,通过RMW层实现中间件可插拔,通过DDS动态发现机制实现分布式组网,通过QoS策略将可靠性、时延、带宽与历史数据行为显式暴露出来。
1.1 ROS1通信模型的工程边界
ROS1的通信体系中,roscore承担Master角色,负责节点注册、Topic查询和连接关系建立。一个典型ROS1系统启动后,节点会先向Master登记自身信息,订阅端通过Master查询发布端地址,随后发布端与订阅端之间建立点对点连接。数据真正传输时,Topic数据通常并不经过Master;但连接关系的建立依赖Master。
这种模式具有清晰的工程优点:结构简单、调试直观、入门成本低。在教学、算法验证、单机机器人平台中,roscore提供了足够便利的中心化协调能力。
自动驾驶系统对通信基础有更高要求:
| 工程需求 | ROS1中心化发现的约束 |
|---|---|
| 多机协同 | Master地址配置、网络环境变化、跨主机解析容易引入额外复杂度 |
| 高可用运行 | Master异常会影响新节点加入和连接关系重建 |
| 高频传感器融合 | 通信可靠性、队列深度、传输策略需要更细粒度控制 |
| 车端/边缘端部署 | 系统需要在动态拓扑中自动发现、自动恢复、自动隔离 |
| 工业网络管理 | 需要通过域、QoS、发现策略和中间件配置进行工程化治理 |
ROS2对底层通信进行重构,将系统发现、数据分发和通信质量控制下沉到DDS生态。DDS本身是面向实时系统、分布式系统和数据中心式通信模型设计的中间件标准,ROS2基于DDS获得了分布式发现、QoS配置、跨语言跨平台互操作等能力。
1.2 从节点中心到数据中心
ROS1开发者习惯从“节点连接节点”的角度理解系统。ROS2更适合从“数据在全局数据空间中被发布、匹配和分发”的角度理解通信。
在DDS模型中,系统中的Participant加入某个Domain后,发布者与订阅者围绕Topic、数据类型和QoS进行匹配。应用层并不需要手动维护每个对端节点地址,也不需要显式指定数据要发给哪台机器。只要位于同一通信域、Topic名称一致、类型兼容、QoS匹配,底层中间件就会建立通信关系。
这种设计带来的变化非常关键:
- 节点生命周期与通信发现过程解耦,后启动节点可以自动加入系统。
- 多台机器上的节点处于同一DDSDomain时,可以形成统一的逻辑通信空间。
- 通信质量由QoS策略约束,工程师可以针对传感器、控制指令、状态量、地图数据配置不同传输行为。
- 底层DDS实现可以替换,应用代码通过rclcpp/rclpy保持相对稳定。
ROS2官方文档说明,ROS2默认使用DDS作为中间件,同时兼容多个DDS或RTPS实现,并支持FastDDS、CycloneDDS、ConnextDDS、GurumDDS等实现;当前ROS2也支持Zenoh等非DDSRMW实现。
2. ROS2通信架构
ROS2通信栈可以理解为从应用API到网络协议的多层封装。每一层都承担明确职责:上层关注自动驾驶开发接口,下层关注发现、序列化、传输和QoS。
2.1 应用层与rcl:开发者直接接触的接口
应用层由rclcpp、rclpy等客户端库组成。开发者创建Node,声明Publisher、Subscription、Service、Client、ActionServer或ActionClient,并通过回调函数处理数据。
以C++Publisher为例,应用层创建发布者:
auto pub = node->create_publisher<std_msgs::msg::String>(
"/diagnostics/state",
rclcpp::QoS(10).reliable()
);
这行代码背后实际发生了多层动作:
- rclcpp将C++接口转换为rcl层通用调用。
- rcl将Topic、类型、QoS信息传递给rmw层。
- rmw实现调用具体DDS厂商API创建DataWriter。
- DDS参与发现与匹配,找到兼容订阅者。
- RTPS将数据样本编码为网络报文并发送。
2.2 RMW层:ROS2架构解耦的关键
RMW即ROSMiddleware接口。它是ROS2通信架构中最关键的解耦层。ROS2并未把应用代码直接绑定到某一个DDS厂商API,而是通过rmw接口抽象出统一的创建节点、创建发布者、创建订阅者、序列化、反序列化、等待集合、服务调用等能力。
这种设计使ROS2具备中间件可插拔能力。使用过程中可以在不修改业务代码的情况下,通过环境变量切换底层RMW实现:
# 查看当前RMW实现
printenv RMW_IMPLEMENTATION
# 切换到FastDDS实现
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
# 切换到CycloneDDS实现
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
官方文档说明,安装并正确source新的RMWVendor后,可以在运行时选择使用哪个RMW实现。
在工业现场,这一层解耦非常重要。不同中间件在发现策略、资源占用、共享内存、网络接口选择、跨网段配置、实时性表现上存在差异。开发阶段可以使用默认实现快速验证,部署阶段可以根据网络拓扑和性能测试结果选择更适合的RMW实现。
2.3 DDS标准层:全局数据空间
DDS的核心抽象包括Domain Participant、Topic、Publisher、Subscriber、DataWriter、DataReader和QoS。可以将DDS Domain理解为一个逻辑隔离的通信空间。处于相同Domain中的参与者可以相互发现,处于不同Domain中的参与者默认相互隔离。
在DDS视角中,通信关系围绕数据展开:
| DDS概念 | ROS2中的近似对应 | 作用 |
|---|---|---|
| GDS | DDS Domain | 全局数据空间 |
| Domain Participant | 节点所在进程中的DDS参与者 | 加入某个通信域,参与发现过程 |
| Topic | ROS2Topic | 定义数据名称和类型 |
| DataWriter | Publisher底层实体 | 写入数据样本 |
| DataReader | Subscriber底层实体 | 读取数据样本 |
| QoS | ROS2QoSProfile | 约束可靠性、历史队列、持久性等行为 |
DDS的设计重点是数据分发,不是远程过程调用。Service和Action在ROS2上层仍然存在,但底层也会映射到DDS通信实体,最终通过数据读写实现请求、响应和状态反馈。
2.4 RTPS协议层:互操作性的线协议
RTPS即Real-Time Publish-Subscribe Protocol,是DDSI-RTPS规范定义的线协议。它规定了DDS数据如何在网络中表达、传输和互操作。DDS厂商可以有不同实现,但只要遵循RTPS协议,就具备跨实现互操作基础。从工程角度看,RTPS解决了三个关键问题:
- 发现信息如何表达:Participant、Reader、Writer等实体如何被对端识别。
- 数据样本如何传输:Writer如何向匹配Reader发送CacheChange。
- 可靠性如何维持:心跳、ACK/NACK、重传等机制如何支持可靠传输。
OMG发布的DDSI-RTPS规范定义了DDS互操作线协议,RTPSWriter负责将HistoryCache中的变更传输给匹配的RTPSReader。
3. DDS动态发现机制
ROS2 在取消 roscore 这一中心节点后,多机系统中节点的互相寻址与连接完全依赖于底层 DDS 的自动发现机制(Discovery Protocol)。以最常用的简单发现协议(Simple Discovery)为例,整个动态发现过程通常分为两个核心阶段:PDP(参与者发现阶段)与 EDP(端点发现阶段)。
3.1 PDP参与者发现
PDP即Participant Discovery Protocol。它负责让DDS Domain中的Participant知道彼此存在。常见实现会使用UDP组播向局域网发送发现公告。参与者启动后,会周期性发送自身标识、Domain信息、地址信息和能力信息。其他参与者收到公告后,会在本地维护远端参与者记录。
CycloneDDS文档说明,SPDP 协议会定期像一组地址发送SPDP样本,默认情况下仅包含多播地址;同时也可以通过Discovery/Peers配置单播地址作为组播发现的补充或替代。
PDP解决的是“系统中有哪些参与者”的问题。此时双方只知道对端参与者存在,还不知道对端发布或订阅了哪些具体Topic。
3.2 EDP端点发现
EDP即Endpoint Discovery Protocol。让Participant各处可以交换底下有哪些端点。端点是收送数据的通讯端点,即数据读取器(DataReader)和数据写入器(DataWriter)。端点信息通常包括:
- Topic名称。
- Topic数据类型。
- Publisher或Subscriber标识。
- QoS配置。
- 可用传输地址。
- 可靠性、持久性、历史队列等策略。
FastDDS文档说明,EDP阶段中,DataWriter和DataReader会相互确认;DomainParticipant通过PDP阶段建立的通信通道交换DataWriter和DataReader信息。
EDP解决的是“参与者内部有哪些具体通信端点”的问题。只有Topic名称、数据类型和QoS兼容的DataWriter与DataReader才会完成匹配。
3.3 从组播发现到单播数据传输
在很多局域网场景中,组播主要用于发现。发现完成并匹配成功后,用户数据通常可以通过点对点单播路径发送。此时数据流不再依赖中心节点,也不需要所有节点都接收所有数据。这也是ROS2多机通信看似“自动”的根源:
- 节点加入相同ROS_DOMAIN_ID。
- DDS Participant通过PDP发现彼此。
- DataWriter和DataReader通过EDP交换端点元数据。
- Topic、类型和QoS兼容后建立匹配关系。
- RTPS按照QoS和传输配置发送用户数据。
3.4 工业网络中的发现策略取舍
Simple Discovery适合小规模局域网、研发测试环境和节点数量有限的机器人系统。随着节点数量、主机数量和Topic数量增加,发现流量与元数据交换会变得明显。工业现场还经常遇到交换机禁用组播、VLAN隔离、防火墙过滤UDP、无线链路丢包等情况。
因此工程部署时通常需要评估以下策略:
| 场景 | 建议策略 |
|---|---|
| 单车多进程、多传感器 | 默认发现通常足够,重点检查QoS和网络接口 |
| 多项目、多车辆 | 使用ROS_DOMAIN_ID隔离不同系统,避免发现风暴 |
| 交换机组播受限 | 配置CycloneDDS Peers或FastDDS Initial_Peers |
| 大规模节点系统 | 评估FastDDS Discovery Server、静态发现或Zenoh路由方案 |
| 跨网段通信 | 明确路由、组播代理、DDSRouter或ZenohRouter方案 |
FastDDS文档说明,发现公告可以配置为发送到单播Initial_Peers,也可以配置公告周期;CycloneDDS也支持通过Peers配置单播发现地址。
4. QoS策略深度解析与适配匹配
ROS2将QoS暴露给应用开发者,是其相对ROS1的重要变化之一。QoS不是简单的“可靠”或“不可靠”开关,而是一组控制通信行为的策略组合。ROS2官方文档]说明,QoS策略可以将通信调到类似TCP的可靠状态,也可以调到类似UDP的尽力而为状态。下面列举一些常见 QoS。
4.1 Reliability:可靠性策略
Reliability决定发布端和订阅端如何处理丢包与重传。
| 策略 | 行为 | 适用场景 | 工程风险 |
|---|---|---|---|
| RELIABLE | 尽力确保数据送达,底层可能触发确认和重传 | 控制指令、任务状态、低频关键事件、服务调用 | 网络拥塞时可能增加延迟和抖动 |
| BEST_EFFORT | 尽力发送,不保证每条数据送达 | LiDAR点云、相机图像、IMU高频流、临时状态可视化 | 丢包时应用层必须容忍数据缺口 |
在100Hz高分辨率LiDAR点云、多路摄像头视频流或车端调试画面中,短暂丢帧通常可以接受。强制使用RELIABLE会引入确认、重传和缓存压力,弱网环境下可能导致带宽拥塞和时延抖动。此时BEST_EFFORT更符合实时感知链路的工程目标。
控制指令、模式切换、紧急停车、任务结果等数据具有较高语义价值,丢失一条消息可能导致状态机不一致。此类链路应优先使用RELIABLE,并配合合理的Deadline、Liveliness和应用层安全机制。
4.2 Durability:持久性策略
Durability决定后加入的订阅者是否可以获取发布者已经发布过的数据。
| 策略 | 行为 | 典型场景 |
|---|---|---|
| VOLATILE | 只接收订阅建立之后的新数据 | 传感器实时流、控制闭环数据 |
| TRANSIENT_LOCAL | 发布端保留一定历史数据,后加入订阅者可获得最近样本 | 地图、静态配置、标定参数、路径规划初始参考 |
经典案例是地图Server发布静态地图。导航节点可能在地图发布后才启动。如果地图Topic使用VOLATILE,后启动节点可能无法获得已发布地图;使用TRANSIENT_LOCAL后,发布端可以为后加入订阅者提供最近缓存样本。
4.3 History与Depth:队列行为
History控制历史消息保留策略,Depth控制KEEP_LAST模式下保留多少条样本。
| 策略 | 含义 | 工程建议 |
|---|---|---|
| KEEP_LAST(N) | 保留最近N条消息 | ROS2最常用配置,适合资源可控系统 |
| KEEP_ALL | 尽量保留全部消息 | 谨慎使用,需要配合资源限制,避免内存膨胀 |
Depth并非越大越好。对于高频传感器,如果订阅端处理能力不足,过大的队列会让应用处理过期数据,造成感知结果滞后。对于控制闭环,通常更关注最新状态,Depth可以较小。对于离线记录、低频状态、调试信息,可以适当增加Depth以减少偶发处理延迟带来的数据丢失。
4.4 Deadline:截止时间策略
Deadline用于描述一个Topic在时间维度上的“更新周期契约”。它不是传输层重传策略,也不是实时调度器,而是告诉DDS/RMW:这个Topic理论上应该在多长时间内至少更新一次。对于Publisher来说,Deadline表示两次连续发布之间允许的最大时间间隔;对于Subscriber来说,Deadline表示两次连续接收之间允许的最大时间间隔。
| 关注点 | 说明 |
|---|---|
| 核心含义 | 期望Topic按固定或近似固定周期更新 |
| 触发条件 | 超过指定时间没有发布或接收新样本 |
| 典型事件 | offered deadline missed、requested deadline missed |
| 适用数据 | 控制周期、底盘状态、定位状态、心跳状态、关键传感器健康状态 |
| 不适合误用 | 不应把Deadline当成“保证准时到达”的实时性承诺 |
在自动驾驶系统和工业机器人中,Deadline更适合用来做“通信健康监控”。例如底盘状态Topic设计为50Hz更新,理论周期为20ms,可以设置一个略宽松的Deadline,例如40ms或50ms。一旦连续超过该时间窗口没有收到状态,订阅端就可以认为底盘状态链路异常,触发降级、报警或安全停车逻辑。
Deadline的兼容性也需要注意:Subscriber请求的Deadline不能比Publisher提供的能力更严格。更直观地说,如果Publisher承诺最多20ms更新一次,而Subscriber只要求50ms内收到一次,这是兼容的;如果Publisher只能承诺100ms更新一次,而Subscriber要求20ms内必须收到一次,则QoS不兼容。
Deadline要根据真实发布频率、网络抖动、Executor调度延迟和系统负载留出余量。设置过严会导致误报,设置过宽则失去健康监控意义。
4.5 Liveliness:存活性策略
Liveliness用于判断发布实体是否仍然“活着”。它解决的问题不是“数据有没有按周期更新”,而是“发布者是否还存在,是否还具备继续发布的能力”。这在分布式机器人系统中非常重要,因为节点崩溃、进程卡死、网络断开、主备控制器切换,都可能导致系统表面Topic还存在,但实际数据链路已经不可用。
| 策略 | 行为 | 工程含义 |
|---|---|---|
| AUTOMATIC | 由底层RMW/DDS自动维护存活状态 | 使用简单,适合大多数普通Topic |
| MANUAL_BY_TOPIC | 应用层需要通过发布数据或显式assert liveliness声明该Topic仍然存活 | 适合关键控制、主备冗余、需要检测应用逻辑卡死的场景 |
| Lease Duration | 允许发布者多久不声明存活,超过后认为失活 | 相当于存活租约或心跳超时时间 |
Deadline与Liveliness的区别很关键:Deadline关注的是“数据是否按预期周期到达”,Liveliness关注的是“发布者是否还活着”。一个低频事件Topic可能很长时间没有新数据,但发布者仍然存活;反过来,一个周期Topic如果发布者卡死,既可能Deadline Missed,也可能Liveliness Lost。
在自动驾驶和工业控制中,Liveliness常用于关键节点健康判断。例如主控制节点、制动控制节点、状态机节点可以设置较短的Lease Duration。订阅端一旦发现Liveliness丢失,不应继续使用旧控制状态,而应进入安全策略,例如保持、降级、急停或切换备用控制链路。
普通传感器流一般不需要过度配置Liveliness,使用默认AUTOMATIC即可;关键控制链路和主备冗余链路可以考虑MANUAL_BY_TOPIC,但必须保证应用层有稳定的assert逻辑,否则容易出现误判。
4.6 Lifespan:消息寿命策略
Lifespan用于规定一条消息从发布开始,在多长时间内仍然有效。超过该时间后,消息会被认为是过期数据,不应再被交付给订阅端,也不应继续停留在历史缓存中。它的核心价值是避免系统处理“迟到但已经失去意义”的旧数据。
| 关注点 | 说明 |
|---|---|
| 核心含义 | 限制消息有效期,防止过期样本被使用 |
| 典型对象 | 图像帧、点云帧、障碍物列表、临时规划结果、短时状态估计 |
| 适合场景 | 高实时性链路、弱网环境、存在缓存或重传的链路 |
| 主要风险 | 时间设置过短会导致消息还未处理就过期,设置过长则可能引入陈旧数据 |
例如相机图像、LiDAR点云、感知障碍物列表这类数据具有明显时效性。对于高速移动平台,500ms前的障碍物位置可能已经不再可靠。如果系统在网络拥塞或订阅端阻塞后继续处理旧数据,反而会造成错误决策。此时可以通过Lifespan限制消息有效期,让过期数据在进入业务逻辑前被丢弃。
Lifespan和Reliability之间存在一个常见取舍:RELIABLE会尽力重传丢失样本,但如果样本已经超过Lifespan,即使最终重传成功,也不应该再被使用。因此,对强实时数据来说,RELIABLE并不总是更好;需要结合Lifespan、Deadline和业务容忍度综合判断。
传感器数据的Lifespan应略大于正常链路延迟和处理延迟,但小于业务上可接受的最大数据年龄。例如感知链路可以按100ms、200ms、500ms等等级设计,而不是盲目使用无限有效期。
4.7 Ownership:所有权策略
Ownership是DDS层面的QoS策略,用于处理“多个DataWriter同时向同一个Topic实例写数据时,DataReader应该接受谁的数据”。它在ROS2常规应用层接口中不像Reliability、Durability、Deadline那样常被直接配置,很多项目需要通过具体DDS厂商的XML配置或底层能力支持,因此写Ownership更偏DDS高级策略,不是所有RMW实现或ROS2使用方式都适合直接依赖。
| 策略 | 行为 | 典型场景 |
|---|---|---|
| SHARED | 多个Writer的数据都可以被Reader接收 | 多个节点共同上报告警、日志、观测信息 |
| EXCLUSIVE | 同一实例同一时刻只接受一个Owner的数据 | 主备冗余控制、热备系统、唯一指令源选择 |
| Ownership Strength | EXCLUSIVE模式下用于决定哪个Writer是Owner | 主控制器强度高,备用控制器强度低 |
在自动驾驶系统中,Ownership最典型的价值是主备冗余。例如主从机都能发布同一个控制Topic,但系统希望正常情况下只接受主机数据;当主机失活或错过Deadline时,从机自动接管。DDS可以通过EXCLUSIVE Ownership和Ownership Strength实现这种“谁拥有当前Topic实例控制权”的选择。
但是,在自动驾驶中不建议把关键仲裁逻辑完全隐藏在DDS Ownership里。因为ROS2消息通常不是按业务对象精细Keyed建模,很多Topic在DDS视角下可能只有一个实例;同时不同RMW实现、XML配置、调试工具对Ownership的支持和可见性也不完全一致。对于自动驾驶这种安全系数较高的场景,更稳妥的做法通常是:DDS Ownership作为底层冗余能力之一,应用层仍然保留显式的主从状态机、控制权仲裁、日志记录和安全校验。
Ownership还与Liveliness、Deadline有关。EXCLUSIVE模式下,当前Owner如果失去Liveliness,或者违反Deadline,系统可能切换到其他具备更高或可用Ownership Strength的Writer。因此,Ownership不应孤立理解,而应放在“冗余发布者 + 存活检测 + 周期契约 + 应用层安全策略”的组合中设计。
普通ROS2话题默认不需要考虑Ownership;只有在多发布者冗余、主备控制、热切换、唯一数据源选择等场景下,才值得深入评估DDS Ownership。使用前必须确认当前RMW/DDS实现是否支持、配置方式是否可控、故障切换行为是否可测试。
4.8 QoS兼容性原则:请求与提供模型
ROS2 QoS匹配遵循Request/Offered模型。Publisher提供某种服务质量,Subscriber请求某种最低服务质量。只有Publisher提供能力满足Subscriber请求时,通信才能建立。官方文档指出,兼容性由请求端与提供端策略决定;对于Reliability和Durability等策略,不兼容会导致两端即使在线也无法通信。
常见误区如下:
| Publisher | Subscriber | 是否匹配 | 说明 |
|---|---|---|---|
| BEST_EFFORT | BEST_EFFORT | 匹配 | 订阅端接受尽力而为 |
| RELIABLE | BEST_EFFORT | 匹配 | 发布端能力更强,订阅端要求较低 |
| BEST_EFFORT | RELIABLE | 不匹配 | 订阅端要求可靠,发布端无法提供 |
| VOLATILE | VOLATILE | 匹配 | 双方只处理新数据 |
| TRANSIENT_LOCAL | VOLATILE | 匹配 | 发布端保留历史,但订阅端不强制要求 |
| VOLATILE | TRANSIENT_LOCAL | 不匹配 | 订阅端要求历史数据,发布端无法提供 |
对于时间与存活策略,也要遵循同样的“请求不能高于提供”原则:
| 策略 | 兼容性关注点 | 说明 |
|---|---|---|
| Deadline | Publisher提供的更新周期能力要满足Subscriber请求 | 可理解为offered deadline period <= requested deadline period |
| Liveliness | Subscriber要求的存活声明粒度和租约不能比Publisher能提供的更严格 | Lease Duration过短容易造成误判 |
| Lifespan | 更多体现为样本有效期控制,通常不是最常见的匹配失败原因 | 重点防止过期数据进入业务逻辑 |
| Ownership | SHARED/EXCLUSIVE类型需要一致 | 主要在DDS高级冗余场景中关注 |
“节点能看到,Topic也能看到,但收不到消息”经常由QoS不兼容引起。排查时优先使用以下命令查看实际QoS:
ros2 topic info /camera/image_raw --verbose
ros2 topic info /points_raw --verbose
ros2 topic echo /map --qos-durability transient_local
4.9 典型数据链路QoS建议
| 数据类型 | Reliability | Durability | History/Depth | 说明 |
|---|---|---|---|---|
| 相机图像 | BEST_EFFORT | VOLATILE | KEEP_LAST(1~5) | 保持实时性,容忍丢帧 |
| LiDAR点云 | BEST_EFFORT | VOLATILE | KEEP_LAST(1~5) | 避免重传造成拥塞 |
| IMU | BEST_EFFORT或RELIABLE | VOLATILE | KEEP_LAST(10~50) | 根据频率和丢包容忍度选择 |
| 控制指令 | RELIABLE | VOLATILE | KEEP_LAST(1~10) | 语义关键,需降低丢失概率 |
| 车辆状态 | RELIABLE或BEST_EFFORT | VOLATILE | KEEP_LAST(5~20) | 低频关键状态可可靠,高频状态可尽力 |
| 静态地图 | RELIABLE | TRANSIENT_LOCAL | KEEP_LAST(1) | 支持后启动节点获取地图 |
| 参数/配置 | RELIABLE | TRANSIENT_LOCAL | KEEP_LAST(1~10) | 强调一致性与后加入可用性 |
| 调试可视化 | BEST_EFFORT | VOLATILE | KEEP_LAST(1~5) | 优先减少系统扰动 |
5. ROS2多机通信配置
5.1 基础条件检查
ROS2多机通信首先应满足以下条件:
| 检查项 | 要求 |
|---|---|
| 网络连通性 | 多台机器位于可达网络中,IP层可以互通 |
| ROS_DOMAIN_ID | 需要通信的节点使用相同Domain ID |
| RMW实现 | 推荐同一系统内先使用相同RMW实现降低变量 |
| Topic类型 | Publisher与Subscriber消息类型一致 |
| QoS策略 | Subscriber请求不能超过Publisher提供能力 |
| 防火墙 | 放行DDS发现和数据传输所需UDP流量 |
| 组播 | Simple Discovery依赖组播时,交换机与系统需允许组播 |
官方文档说明,ROS2节点默认使用Domain ID 0;为了避免同一网络中不同计算机组互相干扰,应为不同系统设置不同Domain ID。
# 机器A与机器B使用同一DomainID
export ROS_DOMAIN_ID=10
# 建议写入shell配置,避免重启终端后丢失
echo 'export ROS_DOMAIN_ID=10' >> ~/.bashrc
source ~/.bashrc
5.2 RMW实现切换
不同ROS2发行版默认RMW实现可能存在差异,工程项目中应显式记录部署所用RMW实现。
# 查看当前RMW
printenv RMW_IMPLEMENTATION
# 临时切换到FastDDS
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
# 临时切换到CycloneDDS
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
# 运行测试节点
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener
建议在项目部署文档中固定以下信息:
export ROS_DOMAIN_ID=23
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
RMW切换后,应重新打开终端或重新source环境,确保所有节点使用一致配置。混合RMW并非一定不能通信,但会引入互操作、默认QoS、发现策略和厂商配置差异,现场排障成本更高。
5.3 组播连通性测试
ROS2提供ros2multicast命令用于测试两端之间UDP组播数据是否可达。官方文档给出的基本用法是在一台机器运行receive,在另一台机器运行send,成功时接收端会输出“HelloWorld!”。
机器A:
ros2 multicast receive
机器B:
ros2 multicast send
如果接收端没有输出,可以检查:
- 两台机器是否在同一局域网或组播可达网络中。
- 防火墙是否阻止UDP组播。
- 交换机是否启用IGMPSnooping且缺少Querier配置。
- Wi-FiAP是否隔离客户端或禁用组播转发。
- Docker、虚拟机、WSL或容器网络是否阻断组播。
5.4 Topic与QoS排查命令
# 查看Topic列表
ros2 topic list
# 查看Topic发布/订阅端与QoS
ros2 topic info /points_raw -v
# 尝试订阅数据
ros2 topic echo /points_raw
# 指定QoS可靠性订阅
ros2 topic echo /points_raw --qos-reliability best_effort
# 对TRANSIENT_LOCAL地图进行订阅
ros2 topic echo /map --qos-durability transient_local
排查时可以按以下顺序推进:
IP互通 -> ROS_DOMAIN_ID一致 -> RMW一致 -> 组播可达 -> Topic存在 -> 类型一致 -> QoS兼容 -> 应用回调执行 -> CPU/带宽/队列瓶颈
5.5 网络抓包观察RTPS
当命令层面无法解释问题时,可以用tcpdump或Wireshark观察RTPS报文。RTPS常见于UDP传输,端口会受Domain ID、Participant ID和DDS实现配置影响。抓包时不建议只盯固定端口,建议先观察主机间UDP流量,再结合Wireshark的RTPS解析器过滤。
# 抓取某个网卡上的UDP报文
sudo tcpdump -i eth0 udp -w ros2_rtps.pcap
# 限定目标主机,降低抓包噪声
sudo tcpdump -i eth0 host 192.168.1.20 and udp -w ros2_between_hosts.pcap
Wireshark中可以尝试使用以下过滤条件:
rtps
udp
ip.addr == 192.168.1.20
观察重点:
| 报文现象 | 可能原因 |
|---|---|
| 只有SPDP,没有SEDP | Participant发现成功,端点交换异常或被过滤 |
| 有发现报文,无用户数据 | Topic、类型或QoS不匹配 |
| 有大量ACK/NACK | RELIABLE链路丢包或订阅端处理不过来 |
| 报文只出不进 | 防火墙、路由、VLAN或组播转发问题 |
| 数据突发延迟 | 队列过深、重传积压、CPU或带宽瓶颈 |
5.6 容器与多网卡场景
工业部署经常将ROS2节点运行在Docker容器中,也经常存在多网卡:车载以太网、调试网口、5G路由、Wi-Fi、虚拟网桥同时存在。DDS自动选择网络接口时可能选错出口,导致节点在本机正常、多机异常。使用策略:
# Docker中优先使用host网络进行ROS2多机通信验证
docker run --rm -it --net=host ros:humble
对于CycloneDDS,可通过配置文件约束网络接口和Peer;对于FastDDS,可通过XML配置InitialPeers、接口白名单、Discovery Server等能力。正式项目应将DDS配置纳入版本管理,避免现场通过临时环境变量逐台修改。
示例:CycloneDDS单播Peer配置思路。
<CycloneDDS>
<Domain>
<General>
<Interfaces>
<NetworkInterface name="eth0"/>
</Interfaces>
</General>
<Discovery>
<Peers>
<Peer Address="192.168.1.10"/>
<Peer Address="192.168.1.20"/>
</Peers>
</Discovery>
</Domain>
</CycloneDDS>
export CYCLONEDDS_URI=file:///home/robot/cyclonedds.xml
该配置适用于组播不可用但主机IP固定的场景。对于动态IP或大规模部署,应结合服务发现服务器、路由器或上层编排系统进行治理。
6.常见故障与定位路径
6.1 两台机器互相ping通,但ros2 topic list看不到对方Topic
优先检查:
echo $ROS_DOMAIN_ID
echo $RMW_IMPLEMENTATION
ros2 multicast receive
ros2 multicast send
排查思路:
- 保证两端ROS_DOMAIN_ID一致。
- 暂时关闭防火墙验证问题边界。
- 使用有线网络替代Wi-Fi进行对比测试。
- Docker环境使用–net=host复现。
- 组播不可用时配置CycloneDDSPeers或FastDDSInitialPeers。
6.2 Topic可见,但echo没有数据
优先检查:
ros2 topic info /topic_name --verbose
ros2 interface show your_msgs/msg/Type
可能原因:
| 原因 | 说明 |
|---|---|
| QoS不兼容 | 最常见,尤其是BEST_EFFORT Publisher与RELIABLE Subscriber |
| 类型不一致 | Topic名称相同但消息类型不同 |
| 命名空间混乱 | Launch文件或remap导致实际Topic不同 |
| 发布频率过低 | echo期间没有新数据产生 |
| TRANSIENT_LOCAL误用 | 后加入节点没有按持久性策略订阅 |
6.3 高频点云或图像导致系统卡顿
定位路径:
ros2 topic hz /points_raw
ros2 topic bw /points_raw
top
htop
nload
iftop
调整思路:
- 将传感器流QoS从RELIABLE调整为BEST_EFFORT。
- 减小Depth,避免订阅端处理过期数据。
- 对图像使用压缩传输或硬件编码链路。
- 点云进行下采样、ROI裁剪或分通道发布。
- 记录rosbag时单独评估磁盘写入带宽。
- 将调试可视化链路与控制链路隔离。
6.4 部分机器可以通信,部分机器不可以
多机系统中应绘制网络矩阵:
| 源机器 | 目标机器 | ping | multicast | topic | 数据 |
|---|---|---|---|---|---|
| A | B | 通过 | 通过 | 可见 | 正常 |
| A | C | 通过 | 失败 | 不可见 | 无 |
| B | C | 通过 | 失败 | 不可见 | 无 |
通过这种表格可以快速判断问题位于系统配置、交换机策略、VLAN边界、防火墙或RMW配置层。
7.自动驾驶通信设计思路
7.1 按数据语义划分通信等级
自动驾驶系统中,所有Topic不应套用同一套QoS模板。可以按数据语义分级:
| 等级 | 数据 | 目标 | QoS倾向 |
|---|---|---|---|
| A级 | 制动、急停、模式切换、任务状态 | 降低丢失概率与状态不一致 | RELIABLE、较小Depth、应用层确认 |
| B级 | 定位、车辆状态、规划轨迹 | 保持连续性和较低延迟 | RELIABLE或BEST_EFFORT视频率选择 |
| C级 | 相机、点云、雷达、调试图像 | 保持实时性,容忍局部丢帧 | BEST_EFFORT、VOLATILE、小Depth |
| D级 | 地图、配置、标定、静态信息 | 后启动节点可恢复状态 | RELIABLE、TRANSIENT_LOCAL |
7.2 发现平面与数据平面分开治理
DDS通信可以分为发现平面和数据平面。发现平面负责节点、端点和QoS元数据交换;数据平面负责用户消息传输。多机系统常见问题来自二者混淆:发现成功不代表数据可达,Topic可见不代表QoS匹配,组播正常不代表单播数据链路无瓶颈。
在调试项目文档中可分别记录:
- 发现策略:SimpleDiscovery、StaticDiscovery、DiscoveryServer、Peers、DomainID。
- 数据链路:Topic频率、消息大小、QoS、网络接口、带宽预算。
- 故障边界:发现失败、匹配失败、传输失败、应用处理失败。
7.3 现场部署通信调试
部署自动驾驶时使用以下通信基线测试:
# 1.基础发现
ros2 multicast receive
ros2 multicast send
# 2.低频可靠Topic
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener
# 3.高频压力Topic
ros2 topic hz /camera/image_raw
ros2 topic bw /camera/image_raw
# 4.QoS核查
ros2 topic info /camera/image_raw --verbose
ros2 topic info /map --verbose
# 5.抓包留证
sudo tcpdump -i eth0 udp -w baseline_rtps.pcap
通信基线应随软件版本、RMW版本、DDS配置和网络拓扑一起归档。现场问题复现时,先对比基线,再修改配置。
ROS2通信架构的本质,是将系统从中心化命名与连接管理,推进到分布式数据空间与可配置通信质量模型。DDS为ROS2提供了自动发现、发布订阅、QoS、可靠传输、历史数据保留和多厂商实现基础;RMW层则让ROS2应用代码与底层中间件解耦,使工程项目可以在FastDDS、CycloneDDS、ConnextDDS、GurumDDS以及Zenoh等实现之间进行选择。
这种架构也带来了新的工程复杂度。ROS2多机通信问题经常发生在Domain ID、组播、防火墙、多网卡、Docker网络、QoS匹配和RMW默认行为之间。现场调试时可以按照分层排查思路:先验证IP与组播,再检查Domain与RMW,再确认Topic、类型与QoS,最后通过抓包、带宽和CPU监控定位性能瓶颈。
ROS2通信生态正在从单一DDS视角向更灵活的路由化、跨网段、云边协同方向发展。Zenoh、DDSRouter、DiscoveryServer、静态发现和共享内存传输等能力,会在自动驾驶车队、大规模机器人、工厂移动机器人和边缘计算系统中承担更重要角色。