Skip to content

Run gazebo harmonic on docker

Build a docker container base on cuda runtime and ubuntu 22.04 to run Gazebo harmonic simulation. The dockerfile base on Allison Thackston

Use vscode devcontainer to run the docker image. using docker compose. vscode devcontainer

Prerequisites

  • Check nvidia version using nvidia-smi
  • Pull the cuda runtime
  • Install nvidia-container-toolkit more
pull cuda runtime
1
2
3
4
5
# my current cuda version is 12.4
docker pull nvidia/cuda:12.4.0-runtime-ubuntu22.04
docker run --gps all -it --rm  nvidia/cuda:12.4.0-runtime-ubuntu22.04 /bin/bash
# from docker 
nvida-smi

Dockerfile

Docker file
FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04 AS base

# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive

# Install language
RUN apt-get update && apt-get install -y --no-install-recommends \
  locales \
  && locale-gen en_US.UTF-8 \
  && update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 \
  && rm -rf /var/lib/apt/lists/*
ENV LANG=en_US.UTF-8

# Install timezone
RUN ln -fs /usr/share/zoneinfo/UTC /etc/localtime \
  && export DEBIAN_FRONTEND=noninteractive \
  && apt-get update \
  && apt-get install -y --no-install-recommends tzdata \
  && dpkg-reconfigure --frontend noninteractive tzdata \
  && rm -rf /var/lib/apt/lists/*

# install packages
RUN apt-get update && apt-get install -q -y \
    curl \
    gnupg \
    lsb-release \
    python3-argcomplete \
    sudo \
    wget \
  && wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg \
  && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null \
  && apt-get update && apt-get install -y -q \
    gz-harmonic \
  && rm -rf /var/lib/apt/lists/*

################
# Expose the nvidia driver to allow opengl
# Dependencies for glvnd and X11.
################
RUN apt-get update \
 && apt-get install -y -qq --no-install-recommends \
  libglvnd0 \
  libgl1 \
  libglx0 \
  libegl1 \
  libxext6 \
  libx11-6

# Env vars for the nvidia-container-runtime.
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
ENV QT_X11_NO_MITSHM=1

ARG USERNAME=user
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Check if "ubuntu" user exists, delete it if it does, then create the desired user
RUN if getent passwd ubuntu > /dev/null 2>&1; then \
        userdel -r ubuntu && \
        echo "Deleted existing ubuntu user"; \
    fi && \
    groupadd --gid $USER_GID $USERNAME && \
    useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME && \
    echo "Created new user $USERNAME"

# Add sudo support for the non-root user
RUN apt-get update && apt-get install -y sudo \
  && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
  && chmod 0440 /etc/sudoers.d/$USERNAME \
  && rm -rf /var/lib/apt/lists/*

CMD ["bash"]

Docker environment variables

  • QT_X11_NO_MITSHM=1 is used to disable the MIT-SHM extension for X11, which can cause issues with some applications running in Docker containers.
  • NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute is used to specify the capabilities of the NVIDIA driver that should be exposed to the container. This is important for GPU-accelerated applications.
  • NVIDIA_VISIBLE_DEVICES=all is used to make all NVIDIA GPUs visible to the container. This is important for GPU-accelerated applications that need access to the GPU.

Build the image

docker build -t gz:harmonic .

Run the image

xhost +local:docker

docker run --gpus all -it --rm \
--name gz \
--hostname gz \
--user user \
--network host \
--env="QT_X11_NO_MITSHM=1"  \
--env="DISPLAY"  \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-v /dev/dri:/dev/dri \
-v /dev/nvidia0:/dev/nvidia0 \
-v /dev/nvidiactl:/dev/nvidiactl \
-v /dev/nvidia-modeset:/dev/nvidia-modeset \
gz:harmonic

Use VSCode and docker

  • Using docker-compose
  • Using devcontainer to run the docker compose
1
2
3
4
5
6
7
├── .devcontainer
│   └── devcontainer.json
├── docker-compose.yaml
├── .gitignore
└── gz_tutorial
    └── worlds
        └── empty.world
docker-compose.yaml
services:
  gazebo:
    image: gz:harmonic
    network_mode: host
    user: user
    stdin_open: true
    tty: true
    hostname: gz
    environment:
      - DISPLAY=${DISPLAY}
      - QT_X11_NO_MITSHM=1
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
      - GZ_TRANSPORT_IP=gazebo
      - GZ_DISCOVERY_SERVER=gazebo
      - GZ_PARTITION=my_simulation
    volumes:
      - .:/workspace:cached
      - ./.gz:/home/user/.gz:cached
      - /tmp/.X11-unix:/tmp/.X11-unix:rw 
      - /dev/dri:/dev/dri 
      - /dev/nvidia0:/dev/nvidia0 
      - /dev/nvidiactl:/dev/nvidiactl 
      - /dev/nvidia-modeset:/dev/nvidia-modeset 
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]
.devcontainer/devcontainer.json
{
    "name": "gz_tutorial",
    "dockerComposeFile": "../docker-compose.yaml",
    "service": "gazebo",
    "shutdownAction": "stopCompose",
    "workspaceFolder": "/workspace",
    "remoteUser": "user",
    "customizations": {
      "vscode": {
        "extensions": [
            "ms-python.python",
            "ms-vscode.cpptools",
            "twxs.cmake",
            "redhat.vscode-xml",
            "redhat.vscode-yaml",
            "albert.tabout",
            "actboy168.tasks",
            "streetsidesoftware.code-spell-checker"
        ],
        "settings": {}
      }
    }
  }

Run the simulation

minimal world
<!-- https://github.com/gazebosim/docs/blob/master/harmonic/tutorials/sdf_worlds/world_demo.sdf -->
<!-- https://gazebosim.org/docs/harmonic/sdf_worlds/ -->
<?xml version="1.0" ?>
<sdf version="1.8">
  <world name="world_demo">
    <physics name="1ms" type="ignored">
      <max_step_size>0.001</max_step_size>
      <real_time_factor>1.0</real_time_factor>
    </physics>
    <plugin
      filename="gz-sim-physics-system"
      name="gz::sim::systems::Physics">
    </plugin>
    <plugin
      filename="gz-sim-user-commands-system"
      name="gz::sim::systems::UserCommands">
    </plugin>
    <plugin
      filename="gz-sim-scene-broadcaster-system"
      name="gz::sim::systems::SceneBroadcaster">
    </plugin>

    <!--light-->
    <light type="directional" name="sun">
      <cast_shadows>true</cast_shadows>
      <pose>0 0 10 0 0 0</pose>
      <diffuse>0.8 0.8 0.8 1</diffuse>
      <specular>0.2 0.2 0.2 1</specular>
      <attenuation>
        <range>1000</range>
        <constant>0.9</constant>
        <linear>0.01</linear>
        <quadratic>0.001</quadratic>
      </attenuation>
      <direction>-0.5 0.1 -0.9</direction>
    </light>
    <include>
        <name>Coke0</name>
        <pose>0 0 0 0 0 0</pose>
        <uri>https://fuel.gazebosim.org/1.0/OpenRobotics/models/Coke</uri>
    </include>
    <include>
        <name>Coke1</name>
        <pose>0 0.1 0 0 0 0</pose>
        <uri>https://fuel.gazebosim.org/1.0/OpenRobotics/models/Coke</uri>
    </include>
  </world>
</sdf>
# run the simulation
gz sim -r v4 gz_tutorial/worlds/empty.world 

alt text

gz topic
1
2
3
4
5
6
7
8
gz topic --list
gz topic -e -t /clock
#

sim {
  sec: 326
  nsec: 476000000
}

Gz Transport

gz_transport is Gazebo's communication middleware, used for inter-process communication (IPC) between different Gazebo components — like sensors, plugins, UI, and even ROS bridges.

  • GZ_PARTITION: Isolates topic namespaces between different simulations
  • GZ_DISCOVERY_SERVER: IP address of the main discovery server (usually the Gazebo server machine)
  • GZ_TRANSPORT_IP: IP address the local process uses to advertise itself to others

Resource