基于 ROS2 通信机制的局域网通信
目标: 基于 ROS2 通信机制设计并实现一个局域网通信系统,包括:
- 局域网广播通信(同一子网内所有机器互相发现)
- 点对点通信(精确隔离,仅指定机器之间互相发现)
教程级别: 中等
时间: 45 分钟
1. 什么是局域网通信
局域网(LAN, Local Area Network)指覆盖范围较小的计算机网络,例如学校机房、实验室或家庭网络,所有设备共享同一个 IP 子网(如 192.168.1.0/24)。
局域网内的通信主要有两种模式:
| 模式 | 说明 | 典型场景 |
|---|---|---|
| 广播(Broadcast) | 一台机器发送,局域网内所有机器均可收到 | 服务发现、多机器人状态同步 |
| 点对点(Unicast / P2P) | 一台机器发送,只有指定的另一台机器能收到 | 远程控制指令、隐私数据传输 |
在多机器人系统中,两种模式各有用途:广播适合"集群通知",点对点适合"一对一任务分配"或隔离秘密频道,避免其他机器人干扰。
2. 业界通常如何进行局域网通信
局域网通信有多种技术方案,以下是工业和学术界常见的几种:
| 方案 | 底层协议 | 是否需要中间件 | 典型场景 | 优缺点 |
|---|---|---|---|---|
| UDP Socket 广播 | UDP Broadcast | 否 | 简单设备发现、游戏局域网 | 简单快速,但不可靠,无连接管理 |
| TCP Socket | TCP | 否 | 文件传输、指令传输 | 可靠,但需手写协议和发现机制 |
| MQTT | TCP + Broker | 需 Broker 进程 | IoT 设备消息分发 | 轻量,但需独立 Broker,单点故障风险 |
| DDS(ROS2 底层) | UDP Multicast/Unicast | 需 RMW 中间件 | 机器人分布式系统 | 自动发现、QoS 丰富,与 ROS2 原生集成 |
ROS2 基于 DDS(Data Distribution Service) 标准构建通信层,因此它天然支持局域网通信,只需配置少量环境变量即可实现广播和点对点两种模式,无需手写 Socket 代码。
3. ROS2 实现局域网通信的基本思路
3.1 DDS 中间件简介
DDS 是一套"以数据为中心"的发布/订阅通信标准。ROS2 通过 RMW(ROS Middleware) 层抽象出不同的 DDS 实现,目前内置支持以下几种:
| RMW 实现 | DDS 实现 | 安装方式 | 备注 |
|---|---|---|---|
rmw_fastrtps_cpp | eProsima FastDDS | ROS2 默认安装 | ROS2 Kilted 默认 RMW |
rmw_cyclonedds_cpp | Eclipse CycloneDDS | 需额外安装 | 性能优秀 |
rmw_zenoh_cpp | Zenoh | ROS2 Kilted 内置 | 新协议,跨网络友好 |
3.2 广播通信:ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET
ROS2 默认仅在本机(localhost)范围内做 DDS 发现。要打开局域网广播,需要设置两个环境变量:
export ROS_DOMAIN_ID=42 # 逻辑隔离 ID,同一局域网内相同才能互通
export ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET # 将发现范围扩展到整个子网
ROS_DOMAIN_ID:取值 0–232,相当于"频道编号",不同 ID 的节点互相不可见。ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET:启用 DDS 多播(Multicast),局域网内所有设置了相同DOMAIN_ID的节点自动互相发现,无需知道对方 IP。
3.3 点对点通信:FastDDS Discovery Server
默认的 DDS 广播发现意味着局域网内任何人都能看到你的节点。当需要精确控制哪些机器之间可以互相通信时,可以使用 FastDDS Discovery Server。
工作原理:
- 一台机器(机器 A)启动 Discovery Server 进程,监听指定端口。
- 其他机器设置
ROS_DISCOVERY_SERVER=<机器A的IP>:11811,只向该 Server 注册自己。 - 未注册到同一 Server 的机器无法发现这些节点,实现物理隔离。
# 机器A:指向本机 Server
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DISCOVERY_SERVER="127.0.0.1:11811"
# 机器B:指向机器A的 Server
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DISCOVERY_SERVER="192.168.1.100:11811"
3.4 四种 P2P 方案横向对比
ROS2 生态中实现点对点/隔离发现有以下几种方案,供参考:
| 方案 | RMW 要求 | 额外进程 | 配置方式 | CLI 友好度 |
|---|---|---|---|---|
| FastDDS Discovery Server(本课选用) | rmw_fastrtps_cpp(默认) | 需要 1 个 Server 进程 | ROS_DISCOVERY_SERVER | ★★★★ |
| ROS_STATIC_PEERS | 与 RMW 无关 | 不需要 | 环境变量 | ★★★★★ |
| CycloneDDS Unicast 配置 | rmw_cyclonedds_cpp | 不需要 | XML 文件 | ★★★ |
| Zenoh Router | rmw_zenoh_cpp | 需要 1 个 Router 进程 | 自动 | ★★★★ |
本课程选用 FastDDS Discovery Server,因为它是官方文档最完整的方案,且使用 ROS2 默认 RMW,无需额外安装。
4. 实验:局域网通信
4.1 实验准备
实验架构:
局域网 192.168.1.0/24
│
├── 机器A 192.168.1.100 ← 广播发布者 / P2P Discovery Server
├── 机器B 192.168.1.101 ← 广播订阅者 / P2P 客户端
└── 机器C 192.168.1.102 ← 旁观者(用于验证 P2P 隔离性)
如果你只有两台机器,可以跳过机器 C 的隔离验证步骤,或用单机的两个终端模拟广播实验。
步骤 1:验证三台机器在同一子网
在每台机器上运行:
ip addr show | grep "inet "
确认三台机器的 IP 均在 192.168.1.x 段,子网掩码 /24。
步骤 2:测试网络连通性
从机器 B ping 机器 A:
ping -c 4 192.168.1.100
从机器 C ping 机器 A:
ping -c 4 192.168.1.100
全部 ping 通后再继续。
步骤 3:验证多播可达(广播实验前置条件)
在机器 B 开一个终端,等待接收多播包:
source /opt/ros/kilted/setup.bash
ros2 multicast receive
在机器 A 开一个终端,发送多播包:
source /opt/ros/kilted/setup.bash
ros2 multicast send
如果机器 B 的终端显示收到消息,说明局域网多播正常,可以进行广播通信实验。
如果 ros2 multicast receive 没有收到消息,原因通常是:
- 防火墙阻断了 UDP 多播(
sudo ufw disable临时关闭测试) - 路由器禁止多播(更换交换机直连或同一交换机下的机器)
- 网络接口不同(机器有多块网卡时,用
ros2 multicast send --transient指定接口)
步骤 4:检查当前 ROS2 环境变量
在每台机器上运行:
printenv | grep -i ROS
确保没有残留的旧 ROS_DOMAIN_ID、ROS_DISCOVERY_SERVER 变量。如有,重新开一个终端或用 unset 清除。
4.2 广播通信实验
广播通信让局域网内所有机器都能互相发现和订阅话题,无需知道对方 IP。
步骤 1:创建广播环境配置脚本
在每台机器上创建文件 setup_broadcast.sh,内容如下:
#!/usr/bin/env bash
source /opt/ros/kilted/setup.bash
export ROS_DOMAIN_ID=42
export ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET
echo "[广播模式] DOMAIN_ID=$ROS_DOMAIN_ID RANGE=$ROS_AUTOMATIC_DISCOVERY_RANGE"
将此脚本放在家目录 ~/setup_broadcast.sh,每次实验时用 source ~/setup_broadcast.sh 载入当前终端,不要直接执行(./setup_broadcast.sh),否则 export 的变量不会保留在当前 shell 中。
步骤 2:两台机器分别 source 配置脚本
机器 A 和 机器 B 各开一个终端:
source ~/setup_broadcast.sh
步骤 3:机器 A 发布广播话题
ros2 topic pub /lan_broadcast std_msgs/msg/String \
'{data: "Hello from Machine-A!"}' \
--rate 1
步骤 4:机器 B 订阅广播话题
ros2 topic echo /lan_broadcast
成功时,机器 B 终端会每秒打印一条消息:
data: Hello from Machine-A!
---
data: Hello from Machine-A!
---
步骤 5:验证节点互相可见
在机器 B 运行:
ros2 node list
ros2 topic list
ros2 topic hz /lan_broadcast
ros2 node list 应同时列出机器 A 和 机器 B 的匿名节点;ros2 topic hz 应显示约 1 Hz 的频率。
步骤 6(可选):机器 C 验证广播可接收
机器 C 同样 source setup_broadcast.sh 后运行:
ros2 topic echo /lan_broadcast
机器 C 也能收到消息,说明广播对整个子网开放。
4.3 点对点通信(FastDDS Discovery Server)
点对点通信让只有连接到同一 Discovery Server 的机器才能互相发现,机器 C 虽在同一局域网,但不向该 Server 注册,因此无法看到 A/B 的节点。
步骤 1:机器 A 启动 Discovery Server
在机器 A 新开一个专用终端,运行:
source /opt/ros/kilted/setup.bash
fastdds discovery -i 0 -l 0.0.0.0 -p 11811
参数说明:
-i 0:Server ID,从 0 开始编号-l 0.0.0.0:监听所有网络接口(局域网可达)-p 11811:监听端口(默认端口,可自定义)
成功后终端会持续打印 Server 运行日志,保持此终端开启。
步骤 2:创建 P2P 配置脚本
在机器 A 创建 setup_p2p_server.sh:
#!/usr/bin/env bash
source /opt/ros/kilted/setup.bash
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DISCOVERY_SERVER="127.0.0.1:11811"
export ROS_DOMAIN_ID=42
echo "[P2P 服务端模式] SERVER=$ROS_DISCOVERY_SERVER"
在机器 B 创建 setup_p2p_client.sh(接受一个参数:服务端 IP):
#!/usr/bin/env bash
# 用法: source setup_p2p_client.sh <SERVER_IP>
if [ -z "$1" ]; then
echo "用法: source setup_p2p_client.sh <SERVER_IP>"
return 1
fi
source /opt/ros/kilted/setup.bash
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DISCOVERY_SERVER="${1}:11811"
export ROS_DOMAIN_ID=42
echo "[P2P 客户端模式] SERVER=$ROS_DISCOVERY_SERVER"
步骤 3:机器 A 和 机器 B 分别 source P2P 脚本
机器 A(新终端,不是运行 fastdds 的那个):
source ~/setup_p2p_server.sh
机器 B:
source ~/setup_p2p_client.sh 192.168.1.100
步骤 4:机器 A 发布 P2P 话题
ros2 topic pub /p2p_channel std_msgs/msg/String \
'{data: "Private message to Bot-B"}' \
--rate 1
步骤 5:机器 B 订阅 P2P 话题
ros2 topic echo /p2p_channel
成功时,机器 B 收到消息:
data: Private message to Bot-B
---
步骤 6:机器 C 验证隔离性
机器 C 不 source P2P 脚本,保持原有广播模式(或仅 source ROS2 环境不加 ROS_DISCOVERY_SERVER):
source /opt/ros/kilted/setup.bash
export ROS_DOMAIN_ID=42
export ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET
ros2 node list
机器 C 的 ros2 node list 不显示机器 A 和 机器 B 的节点(虽然机器 C 和 A/B 在同一局域网,Domain ID 也相同),说明 Discovery Server 成功隔离了节点发现。
步骤 7:ros2 service call 跨机测试(扩展)
确认 P2P 连接后,还可以在机器 B 调用机器 A 上由 turtlesim 等提供的服务,进一步验证 P2P 的双向通信能力:
# 机器A 开一个终端(source P2P 脚本后)
ros2 run turtlesim turtlesim_node
# 机器B 查看跨机服务列表
ros2 service list
# 机器B 调用服务
ros2 service call /clear std_srvs/srv/Empty {}
8. 拓展思考
- 如果用 ROS2 的通信机制实现一个"聊天群",需要哪些功能?
受保护的内容
请输入密码以查看此内容
- 仅依靠 ROS2 能否完整实现聊天群?其局限性是什么?
受保护的内容
请输入密码以查看此内容
9. 课程总结与作业
总结
| 对比项 | 广播通信(SUBNET 模式) | 点对点通信(Discovery Server 模式) |
|---|---|---|
| 关键环境变量 | ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNET | ROS_DISCOVERY_SERVER=<IP>:<PORT> |
| 节点发现方式 | DDS 多播,自动广播 | 集中注册,按需发现 |
| 是否需要额外进程 | 否 | 是(fastdds discovery) |
| 隔离性 | 弱(同 Domain ID 均可见) | 强(未注册 Server 则不可见) |
| 配置复杂度 | 低 | 中 |
| 典型用途 | 多机器人状态共享、调试 | 隐私通道、定向控制 |
两种模式可以共存:在同一个系统中,部分节点走广播(状态广播),部分节点走 Discovery Server(控制通道),按需选择。
作业
作业 1(必做):三机广播通信
在 3 台机器上配置广播通信,使机器 A 发布 /team_status 话题,机器 B 和 机器 C 同时订阅并接收消息。
提交内容:
- 三台机器上
printenv | grep -i ROS的截图(证明环境变量配置正确) - 机器 B 和 机器 C 上
ros2 topic echo /team_status的截图 - 在机器 B 上运行
ros2 topic hz /team_status的截图
作业 2(必做):P2P 通信与隔离验证
配置机器 A 和 机器 B 进行 P2P 通信,同时验证机器 C 无法发现 A/B 的节点。
提交内容:
- 机器 A 上
fastdds discovery运行截图 - 机器 B 上
ros2 topic echo /p2p_channel收到消息的截图 - 机器 C 上
ros2 node list输出为空(或不含 A/B 节点)的截图,并附上机器 C 当时的环境变量截图证明它确实在同一局域网和相同ROS_DOMAIN_ID