ROS 跨机通信与 Docker 多机环境搭建

ROS 跨机通信与 Docker 多机环境搭建笔记

一、跨机通信概述

  • 在无人驾驶、大型服务机器人等场景中,ROS 常运行在多台计算设备上,协作完成任务。
  • ROS 支持分布式计算 ,但整个分布式系统中只有一个 Master 节点
  • 所有节点通过将 ROS_MASTER_URI 指向 Master 所在设备进行通信。
  • 需要通过设置 ROS_HOSTNAMEROS_MASTER_URI(可添加到 ~/.bashrc 中)来配置网络。

二、创建多机环境(以 Docker 为例)

  1. 创建 Docker 环境
  2. 在 Docker 容器中启动 Master
  3. 在宿主机上启动小海龟(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

镜像来源:https://hub.docker.com/_/ros


四、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_HOSTNAMEROS_IP 设置不当,导致发布的 URI 无法被宿主机访问。
  • 防火墙或网络策略阻止了端口访问(默认 11311)。
  • 容器内 ROS_MASTER_URI 指向错误(例如仍指向 localhost,而宿主机需指向容器 IP)。

九、解决方案

方案一:使用容器 IP 直接通信(推荐)
  1. 在容器内设置 ROS_IP 为容器 IP

    进入容器后,执行:

    bash 复制代码
    export ROS_IP=172.17.0.2   # 替换为容器实际 IP

    或写入 ~/.bashrc 以便持久化。

  2. 在宿主机设置 ROS_MASTER_URI 为容器 IP

    bash 复制代码
    export ROS_MASTER_URI=http://172.17.0.2:11311

    注意:此时宿主机不需要设置 ROS_HOSTNAME(或可注释掉)。

  3. 验证连通性

    宿主机上:

    bash 复制代码
    ping 172.17.0.2
    telnet 172.17.0.2 11311   # 检查端口是否可达
方案二:使用主机名并确保双向解析
  1. 宿主机 hosts 文件(已做):

    复制代码
    172.17.0.2    docker_ros
  2. 容器内 hosts 文件

    需要确保容器内也能解析 docker_ros 为自身 IP。可在启动容器时添加 --add-host 参数:

    bash 复制代码
    sudo docker run -ti --add-host docker_ros:172.17.0.2 ros:robot /bin/bash

    或在容器内手动编辑 /etc/hosts

  3. 容器内设置 ROS_HOSTNAME

    bash 复制代码
    export ROS_HOSTNAME=docker_ros

    同时确保 ROS_MASTER_URI 指向 docker_ros:11311

  4. 检查 roscore 监听地址

    roscore 默认监听 0.0.0.0(所有接口),若启动时出现异常,可手动指定:

    bash 复制代码
    roscore -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 showhostname -I
测试网络连通性 ping docker_ros
测试端口是否监听 lsof -i:11311(容器内)
查看节点注册信息 rosnode listrosnode 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 ~/.bashrcgedit ~/.bashrc
  • 查看 hosts 文件:cat /etc/hosts

通过以上步骤,就能够解决跨机通信失败的问题,顺利实现 Docker 容器与宿主机之间的 ROS 节点通信。

完整的实践流程

一个完整的、可直接操作的配置流程,实现宿主机启动小海龟界面,Docker容器内用键盘控制它运动
Phase 3: 数据传输
Phase 2: 连接协商
Phase 1: 节点注册

  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. 鼠标点击键盘控制节点的终端窗口使其获得焦点
  2. 使用键盘的方向键(↑↓←→)控制小海龟移动
  3. 你应该能看到宿主机窗口中的小海龟随之移动

三、如果通信失败?排查指南

现象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模式,需要额外配置:

  1. 容器内
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
  1. 宿主机
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}}" 容器内新终端

五、注意事项总结

  1. 环境变量一致性 :所有节点必须连接到同一个ROS_MASTER_URI

  2. 网络可达性 :使用pingtelnet验证网络和端口

  3. 图形界面显示 :如果你需要在容器内显示图形,启动容器时需添加:

    bash 复制代码
    -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY
  4. 防火墙:如果使用非host模式且跨设备通信,确保11311端口开放

按照这个流程,你应该能顺利实现宿主机显示、容器内控制的小海龟分布式运行。如果遇到具体问题,可以告诉我错误现象,我帮你进一步排查。

简介

其实就是三个要点。

  • 网络是否通畅:使用 ping 或者 lsof 工具检查网络。网络通畅则在所有叶子结点所在机器上配置 roscore 所在的 ip 地址:
bash 复制代码
echo 'export ROS_MASTER_URI=http://10.***.**.*:11311' >> ~/.bashrc
source ~/.bashrc
  • 或者在容器启动的时候设置 --net=host,这样连 ROS_MASTER_URI 也不需要配置
  • 给容器图像显示授权,点击这里
相关推荐
主角1 71 小时前
Nginx核心功能
运维·nginx
cyber_两只龙宝1 小时前
【MySQL】MySQL主从复制架构
linux·运维·数据库·mysql·云原生·架构
切糕师学AI2 小时前
Kubernetes 中的 Informer 机制
云原生·容器·kubernetes·informer
i建模2 小时前
在 Windows CMD 中将当前路径永久添加到系统环境变量
运维·windows
虚拟世界AI2 小时前
Linux运维实战:从部署到高可用全指南
linux·运维
闫记康2 小时前
scp工具
linux·运维·服务器·学习·ssh·github
虾..2 小时前
Linux 套接字编程---基于UDP协议实现简易的聊天室
linux·运维·udp
xiaoye37082 小时前
docker 迁移mysql容器
mysql·docker
默|笙2 小时前
【Linux】库制作与原理(2)_ELF格式
linux·运维·服务器