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 |
|
Read-only |
Default values shipped with the Isaac ROS CLI.
This file is a useful reference for the CLI’s configuration schema.
|
System |
|
Managed by the CLI |
Config written to by the Isaac ROS CLI. |
User |
|
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 |
|
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 |
|---|---|
|
Base image for Isaac ROS development. |
|
Dependencies for RealSense cameras. |
|
Dependencies for GR00T Workflow. Isaac ROS Physical AI packages, such as |
|
Deprecated image key for platform-specific dependencies for CUDA and other NVIDIA libraries on Ubuntu 24.04 Noble. |
|
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#
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 setsBASE_IMAGEto the previous layer’s output when chaining Dockerfiles.See
Dockerfile.realsenseandDockerfile.zedunder/etc/isaac-ros-cli/docker/for real-world examples.Pre-installing
rosdepdependencies for building from sourceWhen building a ROS package from source,
rosdep install --from-pathsresolves dependencies from thepackage.xmlin the source tree. Because the source tree is not available duringdocker build(it lives on the host and is mounted at runtime), you can provide the dependency information at build time so thatrosdepresolves and installs the same system packages without needing the full source code.If the
package.xmlis publicly accessible, fetch it directly withcurl: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.xmlat build time, so dependencies stay in sync with the source of truth automatically. Update the URL or branch when the targetpackage.xmlchanges location.If the
package.xmllives in a private repository that is not accessible duringdocker build, create a minimal shimpackage.xmlinline in the Dockerfile. Copy only the<depend>,<build_depend>, and<exec_depend>entries from your realpackage.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.xmldependencies change.With either approach,
isaac-ros activate --build-localinstalls all build dependencies into the image. At runtime, you clone the source and runcolcon builddirectly. 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-localafter updating either the Dockerfile URL (public tab) or the shim entries (private tab).Tell the Isaac ROS CLI where to find your Dockerfile. Create or edit a
.isaac_ros_common-configfile 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_DIRSline 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 baseDockerfile.isaac_roscannot be found.Use absolute paths or shell variables:
CONFIG_DOCKER_SEARCH_DIRS=(${ISAAC_ROS_WS}/docker /etc/isaac-ros-cli/docker)
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.Build the image:
isaac-ros activate --build-local
The first build may take several minutes. After the image is built, subsequent
isaac-ros activatecommands reuse the cached image without rebuilding.