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