Skip to content

Use gazebo harmonic with vscode devcontainer

Use VSCode and docker

  • Using docker-compose
  • Using devcontainer to run the docker compose
1
2
3
4
5
6
7
├── .devcontainer
│   ├── Dockerfile
│   └── devcontainer.json
├── docker-compose.yaml
├── .gitignore
└── worlds
        └── empty.world
Dockerfile
FROM ubuntu:22.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 \
&& rm -rf /var/lib/apt/lists/*

# 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/*

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
    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_TRANSPORT_IP=gazebo
      - GZ_DISCOVERY_SERVER=gazebo
      - 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

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-->
        <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
echo '🤖 Environment ready!'
# bash key bindings
# replace bringup with full bringup name
bind '"\C-b": "gz sim -v 4 -r mini.world"'

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

# Custom PS1 with turtle icon and git branch
export PS1="🤖 \[\033[32m\]\u@\h\[\033[00m\]:\[\033[34m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\]\$ "

Usage

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