ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ROS2 多机消息串扰隔离方案教程

ROS2 多机消息串扰隔离方案教程

适用场景:多架无人机机载电脑连接同一局域网(如 192.168.144.x)时,机内 ROS2 消息互相串扰。 方案:ROS_LOCALHOST_ONLY=1,让每架飞机的 ROS2 成为 "本机私有图"。


1. 背景与问题

1.1 现象

  • 两架飞机(A、B)的机载电脑连接同一个网络时:
    • 地面站发给 A 的任务,B 也会执行;
    • A 的无人机状态 / 遥测,地面站会显示到 B 名下(或反之)。
  • 序列号(SN)不同,但消息仍然串。

1.2 根因

消息链路分为两段:

表格

机制是否按 SN 隔离
MQTT(地面站 ⇄ 机载)TCP 直连 broker(xx.xxx.xxx.xxx),按/{SN}/xxx主题收发✅ 已隔离,没问题
ROS2(机内话题/ros2/*/mavros/*DDS 默认走网卡组播,同一网段所有机器互通❌ 未隔离,串的原因

一句话:MQTT 按序列号分了家,但机内 ROS2 话题是固定名,DDS 广播让同网络的飞机互相听得到。

1.3 结论

只需隔离 ROS2 一层即可。MQTT、TCP(图传 / 云台)、MAVLink(飞控 / 地面站)、网段全部不受影响。


2. 方案 A 原理

2.1 是什么

ROS_LOCALHOST_ONLY=1是 ROS2(Foxy 及以上,含 Humble)官方的环境变量开关,作用:让 DDS 只使用本机回环接口127.0.0.1,消息不出网卡。

  • 127.0.0.1 永远只代表 "本机自己",任何其他电脑都无法通过它收到消息;
  • 设置后:A 机 ROS2 消息只在 A 机电脑内传播,B 机物理上收不到→ 不可能串。本质:ROS2 的通信协议 DDS 天生是为 "跨机器分布式通信" 设计的 —— 默认通过网卡组播在局域网里互相发现、互相收发。这个设置的本质,是把 DDS 绑定的网络接口从 "网卡" 换成 " 内核回环127.0.0.1",把 ROS2 通信从" 跨机网络通信 "降级为" 单机进程间通信 "。 | 维度 | 默认状态 | 设置后 | |---|---|---| | DDS 绑定的网络接口 | 物理网卡(192.168.144.x) | 回环接口(127.0.0.1) | | 报文走的路 | 网卡 → 交换机 → 局域网其他设备 | 内核回环路径,不出物理网卡 | | 通信能力 | 跨机分布式通信(DDS 的本职) | 只剩单机进程间通信 | | 能发现谁 | 同网段所有 ROS2 节点 | 只有本机节点 | 一句话:DDS 是分布式协议,默认 "联网";这个开关把它的联网能力关掉了,让它退化成本机专用,其他设备物理上无法参与。

2.2 生效前提(本项目全部满足)

  1. 每架飞机所有 ROS2 节点运行在同一台电脑上(本项目所有节点均部署在机载电脑,由 systemd 统一管理)✅
  2. 每架飞机 MQTT 配置独立UAV_SNmqtt_client_ID各机不同(MQTT 层本来就不串,靠此保证)✅
  3. 无跨机 ROS2 通信需求(当前跨机只有 MQTT 和 TCP)✅

2.3 隔离是双向的、物理强制的(不依赖别人是否设置)

  • 只要你这架飞机设置了,不管其他飞机设置与否,你的 ROS2 消息只在自己电脑内部传播,消息不出你的网卡 → 其他飞机收不到你的消息
  • 同理,你也收不到其他飞机的消息(你的 DDS 只在127.0.0.1收发,到达你网卡的 DDS 报文直接不处理);
  • 注意:隔离是 "各管各的"——A 设置了,A 与任何人都不串;但B、C 若都没设置,它们之间照样会串。建议所有飞机统一设置
A机(已设置) B机(没设置) ROS2 ──只在127.0.0.1──> 消息不出网卡 ──╳──> 收不到A的消息 B自己的ROS2 ──走网卡广播──> 局域网收到 ──> A机网卡收到 但A的DDS只在127.0.0.1监听,不处理

3. 实施步骤(每架飞机都要执行)

3.1 创建 systemd 全局环境变量配置(核心,1 步)

运行

sudo mkdir -p /etc/systemd/system.conf.d sudo tee /etc/systemd/system.conf.d/ros_localhost.conf <<'EOF' [Manager] DefaultEnvironment="ROS_LOCALHOST_ONLY=1" EOF

为什么放在/etc/systemd/system.conf.d/

位置会被 OTA 覆盖吗结论
.service文件(/etc/systemd/system/✅ 会(update.sh 同步)不能放
script/*.sh/home/cat/ros2_ws/script/✅ 会(update.sh 同步)不能放
/etc/systemd/system.conf.d/❌ 不会放这里

此配置对所有 systemd 服务生效(含以后 OTA 新部署的服务),永久有效。

3.2 (可选但建议)让手动敲的 ros2 命令也带上变量

运行

echo 'export ROS_LOCALHOST_ONLY=1' | sudo tee /etc/profile.d/ros_localhost.sh

配完重新登录 / 重新 ssh生效。不配也能用,但手动验证时结果会不准。

3.3 重载并重启

运行

sudo systemctl daemon-reload sudo reboot

注意:reboot会重启飞机,请确认飞机不在飞行状态、允许重启时再执行。

3.4 检查配置是否生效(无需重启即可查)

运行

systemctl show-environment | grep ROS
  • 看到ROS_LOCALHOST_ONLY=1→ 配置已生效;
  • 看不到 → 检查 3.1 的文件内容是否正确。

4. 验证(关键,两架飞机都要做)

4.1 设置前(可选,用于确认问题存在)

运行

ros2 node list
  • 能看到对方飞机的节点(如对方的ros2_sdk_node)→ 确认存在串扰。

4.2 设置后

运行

ros2 node list
  • 只能看到自己飞机上的节点→ 隔离成功;
  • 还能看到对方节点 → 见 "FAQ" 排查。

4.3 交叉验证(端到端)

  1. 地面站给 B 机发送一条任务;
  2. 确认 A 机不执行
  3. 再给 A 机发送任务,确认 A 正常执行、B 无反应。

4.4 验证注意事项

  • 手动终端必须带变量:重新登录后执行,或先export ROS_LOCALHOST_ONLY=1再执行;
  • ros2 daemon stop可清除 CLI 后台缓存后再验证。

5. 回退方法(随时可还原)

运行

# 1. 删除配置 sudo rm /etc/systemd/system.conf.d/ros_localhost.conf sudo rm /etc/profile.d/ros_localhost.sh # 如果配了 3.2 # 2. 重载并重启 sudo systemctl daemon-reload sudo reboot

回退后即恢复原状(ROS2 恢复走网卡,串扰问题会回来,其他功能不受影响)。


6. 持久性与 OTA 更新

6.1 每次开机

systemd 每次开机都会重新读取/etc/systemd/system.conf.d/*.conf,把DefaultEnvironment应用到所有服务。配置一次,每次开机生效。

6.2 OTA 更新(update.sh 实际覆盖范围)

目录update.sh 行为本方案配置
/etc/systemd/system/*.service从发布包复制覆盖不受影响
/home/cat/ros2_ws/script/同步覆盖不受影响
/home/cat/ros2_ws/config/只加新文件,不覆盖已有不受影响
/home/cat/ros2_ws/install/整体替换不受影响
/etc/systemd/system.conf.d/完全不碰✅ 永久保留
/etc/profile.d/完全不碰✅ 永久保留

OTA 更新的标准收尾就是 "重启以加载新版本",重启时方案 A 自然生效,无需额外操作。


7. 影响范围与注意事项

7.1 影响范围

通信走什么受影响吗
ROS2 话题(/ros2/*/mavros/*之前走网卡组播✅ 改走本机 127.0.0.1
MQTT(地面站 xx.xxx.xxx.xxx)TCP 网卡❌ 照常
TCP(图传 / 云台)TCP 127.0.0.1❌ 照常
MAVLink(飞控串口 / 地面站 UDP)串口 / UDP❌ 照常
网段 / IP / 路由器(192.168.144.x)网络层❌ 完全不动
非 ROS2 服务(ZLMediaKit、frpc 等)❌ 无影响(不读该变量)

7.2 注意事项

  1. 不要在.service文件中显式设置Environment=ROS_LOCALHOST_ONLY=0等,会覆盖默认值(目前现有 service 均未设置,无冲突);
  2. 已知边界:机上 ROS2无法与外部机器 DDS 通信(当前架构无此需求;MQTT/TCP 跨机通道不受影响);
  3. 若某架飞机由两台电脑分别跑 ROS2 节点,它们之间会断开(本项目每架一台机载,不适用)。

8. FAQ

Q1:为什么不用 ROS_DOMAIN_ID?有效范围只有 0~232,同网段必须全局唯一,机队规模大时无法分配,运维成本高。

Q2:为什么不用 namespace(话题带 SN)?改动面大(10+ 文件:SDK、桥、mavros、tcp、launch 等),漏改一处会导致本机功能断裂或残留串扰,且单机测不出来,需双机联调。方案 A 一行配置即达到等价效果,且无漏改风险。

Q3:验证时还能看到对方节点?按顺序排查:

  1. 确认终端带了变量:export ROS_LOCALHOST_ONLY=1后重试;
  2. 确认systemctl show-environment | grep ROS有输出;
  3. 确认 3.1 的文件内容无误后sudo systemctl daemon-reload并重启相关服务。
  4. Q4:会串进别的网络吗?不会。该方案仅影响本机 ROS2 的通信接口选择,不改变任何网络配置。
  5. Q5:以后想恢复多机 ROS2 互通信怎么办?删除 3.1 的配置文件并重启即可恢复;或改用 namespace 方案(另议)。
  6. Q6:其他飞机没设置,会收到我的消息吗?不会。只要你设置了,你的消息不出自己网卡,物理上到不了任何其他飞机,与对方是否设置无关(详见 2.3)。但若对方也没设置,它仍会与其他同样没设置的飞机互串,所以建议全机队统一设置。
返回列表