ROS 2 + Docker + Gazebo Harmonic 仿真环境配置¶
本教程介绍如何在 macOS/Linux 上通过 Docker 配置完整的 ROS 2 Jazzy + Gazebo Harmonic 仿真环境, 包括可视化界面(X11 转发)和 RViz,并在此基础上运行我们开发的 4 个机器人项目。
学习目标¶
- 在 macOS 上安装并配置 XQuartz(X11 转发)
- 构建 Docker 镜像(ROS 2 Jazzy + Gazebo Harmonic + 仿真包)
- 启动容器并验证 RViz 可视化
- 启动 Gazebo 仿真 + 机器人模型
- 掌握统一启动命令:
robot_bringup
1. 系统架构¶
┌─────────────────────────────────────────────────────────────┐
│ macOS 宿主机 │
│ │
│ XQuartz (X11 服务器) ────── X11 socket ───→ Docker 容器 │
│ 浏览器/终端 │
│ │ │
│ docker compose ───────────→ ros2-jazzy-gazebo:latest │
│ │ │ │
│ Homebrew ┌────────────────────────┤
│ (X11 + Docker) │ ROS 2 Jazzy │
│ │ ├── Gazebo Harmonic (gz sim) │
│ │ ├── robot_bringup │
│ │ ├── robot_description │
│ │ ├── robot_gazebo │
│ │ ├── robot_navigation │
│ │ └── robot_vslam │
│ │ │
│ │ RViz2 ── GUI via X11 ──┘
│ │ Gazebo ── GUI via X11 ──┘
└─────────────────────────────────────────────────────────────┘
为什么要用 Docker?¶
| 优势 | 说明 |
|---|---|
| 零污染 | 不污染主机系统,ROS/Gazebo 依赖复杂 |
| 一致性 | 团队成员同一镜像,避免"在我机器上能跑"问题 |
| 可重复 | docker compose build 保证每次环境相同 |
| GPU 支持 | Apple Silicon M 系列 GPU 可直接穿透 |
2. 安装 XQuartz(仅 macOS)¶
Docker 里的 RViz 和 Gazebo 需要 X11 显示服务。macOS 需要安装 XQuartz。
# Step 1: 通过 Homebrew 安装 XQuartz
brew install --cask xquartz
# Step 2: 重启 macOS(XQuartz 需要注册 X11 服务)
# 点击 Apple Logo → 重启
# Step 3: 允许本地 X11 连接
xhost + 127.0.0.1
# Step 4: 验证 XQuartz
open -a XQuartz
# 检查 XQuartz → Preferences → Output → "Enable connection from network clients" 勾选
必须重启 macOS
XQuartz 安装后必须重启系统,否则 /tmp/.X11-unix socket 不会创建,
Docker 容器无法挂载 X11 socket,导致 RViz 无法显示。
3. 构建 Docker 镜像¶
cd ~/ros2_ws
# 构建包含所有仿真包的镜像(首次约需 20-30 分钟)
docker compose build ros2-dev
# 如果构建报错,检查 Docker Desktop 内存设置 ≥ 8GB
# Docker Desktop → Settings → Resources → Memory: 8GB+
镜像内包含的关键包¶
| 包名 | 说明 |
|---|---|
ros:jazzy |
ROS 2 Jazzy 基础镜像 |
gz-harmonic |
Gazebo Harmonic 仿真引擎 |
ros-jazzy-ros-gzsim |
ROS 2 ↔ Gazebo 桥接 |
ros-jazzy-moveit |
机械臂运动规划 |
ros-jazzy-slam-toolbox |
激光 SLAM 建图 |
ros-jazzy-rviz2 |
3D 可视化 |
ros-jazzy-nav2-* |
导航2 全栈 |
4. 启动容器¶
# 方式 A: 后台启动开发容器
docker compose up -d ros2-dev # 后台运行
docker compose exec ros2-dev bash # 进入容器
# 方式 B: 一行命令启动并进入
docker compose run --rm ros2-dev bash
验证 ROS 2 安装¶
# 在容器内执行
source /opt/ros/jazzy/setup.bash
ros2 pkg list | grep -E "gazebo|rviz|nav2|slam"
# 应该看到 ros_gz_sim, rviz2, nav2_bringup, slam_toolbox 等
5. 构建仿真包¶
# 在容器内
cd /root/ros2_ws
# 首次需要安装依赖
rosdep install --from-paths src --ignore-src -r -y
# 构建所有包(--symlink-install: 修改源码后无需重新构建整个包)
colcon build --symlink-install
# 激活 workspace
source install/setup.bash
预期输出:
Summary: X packages succeeded
- robot_description
- robot_gazebo
- robot_bringup
- robot_navigation
- robot_vslam
6. 一键启动仿真¶
# 移动机器人(差速驱动 + 激光雷达)
ros2 launch robot_bringup robot.launch.py robot_type:=mobile
# 机械臂(7-DOF + 夹爪)
ros2 launch robot_bringup robot.launch.py robot_type:=manipulator
# 无人机(四旋翼 + 深度相机)
ros2 launch robot_bringup robot.launch.py robot_type:=drone world:=aerial_world
启动流程:
1. gz sim (Gazebo Harmonic) 启动,加载 world 文件
2. robot_state_publisher 解析 URDF 并发布 robot_description
3. 机器人模型被 spawn 到 Gazebo 场景中
4. ROS 2 ↔ Gazebo 桥接激活(时钟、里程计、激光、IMU)
5. RViz2 自动启动并显示机器人3D模型
6. teleop_twist_keyboard 键盘控制节点运行
7. 键盘遥控¶
在另一个终端(容器内)运行键盘控制:
# 终端 1: 启动仿真
docker compose exec ros2-dev bash
ros2 launch robot_bringup robot.launch.py robot_type:=mobile
# 终端 2: 键盘控制
docker compose exec ros2-dev bash
source /opt/ros/jazzy/setup.bash
source /root/ros2_ws/install/setup.bash
ros2 run teleop_twist_keyboard teleop_twist_keyboard
键盘控制说明¶
| 按键 | 动作 |
|---|---|
i |
前进 |
, |
后退 |
j |
左转 |
l |
右转 |
k |
停止 |
q |
加速 |
z |
减速 |
8. RViz 可视化¶
RViz 已集成在 robot.launch.py 中自动启动。如需单独启动:
# 加载预配置的 RViz 界面(推荐)
rviz2 -d $(find robot_description)/config/robot.rviz
# 或者手动配置:
# 1. Add → RobotModel → Description Topic: /robot_description
# 2. Add → LaserScan → Topic: /scan
# 3. Add → TF display
# 4. Add → Image (depth camera): /depth_camera/color/image_raw
RViz 面板说明¶
| 面板 | 用途 |
|---|---|
| RobotModel | 显示 URDF 机器人3D模型 |
| TF | 坐标变换树(base_link → lidar_link → imu_link...) |
| LaserScan | 激光雷达扫描点(红色) |
| Image | 深度相机 RGB 画面 |
| Path | 导航路径 |
| Pose | 机器人当前位置估计 |
9. 各项目启动命令¶
项目一:移动机器人导航¶
# SLAM 建图模式
ros2 launch robot_navigation navigation.launch.py
# 2D 地图出现在 /map topic
# 在 RViz 中: Add → Map → Topic: /map
# 用键盘控制机器人在房间走动,地图逐渐构建
# 保存地图
ros2 run nav2_map_server map_saver_cli -f ~/map
项目二:机械臂(MoveIt2)¶
# 启动 MoveIt2 运动规划
ros2 launch moveit2_scripts demo.launch.py
# RViz 中: 使用 MotionPlanning 插件
# 拖动机械臂末端 → 自动规划无碰撞轨迹
项目三:无人机¶
# 无人机仿真
ros2 launch robot_bringup robot.launch.py robot_type:=drone world:=aerial_world
# 键盘控制(高度)
ros2 run teleop_twist_keyboard teleop_twist_keyboard /cmd_vel:=drone/cmd_vel
项目四:视觉导航¶
# 深度相机 + VSLAM
ros2 launch robot_vslam vslam.launch.py camera:=depth_camera
# 启动视觉导航
ros2 launch robot_bringup robot.launch.py robot_type:=mobile vslam:=true
10. 常见问题排查¶
X11 转发不工作¶
# 症状: RViz 窗口不出现
# 检查 1: XQuartz 是否运行
ps aux | grep Xquartz
# 检查 2: DISPLAY 环境变量
echo $DISPLAY
# 期望输出: host.docker.internal:0 或 :0
# 检查 3: X11 socket 是否存在
ls -la /tmp/.X11-unix/
# 期望: srwxrwxrwt ... X0
# 手动修复: 设置 DISPLAY
export DISPLAY=host.docker.internal:0
ros2 run rviz2 rviz2
Docker GPU 访问(Apple Silicon)¶
# 检查 Docker 是否识别 GPU
docker run --rm --device /dev/dri --privileged \
ros:jazzy ros2 run demo_nodes_py talker
# Apple Silicon: 无需额外驱动,Docker Desktop 自动处理
# Intel/NVIDIA: 添加 --gpus all 参数
Gazebo 启动崩溃¶
# 降低仿真精度
gz sim -r --physics-engine ode basic_world.sdf
# 或使用无 GUI 模式(headless)
gz sim -s basic_world.sdf
找不到包(Package Not Found)¶
# 修改源码后重新构建
colcon build --symlink-install
source install/setup.bash
# 或加到 ~/.bashrc(自动生效)
echo "source /root/ros2_ws/install/setup.bash" >> ~/.bashrc
11. Docker 工作流总结¶
# ============================================================
# 日常工作流程
# ============================================================
# 1. 启动 Docker Desktop (macOS)
# 2. 启动开发容器
cd ~/ros2_ws
docker compose up -d ros2-dev
docker compose exec ros2-dev bash
# 3. 编写代码(在容器内或宿主机 ~/ros2_ws/src/)
# 源码修改后:
cd /root/ros2_ws
colcon build --symlink-install && source install/setup.bash
# 4. 运行仿真
ros2 launch robot_bringup robot.launch.py robot_type:=mobile
# 5. 停止
exit
docker compose down
12. 项目代码结构¶
~/ros2_ws/
├── Dockerfile # 完整的仿真环境定义
├── docker-compose.yml # 容器编排(GPU + X11)
├── src/
│ ├── my_first_pkg/ # ROS2 入门示例
│ ├── robot_description/ # URDF/xacro 模型(核心)
│ │ ├── urdf/
│ │ │ ├── common.xacro # 共享宏(gazebo插件、惯性、材质)
│ │ │ ├── sensors.xacro # 传感器(lidar、imu、realsense)
│ │ │ ├── mobile_robot.urdf.xacro
│ │ │ ├── manipulator.urdf.xacro
│ │ │ └── aerial_drone.urdf.xacro
│ │ └── config/
│ │ ├── robot.rviz # RViz 可视化配置
│ │ └── controllers.yaml # ROS2 Control 参数
│ ├── robot_gazebo/ # Gazebo 仿真世界 + 桥接
│ │ ├── worlds/
│ │ │ ├── basic_world.sdf # 仓库环境(导航测试)
│ │ │ └── aerial_world.sdf # 空中飞行环境
│ │ └── launch/
│ │ └── gazebo.launch.py
│ ├── robot_bringup/ # 统一启动器(核心入口)
│ │ └── launch/
│ │ └── robot.launch.py
│ ├── robot_navigation/ # SLAM + Nav2 导航栈
│ │ ├── config/
│ │ │ ├── slam_params.yaml # SLAM Toolbox 配置
│ │ │ └── nav2_params.yaml # Nav2 参数
│ │ └── launch/
│ │ └── navigation.launch.py
│ └── robot_vslam/ # 视觉 SLAM
│ └── launch/
│ └── vslam.launch.py