/ros2-workspace-template

Template to use ROS2 workspace in Dev Container

Primary LanguageShell

ros2-workspace-template

Template for ROS2 workspace using VS Code Dev Containers & Docker Compose.

  • Use Dev Containers: Clone Repository in Container Volume... in VS Code's Command Palette to auto-magically setup everything!
    • To re-open repository, either use File > Open Recent or repeat the above with the exact SAME url.
  • For customization, do a global find & replace for (OPTION).
    • Remember to Dev Containers: Rebuild Container afterwards!
  • GUI apps are viewable via noVNC (VNC client web app) hosted on http://localhost:6080/.
    • The password is password!

Table of Contents

Options

(OPTION) marks key options to consider before creating the Dev Container. Some of the (OPTION)s work together to activate the features listed below:

Mount Point /data

Note: If using Dev Containers: Clone Repository in Container Volume..., the host folder path must be absolute. It is possible to use $USERPROFILE (Windows) or $HOME (Linux) for absolute paths. Otherwise, the host folder path would be relative to the Docker Compose file location.

Mount points are used to mount a folder from the host into the container. An example for mounting a folder to /data is included in docker-compose.dev.yml as an (OPTION). /data can be used to share anything from the host with the container (e.g., config files, models, databases). Also remember to:

While one mount point is sufficient, more can be added by following /data's example. See https://docs.docker.com/storage/bind-mounts/ for more info.

VNC & RQT in Production Image

By default, noVNC & RQT are not installed in the production image to save space. It is recommended to use ROS CLI or create a proper API instead to manage ROS systems. However, they can be enabled by following (OPTION)s in Dockerfile. This can be convenient for early stages of deployment.

Other Features

requirements.txt Escape Hatch

Some dependencies may be unavailable from the rosdep package manager (check ROS Index). For Python dependencies, they should be added to a requirements.txt created within the ROS package. The ROS package's requirements.txt should then be composed into the workspace's requirements.txt (example in requirements.txt). For other dependencies, they should be added to both Dockerfiles. See https://github.com/ros/rosdistro/blob/master/CONTRIBUTING.md#rosdep-rules-contributions with regards to adding new packages to rosdep.

VS Code Tasks

For developer convenience, some common tasks are present in tasks.json. Use them by opening the Command Palette and typing task. The following tasks are available:

  • rosdep install dependencies: Install all dependencies of the current workspace.
  • colcon build all: Build all (detected) ROS packages.
  • colcon build specific: Build a specific ROS package.
  • update package index: Update Ubuntu and ROS package indexes.

Docker Image Distribution

See https://docs.docker.com/engine/reference/commandline/docker/ for more info.

Building

Note: If using Dev Containers: Clone Repository in Container Volume... on Windows, follow https://code.visualstudio.com/docs/containers/choosing-dev-environment#_windows-subsystem-for-linux to ensure built images are stored on the host computer's image repository.

docker build . -t organization/repo:vx.x.x -t organization/repo:latest

Images can have multiple names tagged to them. Tagging images with the version number and as latest helps when distributing images.

Exporting

Note: Run this command on the host computer rather than in the Dev Container.

docker save organization/repo:vx.x.x organization/repo:latest -o repo-vx.x.x.tar

Compressing the image afterwards using xzip is recommended to save space. Docker is able to load compressed images (i.e., repo-vx.x.x.tar.xz) without decompressing manually.

Importing

docker load -i repo-vx.x.x.tar.xz

Imports the image and its names. It will still be tagged as organization/repo:vx.x.x and organization/repo:latest, conveniently replacing the previous latest.

VS Code Extension Suggestions

Both devcontainer.json and extensions.json are configured such that VS Code will automatically install some extensions. These are highly recommended for developer experience.

Code Formatting

black is used to format Python code due to its uncompromising design. Imports are also automatically sorted using compatible rules. See settings.json for the configuration.

Dev Container Lifecycle Hooks

devcontainer.json allows adding lifecycle hooks which can be useful for special cases. See the hooks folder for some examples.

Dev Container using Docker Compose

Instead of using Dev Container with a Dockerfile, this template uses it with Docker Compose instead. This is done for a few reasons:

  • Include example of how to configure Docker for ROS to communicate across containers.
  • Docker Compose is closer to real world deployment scenarios.

Tips

example_module

example_module's README.md provides instructions on how to create a git submodule and add ROS packages to it. It also contains a simple pub-sub launch file that can be used to test bandwidth & latency. To remove example_module:

git rm example_module

git Submodules

Note: The template will clone missing submodules for you by default.

It is recommended to add custom ROS packages to the workspace via git Submodules. However, when cloning a repository using git, it will not clone submodules by default. In order to clone submodules, use:

git clone --recurse-submodules

If the repository is already cloned and has empty submodules, do:

git submodule update --init --recursive

If you want git to clone submodules by default, try:

git config --global submodule.recurse true

Otherwise, use Github Desktop, which uses --recurse-submodules by default.

Nonetheless, when submodules are cloned, they will be in a detached state, which prevents committing. Switching submodules to the main branch can either be done through VS Code's Source Control tab, or:

git submodule foreach --recursive git checkout main

This is done for you automatically if using a named volume to store the repository.

Update Package Indexes

The rosdep and Ubuntu package managers rely on a local cache of their package index. If the package index is outdated, it may not contain any active package distribution server, leading to package downloads failing. Hence, it is recommended to periodically re-download the package index:

apt-get update
rosdep update

Minimize changes to the Dockerfile

When a step in the Dockerfile is changed, subsequent steps are invalidated and need to be rebuilt. Furthermore, ROS workspaces with the same Dockerfile share cache, resulting in less disk usage and shorter rebuilds.

The current Dockerfiles should work in most cases without needing edits. Nonetheless, if the Dockerfile becomes too complex, re-organizing it is fine. See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ for more info on Docker layer caching and other Docker tips.

Change ROS Distro

To change ROS Distro, do a global search for the current distro (humble) and replace as necessary with the new distro. Afterwards, rebuild the Dev Container.

Troubleshooting

Setup Issues

Build Issues

  • Try deleting the build and install folders before rebuilding all packages.

Runtime Issues

  • rosdep has no version lock, which means there is no protection against breaking changes when packages update.
  • ROS launch files aren't symlinked unlike Python code.
    • Rebuild the package when launch files are modified.