Isaac ROS Development Environment#

Note

This page provides a detailed explanation of the development environment and its configuration.

To begin using Isaac ROS, use the Getting Started guide instead.

Overview#

The Isaac ROS Development Environment provides a managed environment for developing and testing Isaac ROS packages.

The Isaac ROS environment is managed and accessed through the Isaac ROS CLI in one of three isolation modes:

  • Docker: Full container isolation from the host system.

  • Virtual Environment: Python packages isolated from system Python, with Debian packages installed on host.

  • Bare Metal: All packages installed directly on the host system.

All Isaac ROS packages, quickstarts, tutorials, and other workflows are tested in these development environments.

You can further customize your development environment by updating the Isaac ROS CLI configuration files.

General Configuration#

The following configuration options apply to all Isaac ROS environment isolation modes.

Isaac ROS Workspace (ISAAC_ROS_WS)#

The Isaac ROS Development Environment is based around a standard ROS 2 workspace.

The Isaac ROS CLI, documentation, and other utilities all rely on the user-specified ISAAC_ROS_WS environment variable to locate your ROS workspace.

As recommended in the Getting Started guide, you can set this variable in your .bashrc file, so that it is pre-loaded into your shell’s environment.

Alternatively, advanced users with multiple workspaces may choose to use a tool like direnv to automatically set the variable based on the current working directory.

In Docker mode, the Isaac ROS CLI mounts the workspace directory into the development container at /workspaces/isaac_ros-dev. For convenience, the CLI also automatically overrides the in-container value of ISAAC_ROS_WS, ensuring that ${ISAAC_ROS_WS} always resolves to the correct location.

Isaac ROS CLI Configuration Files#

The Isaac ROS CLI uses a layered series of YAML files for configuration. A base configuration is shipped with the Isaac ROS CLI during installation, and then higher-priority configuration files can selectively override portions of the base configuration.

The configuration files are loaded in the following order:

Scope

Location

Access Control

Description

Default

/usr/share/isaac-ros-cli/config.yaml

Read-only

Default values shipped with the Isaac ROS CLI.
This file is a useful reference for the CLI’s configuration schema.

System

/etc/isaac-ros-cli/config.yaml

Managed by the CLI

Config written to by the Isaac ROS CLI.

User

~/.config/isaac-ros-cli/config.yaml

Managed by the user

Optional user-level overrides to the base configuration.
Some tutorials in the Isaac ROS documentation will require creating and updating this file.

Workspace

${ISAAC_ROS_WS}/.isaac-ros-cli/config.yaml

Managed by the user

Optional workspace-level overrides to the base configuration.
Advanced users with multiple workspaces can use this file to configure each workspace individually.

If a YAML node is present in multiple configuration files, the Isaac ROS CLI recursively merges the values based on the node type:

Node Type

Resolution Strategy

Scalar

The value in the higher-priority configuration file overrides the value in the lower-priority configuration file.

Sequence

The values in the higher-priority configuration file are appended to the values in the lower-priority configuration file.

Mapping

The (key, value) pairs are recursively merged using these same resolution rules.

Typically, you only need to override small portions of the default configuration, which keeps your override config files smaller than the default.

Note

Do not duplicate the entire read-only configuration file in a user- or workspace-level configuration file.

During initialization, the Isaac ROS CLI writes important information to the system-level configuration file, overriding the uninitialized values stored in the default read-only configuration file.

A duplicated uninitialized configuration stored at the user- or workspace-level will override the Isaac ROS CLI’s attempted initialization, preventing environment activation and other CLI commands.

Instead, selectively override only the desired portions of the default configuration file.

Docker Mode Configuration#

The following configuration options apply only when using the Isaac ROS CLI in Docker mode.

Docker Image Keys#

The Isaac ROS development container runs from an image composed from one or more individual Dockerfiles in a prescribed order.

Each Dockerfile is named Dockerfile.<image_key>, where <image_key> is a unique identifier that describes the file’s contents.

The Isaac ROS CLI ships with the following Dockerfiles:

Image Key

Description

