Skip to content

ROS 2 + Docker + Gazebo Harmonic 仿真环境配置

本教程介绍如何在 macOS/Linux 上通过 Docker 配置完整的 ROS 2 Jazzy + Gazebo Harmonic 仿真环境, 包含可视化界面(X11 转发)和 RViz,并在此基础上运行我们开发的 4 个机器人项目。

Learning Objectives

  • 在 macOS 上安装并配置 XQuartz(X11 转发)
  • 构建 Docker 镜像(ROS 2 Jazzy + Gazebo Harmonic + 仿真包)
  • 启动容器并验证 RViz 可视化
  • 启动 Gazebo 仿真 + 机器人模型
  • 了解统一启动命令:robot_bringup

1. Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│  macOS Host                                                  │
│                                                              │
│  XQuartz (X11 Server) ────── X11 socket ───→ Docker Container│
│  Browser/Terminal                                            │
│       │                                                      │
│  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 ──┘
└─────────────────────────────────────────────────────────────┘

Why Docker?

优势 说明
零污染 不污染主机系统,ROS/Gazebo 依赖复杂
一致性 团队成员同一镜像,避免"在我机器上能跑"问题
可重复 docker compose build 保证每次环境相同
GPU 支持 Apple Silicon M 系列 GPU 可直接穿透

2. Install XQuartz (macOS Only)

Docker 里的 RViz 和 Gazebo 需要 X11 显示服务。macOS 需要安装 XQuartz。

# Step 1: Install XQuartz via Homebrew
brew install --cask xquartz

# Step 2: 重启 macOS(XQuartz 需要注册 X11 服务)
#    Apple Menu → Restart

# 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。


3. Build the Docker Image

cd ~/ros2_ws

# 构建包含所有仿真包的镜像(首次约需 20-30 分钟)
docker compose build ros2-dev

# 如果构建报错,检查 Docker Desktop 内存设置 ≥ 8GB
# Docker Desktop → Settings → Resources → Memory: 8GB+

What's Inside the Image

说明
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. Start the Container

# 方式 A: 交互式开发容器
docker compose up -d ros2-dev     # 后台启动
docker compose exec ros2-dev bash # 进入容器

# 方式 B: 一行命令启动并进入
docker compose run --rm ros2-dev bash

Verify ROS 2 Installation

# 在容器内执行
source /opt/ros/jazzy/setup.bash

ros2 pkg list | grep -E "gazebo|rviz|nav2|slam"
# 应该看到 ros_gz_sim, rviz2, nav2_bringup, slam_toolbox 等

5. Build the Simulation Packages

# 在容器内
cd /root/ros2_ws

# 更新 ROS 依赖(首次需要)
rosdep install --from-paths src --ignore-src -r -y

# 构建所有包(--symlink-install: 修改源码后无需重新构建)
colcon build --symlink-install

# 激活 workspace
source install/setup.bash

Expected output:

Summary: X packages succeeded
  - robot_description
  - robot_gazebo
  - robot_bringup
  - robot_navigation
  - robot_vslam


6. Launch the Simulation — One Command

# 移动机器人(差速驱动 + 激光雷达)
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

What happens:

1. gz sim (Gazebo Harmonic) starts with the world
2. Robot URDF is parsed and published via robot_state_publisher
3. Robot is spawned into Gazebo at (0, 0, 0.075)
4. ROS 2 ↔ Gazebo bridges activate (clock, odometry, scan, IMU)
5. RViz2 launches and shows the robot model
6. teleop_twist_keyboard starts for keyboard control


7. Keyboard Teleoperation

在另一个终端(容器内)运行键盘控制:

# 容器 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

Teleop Controls

Key Action
i Forward
, Backward
j Turn left
l Turn right
k Stop
q Increase speed
z Decrease speed

8. RViz Visualization

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 Panels Explained

Panel Purpose
RobotModel 显示 URDF 机器人3D模型
TF 坐标变换树(base_link → lidar_link → imu_link...)
LaserScan 激光雷达扫描点(红色)
Image 深度相机 RGB 画面
Path 导航路径
Pose 机器人当前位置估计

9. Project-Specific Launch Commands

Project 1: Mobile Robot Navigation

# 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

Project 2: Manipulator Arm (MoveIt2)

# 启动 MoveIt2 运动规划
ros2 launch moveit2_scripts demo.launch.py

# RViz 中: Use MotionPlanning plugin
# 拖动机械臂末端 → 自动规划无碰撞轨迹

Project 3: Aerial Drone

# 无人机仿真
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

Project 4: Visual Navigation

# 深度相机 + VSLAM
ros2 launch robot_vslam vslam.launch.py camera:=depth_camera

# 启动视觉导航
ros2 launch robot_bringup robot.launch.py robot_type:=mobile vslam:=true

10. Troubleshooting

X11 Forwarding Not Working

# 症状: RViz window doesn't appear

# 检查 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 Access (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 Crashes on Startup

# 降低仿真精度
gz sim -r --physics-engine ode basic_world.sdf

# 或使用 headless 模式(无 GUI)
gz sim -s basic_world.sdf

Package Not Found After Build

# 每次修改源码后重新 build
colcon build --symlink-install
source install/setup.bash

# 或者加到 ~/.bashrc(自动生效)
echo "source /root/ros2_ws/install/setup.bash" >> ~/.bashrc

11. Docker Workflow Summary

# ============================================================
# Daily Workflow
# ============================================================

# 1. Start 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. Project Repository Structure

~/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

References