Skip to main content

基于 ROS2 通信机制的局域网通信

目标: 基于 ROS2 通信机制设计并实现一个局域网通信系统,包括:

  1. 局域网广播通信(同一子网内所有机器互相发现)
  2. 点对点通信(精确隔离,仅指定机器之间互相发现)

教程级别: 中等

时间: 45 分钟


1. 什么是局域网通信

局域网(LAN, Local Area Network)指覆盖范围较小的计算机网络,例如学校机房、实验室或家庭网络,所有设备共享同一个 IP 子网(如 192.168.1.0/24)。

局域网内的通信主要有两种模式:

模式说明典型场景
广播(Broadcast)一台机器发送,局域网内所有机器均可收到服务发现、多机器人状态同步
点对点(Unicast / P2P)一台机器发送,只有指定的另一台机器能收到远程控制指令、隐私数据传输

在多机器人系统中,两种模式各有用途:广播适合"集群通知",点对点适合"一对一任务分配"或隔离秘密频道,避免其他机器人干扰。


2. 业界通常如何进行局域网通信

局域网通信有多种技术方案,以下是工业和学术界常见的几种:

方案底层协议是否需要中间件典型场景优缺点
UDP Socket 广播UDP Broadcast简单设备发现、游戏局域网简单快速,但不可靠,无连接管理
TCP SocketTCP文件传输、指令传输可靠,但需手写协议和发现机制
MQTTTCP + 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_cppeProsima FastDDSROS2 默认安装ROS2 Kilted 默认 RMW
rmw_cyclonedds_cppEclipse CycloneDDS需额外安装性能优秀
rmw_zenoh_cppZenohROS2 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

工作原理:

  1. 一台机器(机器 A)启动 Discovery Server 进程,监听指定端口。
  2. 其他机器设置 ROS_DISCOVERY_SERVER=<机器A的IP>:11811,只向该 Server 注册自己。
  3. 未注册到同一 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 Routerrmw_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 隔离性)
info

如果你只有两台机器,可以跳过机器 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 的终端显示收到消息,说明局域网多播正常,可以进行广播通信实验。

warning

如果 ros2 multicast receive 没有收到消息,原因通常是:

  • 防火墙阻断了 UDP 多播(sudo ufw disable 临时关闭测试)
  • 路由器禁止多播(更换交换机直连或同一交换机下的机器)
  • 网络接口不同(机器有多块网卡时,用 ros2 multicast send --transient 指定接口)

步骤 4:检查当前 ROS2 环境变量

在每台机器上运行:

printenv | grep -i ROS

确保没有残留的旧 ROS_DOMAIN_IDROS_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"
tip

将此脚本放在家目录 ~/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. 拓展思考

  1. 如果用 ROS2 的通信机制实现一个"聊天群",需要哪些功能?

    提示:分析聊天群的核心需求——

    • 群消息广播:一个用户发送,所有人收到 → 对应 广播话题ros2 topic pub),所有人订阅同一话题。
    • 私信(私聊):只有指定用户看到 → 对应 Discovery Server 隔离 + 独立话题,或使用 Service(一对一请求/响应)。
    • 用户列表:知道当前在线的用户 → 对应 ros2 node list,每个用户对应一个节点。
    • 离线消息:用户离线时消息不丢失 → ROS2 原生不支持,需配合 QoS Durability = Transient Local 实现有限缓存。
  2. 仅依靠 ROS2 能否完整实现聊天群?其局限性是什么?

    提示:

    • 能实现的部分:节点发现、话题广播、服务调用、QoS 控制,这些构成了"通信机制"本身。
    • 难以实现的部分
      • 用户身份认证(ROS2 无内置用户系统,节点名易伪造)
      • 消息持久化存储(ros2 bag 可记录但不是实时的聊天数据库)
      • 跨 NAT/互联网通信(ROS2 默认不跨公网)
      • 丰富的前端界面(ROS2 是后端通信框架)
    • 结论:ROS2 可以实现局域网内的"聊天群原型",但替代不了 XMPP、Matrix 等成熟即时通信协议。在机器人系统中,ROS2 的通信机制更适合作为"机器人间的指令通道",而非通用聊天系统。

9. 课程总结与作业

总结

对比项广播通信(SUBNET 模式)点对点通信(Discovery Server 模式)
关键环境变量ROS_AUTOMATIC_DISCOVERY_RANGE=SUBNETROS_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