isaac_ros

Base image for Isaac ROS development.

realsense

Dependencies for RealSense cameras.

gr00t_workflow

Dependencies for GR00T Workflow. Isaac ROS Physical AI packages, such as ros-jazzy-isaac-ros-unitree-g1-* and ros-jazzy-realsense2-*

noble (deprecated)

Deprecated image key for platform-specific dependencies for CUDA and other NVIDIA libraries on Ubuntu 24.04 Noble.

ros2_jazzy (deprecated)

Deprecated image key for ROS 2 Jazzy and other Isaac ROS package dependencies.

By default, the Isaac ROS CLI uses the image key sequence [isaac_ros], and NVIDIA provides a corresponding prebuilt Docker image through the NGC Container Registry.

Additional image keys can be added by specifying new entries in an Isaac ROS CLI configuration file at the appropriate scope.

For example, to add the realsense image key, add the following to your configuration file:

docker:
  image:
    additional_image_keys:
      - realsense

Note

Because NVIDIA only provides prebuilt Docker images for the base image key sequence [isaac_ros], any additional image keys must be built locally.

Run isaac-ros activate --build-local to build the image with the new image key:

isaac-ros activate --build-local

Rebuilding can take several minutes.

After the image has been built once, you can use isaac-ros activate to launch the container from the saved image.

If the image is subsequently deleted from the local Docker registry, use the --build-local flag to rebuild the image.

Custom Docker Image Layers#

When you install packages manually inside the container (for example, apt-get install or rosdep install), those changes are lost if the container is removed or the image is rebuilt. Custom Docker image layers solve this by baking your dependencies into the image itself to persist them across container recreations.

This is the recommended approach for teams that need project-specific dependencies beyond what the base isaac_ros image provides.

