Skip to content

Use Gazebo Harmonic with VS Code devcontainer

Use VS Code and Docker

  • Using Docker Compose
  • Using devcontainer to run Docker Compose
1
2
3
4
5
6
7
8
├── .devcontainer
│   ├── Dockerfile
│   └── devcontainer.json
├── docker-compose.yaml
├── env.sh
├── .gitignore
└── worlds
    └── minimal.world

Download the complete project archive:

gz_harmonic_vscode.zip

Extract it and open the folder in VS Code:

1
2
3
unzip gz_harmonic_vscode.zip
cd gz_harmonic_vscode
code .
Dockerfile
FROM ubuntu:22.04 AS base

ENV DEBIAN_FRONTEND=noninteractive

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

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

RUN apt-get update && apt-get install -q -y --no-install-recommends \
    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" > /etc/apt/sources.list.d/gazebo-stable.list \
  && apt-get update \
  && apt-get install -y -q --no-install-recommends gz-harmonic \
  && rm -rf /var/lib/apt/lists/*

RUN apt-get update \
  && apt-get install -y -qq --no-install-recommends \
    libglvnd0 \
    libgl1 \
    libglx0 \
    libegl1 \
    libxext6 \
    libx11-6 \
  && rm -rf /var/lib/apt/lists/*

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

RUN if getent passwd ubuntu > /dev/null 2>&1; then \
      userdel -r ubuntu; \
    fi \
  && groupadd --gid $USER_GID $USERNAME \
  && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME

RUN apt-get update \
  && apt-get install -y --no-install-recommends sudo \
  && echo "$USERNAME ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \
  && chmod 0440 /etc/sudoers.d/$USERNAME \
  && rm -rf /var/lib/apt/lists/*

RUN apt-get update \
  && apt-get install -y -qq --no-install-recommends \
    vim \
    build-essential \
    git \
    openssh-client \
    ca-certificates \
    cmake \
  && rm -rf /var/lib/apt/lists/*

CMD ["bash"]
Docker Compose
docker-compose.yaml
services:
  gazebo:
    build:
      dockerfile: .devcontainer/Dockerfile
      context: .
    network_mode: host
    user: user
    stdin_open: true
    tty: true
    hostname: gz
    working_dir: /workspace
    environment:
      - DISPLAY=${DISPLAY}
      - QT_X11_NO_MITSHM=1
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
      - __NV_PRIME_RENDER_OFFLOAD=1
      - __GLX_VENDOR_LIBRARY_NAME=nvidia
      - GZ_PARTITION=my_simulation
    volumes:
      - .:/workspace:cached
      - ./.gz:/home/user/.gz:rw
      - /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]

nvidia glx

  • __NV_PRIME_RENDER_OFFLOAD=1
  • __GLX_VENDOR_LIBRARY_NAME=nvidia
.devcontainer/devcontainer.json
{
    "name": "gz_harmonic",
    "dockerComposeFile": "../docker-compose.yaml",
    "service": "gazebo",
    "shutdownAction": "stopCompose",
    "workspaceFolder": "/workspace",
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "ms-vscode.cpptools",
                "redhat.vscode-xml",
                "redhat.vscode-yaml",
                "albert.tabout",
                "actboy168.tasks",
                "streetsidesoftware.code-spell-checker",
                "ms-vscode.cmake-tools"
            ],
            "settings": {}
        }
    }
}

Run the simulation

Using Docker Compose

docker compose up --build -d

Then open a shell in the container:

docker compose exec gazebo bash

Run the world:

source env.sh
gz sim -v 4 -r worlds/minimal.world

Using Docker without Compose

Build the image:

1
2
3
4
docker build \
  -t gz-harmonic-vscode \
  -f .devcontainer/Dockerfile \
  .

Allow local Docker containers to connect to the X server:

xhost +local:docker

Run the container:

mkdir -p .gz

docker run \
  --rm \
  -it \
  --name gz-harmonic \
  --network host \
  --hostname gz \
  --user user \
  --workdir /workspace \
  --gpus all \
  -e DISPLAY="${DISPLAY}" \
  -e QT_X11_NO_MITSHM=1 \
  -e NVIDIA_VISIBLE_DEVICES=all \
  -e NVIDIA_DRIVER_CAPABILITIES=all \
  -e __NV_PRIME_RENDER_OFFLOAD=1 \
  -e __GLX_VENDOR_LIBRARY_NAME=nvidia \
  -e GZ_PARTITION=my_simulation \
  -v "${PWD}:/workspace:rw" \
  -v "${PWD}/.gz:/home/user/.gz:rw" \
  -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
  -v /dev/dri:/dev/dri \
  --device /dev/nvidia0 \
  --device /dev/nvidiactl \
  --device /dev/nvidia-modeset \
  gz-harmonic-vscode

Inside the container:

source env.sh
gz sim -v 4 -r worlds/minimal.world
minimal world
<?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 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>
        <model name="ground_plane">
            <static>true</static>
            <link name="link">
                <collision name="collision">
                    <geometry>
                        <plane>
                            <normal>0 0 1</normal>
                            <size>100 100</size>
                        </plane>
                    </geometry>
                </collision>
                <visual name="visual">
                    <geometry>
                        <plane>
                            <normal>0 0 1</normal>
                            <size>100 100</size>
                        </plane>
                    </geometry>
                    <material>
                        <ambient>0.8 0.8 0.8 1</ambient>
                        <diffuse>0.8 0.8 0.8 1</diffuse>
                        <specular>0.8 0.8 0.8 1</specular>
                    </material>
                </visual>
            </link>
        </model>
    </world>
</sdf>

Environment helper file

  • Change prompt
  • Set Environment variables
  • Add keyboard shortcuts
env.sh
export GZ_SIM_RESOURCE_PATH="$(pwd)/models:$(pwd)/worlds:${GZ_SIM_RESOURCE_PATH}"
export GZ_SIM_SYSTEM_PLUGIN_PATH="$(pwd)/bin:${GZ_SIM_SYSTEM_PLUGIN_PATH}"

bind '"\C-b": "gz sim -v 4 -r worlds/minimal.world"'

parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/[\1]/'
}

export PS1="gz \[\033[32m\]\u@\h\[\033[00m\]:\[\033[34m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\]\$ "

echo "Gazebo Harmonic environment ready"

Usage

# run the simulation
gz sim -v 4 -r worlds/minimal.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