ROS 跨机通信与 Docker 多机环境搭建笔记
一、跨机通信概述
- 在无人驾驶、大型服务机器人等场景中,ROS 常运行在多台计算设备上,协作完成任务。
- ROS 支持分布式计算 ,但整个分布式系统中只有一个 Master 节点。
- 所有节点通过将
ROS_MASTER_URI指向 Master 所在设备进行通信。 - 需要通过设置
ROS_HOSTNAME和ROS_MASTER_URI(可添加到~/.bashrc中)来配置网络。
二、创建多机环境(以 Docker 为例)
- 创建 Docker 环境
- 在 Docker 容器中启动 Master
- 在宿主机上启动小海龟(turtlesim)节点
三、Dockerfile 示例(ROS Noetic)
在 catkin_ws/docker/ 下创建 Dockerfile:
dockerfile
FROM ros:noetic-ros-base-focal
RUN apt-get update && apt-get install -y --no-install-recommends \
ros-noetic-robot=1.5.0-1* \
&& rm -rf /var/lib/apt/lists/*
EXPOSE 11311
四、Docker 命令操作
bash
cd docker
# 构建镜像
sudo docker build -t ros:robot .
# 启动并进入容器
sudo docker run -ti ros:robot /bin/bash
# 在容器中安装网络工具
sudo apt update
sudo apt install net-tools lsof
# 启动已有容器
sudo docker start <container_id>
# 进入已启动容器
sudo docker attach <container_id>
五、容器内操作(启动 Master)
bash
# 加载 ROS 环境
source /opt/ros/noetic/setup.bash
# 启动 roscore 后台运行
roscore &
# 查看 11311 端口占用情况
lsof -i:11311
示例输出:
rosmaster 455 root 4u IPv4 *:11311 (LISTEN)
rosmaster 455 root 7u TCP ... (ESTABLISHED)
rosout 465 root 3u TCP ... (ESTABLISHED)
六、宿主机配置与通信
- 编辑
~/.bashrc,添加以下内容:
bash
export ROS_HOSTNAME=docker_ros
export ROS_MASTER_URI=http://docker_ros:11311
export TURTLEBOT3_MODEL=burger
-
注意:
ROS_HOSTNAME必须设置为容器的主机名或可解析的地址(如docker_ros),否则可能出现通信失败,例如:ping node http://docker_ros:43575/ ... failed!
七、注意事项
- 确保宿主机能解析
docker_ros主机名(可通过/etc/hosts或 Docker 网络配置)。 - 容器和宿主机之间网络互通是 ROS 多机通信的基础。
- Master 启动后,其他节点需通过
ROS_MASTER_URI指向正确的 IP 和端口(默认 11311)。
八、通信失败排查记录
1. 错误现象
在宿主机上启动小海龟节点后,出现如下错误:
ping node http://docker_ros:43575/ ... failed!
Communication with node[http://docker_ros:43575/] failed!
即使已在 /etc/hosts 中添加了容器 IP 与主机名的映射(如 172.17.0.2 docker_ros),仍然报错:
contacting node http://docker_ros:41171/ ... failed!
这表明宿主机虽然能解析主机名,但 ROS 节点之间的通信仍然失败。
2. 常见原因
- 容器内
roscore启动时监听了127.0.0.1,未监听容器外部 IP。 - 容器内节点注册的
ROS_HOSTNAME或ROS_IP设置不当,导致发布的 URI 无法被宿主机访问。 - 防火墙或网络策略阻止了端口访问(默认 11311)。
- 容器内
ROS_MASTER_URI指向错误(例如仍指向localhost,而宿主机需指向容器 IP)。
九、解决方案
方案一:使用容器 IP 直接通信(推荐)
-
在容器内设置 ROS_IP 为容器 IP
进入容器后,执行:
bashexport ROS_IP=172.17.0.2 # 替换为容器实际 IP或写入
~/.bashrc以便持久化。 -
在宿主机设置 ROS_MASTER_URI 为容器 IP
bashexport ROS_MASTER_URI=http://172.17.0.2:11311注意:此时宿主机不需要设置
ROS_HOSTNAME(或可注释掉)。 -
验证连通性
宿主机上:
bashping 172.17.0.2 telnet 172.17.0.2 11311 # 检查端口是否可达
方案二:使用主机名并确保双向解析
-
宿主机 hosts 文件(已做):
172.17.0.2 docker_ros -
容器内 hosts 文件 :
需要确保容器内也能解析
docker_ros为自身 IP。可在启动容器时添加--add-host参数:bashsudo docker run -ti --add-host docker_ros:172.17.0.2 ros:robot /bin/bash或在容器内手动编辑
/etc/hosts。 -
容器内设置 ROS_HOSTNAME:
bashexport ROS_HOSTNAME=docker_ros同时确保
ROS_MASTER_URI指向docker_ros:11311。 -
检查 roscore 监听地址 :
roscore 默认监听
0.0.0.0(所有接口),若启动时出现异常,可手动指定:bashroscore -p 11311 &或使用环境变量
ROS_IP覆盖。
方案三:使用 Docker 主机网络模式(最简单)
启动容器时使用 --net=host,使容器直接使用宿主机网络栈,此时 IP 就是宿主机 IP,配置最简单。
bash
sudo docker run -ti --net=host ros:robot /bin/bash
容器内:
bash
export ROS_MASTER_URI=http://localhost:11311
export ROS_HOSTNAME=localhost # 或宿主机实际 IP
roscore &
宿主机:
bash
export ROS_MASTER_URI=http://127.0.0.1:11311
# 启动小海龟节点
rosrun turtlesim turtlesim_node
十、调试命令汇总
| 目的 | 命令 |
|---|---|
| 查看容器 IP | ip addr show 或 hostname -I |
| 测试网络连通性 | ping docker_ros |
| 测试端口是否监听 | lsof -i:11311(容器内) |
| 查看节点注册信息 | rosnode list 和 rosnode info <node> |
| 查看环境变量 | `env |
| 临时设置环境变量 | export VAR=value |
| 编辑 hosts 文件 | sudo vim /etc/hosts(宿主机) 容器内需有权限或启动时指定 --add-host |
十一、注意事项
- 每次修改环境变量后需重新加载:
source ~/.bashrc或重新打开终端。 - 容器内若使用
sudo启动 roscore,可能导致环境变量丢失,建议直接以 root 运行。 - 若使用
docker run -ti启动容器后直接执行roscore,终端会被占用,可加&后台运行,或另开终端进入容器。 - 检查防火墙:
sudo ufw status,若开启则允许 11311 端口。
十二、支持用命令
- 查看文件内容:
cat ~/.bashrc或gedit ~/.bashrc - 查看 hosts 文件:
cat /etc/hosts
通过以上步骤,就能够解决跨机通信失败的问题,顺利实现 Docker 容器与宿主机之间的 ROS 节点通信。
完整的实践流程
一个完整的、可直接操作的配置流程,实现宿主机启动小海龟界面,Docker容器内用键盘控制它运动。
Phase 3: 数据传输
Phase 2: 连接协商
Phase 1: 节点注册
- XML-RPC
注册发布者 2. XML-RPC
注册订阅者 3. XML-RPC
请求发布者信息 4. XML-RPC
返回发布者地址 5. TCP
请求建立连接 6. TCP
确认连接 7. TCP/UDP
发布速度指令 键盘节点
容器内
roscore
Master
小海龟节点
宿主机
宿主机 ↔ Docker容器 ROS通信完整配置流程
一、整体架构说明
| 角色 | 位置 | 运行内容 | IP/主机名 |
|---|---|---|---|
| Master + 控制节点 | Docker容器内 | roscore + 键盘控制节点 (turtle_teleop_key) |
容器IP:172.17.0.2(示例) |
| 显示节点 | 宿主机 | 小海龟界面 (turtlesim_node) |
宿主机IP:192.168.x.x |
通信方向:容器内的键盘节点发布速度话题 → 宿主机的小海龟节点订阅并执行
二、详细配置步骤
步骤1:构建ROS Docker镜像(已完成可跳过)
如果你之前已经构建了镜像,可以直接使用;如果没有,执行:
bash
cd ~/catkin_ws/docker
sudo docker build -t ros:robot .
步骤2:启动容器并配置网络(关键!)
这里必须使用 host 网络模式,否则通信会非常麻烦:
bash
# 使用host网络模式启动容器
sudo docker run -it --net=host \
--name=ros_master \
ros:robot \
/bin/bash
为什么用host模式:容器直接使用宿主机的网络栈,IP就是宿主机IP,避免了复杂的网络配置和通信失败问题。
步骤3:容器内启动 roscore
进入容器后:
bash
# 加载ROS环境
source /opt/ros/noetic/setup.bash
# 启动roscore(默认监听所有接口)
roscore &
验证roscore是否正常运行:
bash
# 查看11311端口监听状态
lsof -i:11311
应该看到 rosmaster 监听 *:11311(表示监听所有网络接口)。
步骤4:宿主机配置环境变量
新开一个终端 (不要用容器内的),编辑 ~/.bashrc:
bash
gedit ~/.bashrc
在文件末尾添加:
bash
# ROS多机通信配置
export ROS_MASTER_URI=http://127.0.0.1:11311
# 注意:不需要设置ROS_HOSTNAME,使用IP通信最稳定
保存后生效:
bash
source ~/.bashrc
步骤5:宿主机启动小海龟界面
bash
# 启动小海龟节点(会自动连接容器内的master)
rosrun turtlesim turtlesim_node
如果成功,会弹出蓝色背景的小海龟窗口。
步骤6:容器内启动键盘控制节点
回到容器内的终端,启动键盘控制:
bash
# 确保已经source过
source /opt/ros/noetic/setup.bash
# 启动键盘控制节点
rosrun turtlesim turtle_teleop_key
步骤7:开始控制
- 鼠标点击键盘控制节点的终端窗口使其获得焦点
- 使用键盘的方向键(↑↓←→)控制小海龟移动
- 你应该能看到宿主机窗口中的小海龟随之移动
三、如果通信失败?排查指南
现象1:宿主机启动小海龟时报错
ERROR: Unable to communicate with master ...
解决方法:
bash
# 检查容器内roscore是否真的在运行
# 在容器内执行:
ps aux | grep roscore
# 检查端口是否可达(在宿主机执行):
telnet 127.0.0.1 11311
现象2:节点都能启动,但键盘控制无效
解决方法:
bash
# 1. 查看话题列表(容器内执行)
rostopic list
# 应该能看到 /turtle1/cmd_vel
# 2. 查看话题发布者(容器内执行)
rostopic info /turtle1/cmd_vel
# 应该显示有一个发布者(键盘节点)
# 3. 查看话题订阅者(宿主机新开终端执行)
rostopic info /turtle1/cmd_vel
# 应该显示有一个订阅者(turtlesim节点)
现象3:使用非host网络模式时的配置(备选方案)
如果你必须使用bridge模式,需要额外配置:
- 容器内:
bash
# 查看容器IP
ip addr show
# 假设是 172.17.0.2
# 设置环境变量
export ROS_IP=172.17.0.2
export ROS_MASTER_URI=http://172.17.0.2:11311
- 宿主机:
bash
# 编辑/etc/hosts,添加:
172.17.0.2 docker_ros
# 设置环境变量
export ROS_MASTER_URI=http://docker_ros:11311
四、验证命令汇总
| 验证内容 | 命令 | 执行位置 |
|---|---|---|
| 查看所有节点 | rosnode list |
任意终端 |
| 查看话题列表 | rostopic list |
任意终端 |
| 查看话题数据 | rostopic echo /turtle1/pose |
宿主机新终端 |
| 手动发布速度 | rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {z: 1.0}}" |
容器内新终端 |
五、注意事项总结
-
环境变量一致性 :所有节点必须连接到同一个
ROS_MASTER_URI -
网络可达性 :使用
ping和telnet验证网络和端口 -
图形界面显示 :如果你需要在容器内显示图形,启动容器时需添加:
bash-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -
防火墙:如果使用非host模式且跨设备通信,确保11311端口开放
按照这个流程,你应该能顺利实现宿主机显示、容器内控制的小海龟分布式运行。如果遇到具体问题,可以告诉我错误现象,我帮你进一步排查。
简介
其实就是三个要点。
- 网络是否通畅:使用 ping 或者 lsof 工具检查网络。网络通畅则在所有叶子结点所在机器上配置 roscore 所在的 ip 地址:
bash
echo 'export ROS_MASTER_URI=http://10.***.**.*:11311' >> ~/.bashrc
source ~/.bashrc
- 或者在容器启动的时候设置 --net=host,这样连 ROS_MASTER_URI 也不需要配置
- 给容器图像显示授权,点击这里