Creating a Custom Dockerfile#

  1. Create a file named Dockerfile.<your_key> (for example, Dockerfile.my_team) in a directory of your choice:

    ARG BASE_IMAGE
    FROM ${BASE_IMAGE}
    
    ARG DEBIAN_FRONTEND=noninteractive
    ENV ROS_DISTRO=jazzy
    ENV ROS_ROOT=/opt/ros/${ROS_DISTRO}
    
    # Install prebuilt packages
    RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
        apt-get update \
        && apt-get install -y \
            ros-jazzy-my-package \
            ros-jazzy-another-package
    

    The ARG BASE_IMAGE / FROM ${BASE_IMAGE} pattern is required. The Isaac ROS CLI automatically sets BASE_IMAGE to the previous layer’s output when chaining Dockerfiles.

    See Dockerfile.realsense and Dockerfile.zed under /etc/isaac-ros-cli/docker/ for real-world examples.

    Pre-installing rosdep dependencies for building from source

    When building a ROS package from source, rosdep install --from-paths resolves dependencies from the package.xml in the source tree. Because the source tree is not available during docker build (it lives on the host and is mounted at runtime), you can provide the dependency information at build time so that rosdep resolves and installs the same system packages without needing the full source code.

    If the package.xml is publicly accessible, fetch it directly with curl:

    ARG BASE_IMAGE
    FROM ${BASE_IMAGE}
    
    ARG DEBIAN_FRONTEND=noninteractive
    ENV ROS_DISTRO=jazzy
    ENV ROS_ROOT=/opt/ros/${ROS_DISTRO}
    
    # Fetch the package.xml and run rosdep to pre-install build dependencies.
    RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
        apt-get update \
        && mkdir -p /tmp/rosdep_ws/src/vslam \
        && curl -fsSL \
           "https://raw.githubusercontent.com/NVIDIA-ISAAC-ROS/isaac_ros_visual_slam/main/isaac_ros_visual_slam/package.xml" \
           -o /tmp/rosdep_ws/src/vslam/package.xml \
        && source ${ROS_ROOT}/setup.bash \
        && rosdep update \
        && rosdep install --from-paths /tmp/rosdep_ws/src --ignore-src -r -y \
        && rm -rf /tmp/rosdep_ws
    

    This fetches the real package.xml at build time, so dependencies stay in sync with the source of truth automatically. Update the URL or branch when the target package.xml changes location.

    If the package.xml lives in a private repository that is not accessible during docker build, create a minimal shim package.xml inline in the Dockerfile. Copy only the <depend>, <build_depend>, and <exec_depend> entries from your real package.xml—the remaining metadata fields are placeholders.

    ARG BASE_IMAGE
    FROM ${BASE_IMAGE}
    
    ARG DEBIAN_FRONTEND=noninteractive
    ENV ROS_DISTRO=jazzy
    ENV ROS_ROOT=/opt/ros/${ROS_DISTRO}
    
    # Pre-install rosdep dependencies using a shim package.xml.
    # Copy the <depend> entries from your package's real package.xml.
    RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
        apt-get update \
        && mkdir -p /tmp/rosdep_ws/src/deps \
        && printf '%s\n' \
           '<?xml version="1.0"?>' \
           '<package format="3">' \
           '  <name>deps</name>' \
           '  <version>0.0.0</version>' \
           '  <description>Dependency shim</description>' \
           '  <maintainer email="maintainer@example.com">Maintainer</maintainer>' \
           '  <license>Apache-2.0</license>' \
           '  <depend>rclcpp</depend>' \
           '  <depend>sensor_msgs</depend>' \
           '  <depend>cv_bridge</depend>' \
           '  <depend>tf2_ros</depend>' \
           '</package>' \
           > /tmp/rosdep_ws/src/deps/package.xml \
        && source ${ROS_ROOT}/setup.bash \
        && rosdep update \
        && rosdep install --from-paths /tmp/rosdep_ws/src --ignore-src -r -y \
        && rm -rf /tmp/rosdep_ws
    

    Because this shim is a copy, it must be updated manually when the real package.xml dependencies change.

    With either approach, isaac-ros activate --build-local installs all build dependencies into the image. At runtime, you clone the source and run colcon build directly. The dependencies are already satisfied, so the build is fast:

    # On host (once)
    cd ${ISAAC_ROS_WS}/src && git clone <your-repository>
    
    # Inside container (daily development)
    isaac-ros activate
    cd ${ISAAC_ROS_WS}
    colcon build --symlink-install --packages-up-to <your-package>
    source install/setup.bash
    

    Rebuild with isaac-ros activate --build-local after updating either the Dockerfile URL (public tab) or the shim entries (private tab).

  2. Tell the Isaac ROS CLI where to find your Dockerfile. Create or edit a .isaac_ros_common-config file at one of these locations (first match wins):

    • ${ISAAC_ROS_WS}/scripts/.isaac_ros_common-config

    • /etc/isaac-ros-cli/.isaac_ros_common-config

    Add a CONFIG_DOCKER_SEARCH_DIRS line listing your Dockerfile’s directory and the default system Dockerfile directory. Both are required because the config search is first-match-wins. If the CLI finds your config file, it stops looking and will not load the system default. Without /etc/isaac-ros-cli/docker, the base Dockerfile.isaac_ros cannot be found.

    Use absolute paths or shell variables:

    CONFIG_DOCKER_SEARCH_DIRS=(${ISAAC_ROS_WS}/docker /etc/isaac-ros-cli/docker)
    
  3. Register your image key in an Isaac ROS CLI configuration file. Workspace scope is recommended here because the image key is project-specific. It keeps the configuration alongside the Dockerfile and is automatically shared when the workspace is checked into version control.

    Create or update ${ISAAC_ROS_WS}/.isaac-ros-cli/config.yaml:

    docker:
      image:
        additional_image_keys:
          - my_team
    

    Alternatively, use the user-level file (~/.config/isaac-ros-cli/config.yaml) for personal experimentation or Dockerfiles that are not part of a specific workspace. Both scopes stack together, so that user-level and workspace-level keys are combined at runtime.

  4. Build the image:

    isaac-ros activate --build-local
    

    The first build may take several minutes. After the image is built, subsequent isaac-ros activate commands reuse the cached image without rebuilding.