Create Overlay Docker Images

When working with MoveIt Pro, you will likely create new packages which may contain:

  • New Behaviors and Objectives
  • New robot configuration packages
  • Descriptions and drivers for a new robot
  • Novel algorithms currently not present in MoveIt Pro

For many of these applications, you can mount a user workspace directly into the MoveIt Pro Docker containers. However, there may be some use cases where this may not be sufficient, such as:

  • Your workspace requires additional binary packages, where rosdep install, apt-get install, pip install, etc. is needed to build the workspace.
  • The hardware and/or algorithms you are working with require additional dependencies.
  • You want to install additional tools for debugging during development.

Creating the Overlay Image

You can create an overlay Docker image by making a Dockerfile at the root of your workspace.

To use this image with the moveit_pro utility, you must ensure there is a stage named base which installs all the needed dependencies.

This includes copying source code into the image, creating a new non-root user to that you have ownership of mounted files on the host, and installing any additional dependencies needed by your workspace.

# Specify the MoveIt Pro release to build on top of.
ARG USERNAME=studio-user
ARG USER_UID=1000
ARG USER_GID=1000

# Extend the 5.2.0 release of MoveIt Pro
FROM picknikciuser/moveit-studio:5.2.0 as base

# Create a non-root user
ARG USERNAME
ARG USER_UID
ARG USER_GID

# Copy source code from the workspace's ROS 2 packages to a workspace inside the container
ARG USER_WS=/home/${USERNAME}/user_ws
ENV USER_WS=${USER_WS}
RUN mkdir -p ${USER_WS}/src ${USER_WS}/build ${USER_WS}/install ${USER_WS}/log
COPY ./src ${USER_WS}/src

# Also mkdir with user permission directories which will be mounted later to avoid docker creating them as root
WORKDIR $USER_WS
# hadolint ignore=DL3008
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    groupadd --gid $USER_GID ${USERNAME} && \
    useradd --uid $USER_UID --gid $USER_GID --shell /bin/bash --create-home ${USERNAME} && \
    apt-get update && \
    apt-get install -q -y --no-install-recommends sudo && \
    echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} && \
    chmod 0440 /etc/sudoers.d/${USERNAME} && \
    cp -r /etc/skel/. /home/${USERNAME} && \
    mkdir -p \
      /home/${USERNAME}/.ccache \
      /home/${USERNAME}/.config \
      /home/${USERNAME}/.ignition \
      /home/${USERNAME}/.colcon \
      /home/${USERNAME}/.ros && \
    chown -R $USER_UID:$USER_GID /home/${USERNAME} /opt/overlay_ws/

# Install additional dependencies
# You can also add any necessary apt-get install, pip install, etc. commands at this point.
# NOTE: The /opt/overlay_ws folder contains MoveIt Pro binary packages and the source file.
# hadolint ignore=SC1091
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    . /opt/overlay_ws/install/setup.sh && \
    apt-get update && \
    rosdep install -q -y \
      --from-paths src \
      --ignore-src

# Set up colcon defaults for the new user
USER ${USERNAME}
RUN colcon mixin add default \
    https://raw.githubusercontent.com/colcon/colcon-mixin-repository/master/index.yaml && \
    colcon mixin update && \
    colcon metadata add default \
    https://raw.githubusercontent.com/colcon/colcon-metadata-repository/master/index.yaml && \
    colcon metadata update
COPY colcon-defaults.yaml /home/${USERNAME}/.colcon/defaults.yaml

# hadolint ignore=DL3002
USER root

Note that final steps in the Dockerfile above set up Colcon defaults by copying from a file named colcon-defaults.yaml. You can configure this file to control the build and test behavior of your ROS 2 packages. Importantly, setting symlink_install: True is necessary for syncing changes to Objectives and Waypoints between your source code and the UI.

build:
  # Setting this to true is necessary for syncing changes to Objectives and Waypoints between your source code and the UI.
  symlink-install: true
  mixin:
    # Enable ccache support
    - ccache
    # Multithreaded linker to speed up linking step during compilation
    - lld
    - compile-commands
    # Debug info and build testing for dev workflows
    - rel-with-deb-info
    - build-testing-on
    - coverage-gcc
    - coverage-pytest

test:
  event-handlers:
    - console_direct+
    - desktop_notification+

Advanced Workflows with Overlay Images

Creating a Release Container

In your existing Dockerfile, we will create a new stage called user-overlay which builds the source code for release and sets up an entrypoint (a script that executes at container startup).

FROM base as user-overlay

ARG USERNAME
ARG USER_WS=/home/${USERNAME}/user_ws
ENV USER_WS=${USER_WS}

# Compile the workspace
WORKDIR $USER_WS
# hadolint ignore=SC1091
RUN --mount=type=cache,target=/home/${USERNAME}/.ccache \
    . /opt/overlay_ws/install/setup.sh && \
    colcon build

CMD ["/usr/bin/bash"]

Next, create a docker-compose.yaml file which extends the docker-compose.yaml file that was installed with MoveIt Pro. The default location for the installed file is ${HOME}/moveit_pro/docker-compose.yaml, but feel free to change this for your setup.

version: "3.9"

services:
  # Sets common properties for other services. Should not be instantiated directly.
  base:
    # Extend the installed MoveIt Pro docker compose file.
    # Change this to match your environment, if MoveIt Pro was installed to a different location.
    extends:
      file: ${HOME}/moveit_pro/docker-compose.yaml
      service: base
    image: moveit-pro-overlay
    build:
      context: .
      target: user-overlay
      args:
        - USER_UID=${STUDIO_USER_UID:-1000}
        - USER_GID=${STUDIO_USER_UID:-1000}
        - USERNAME=${STUDIO_USERNAME:-studio-user}
    # Set the user workspace folder location.
    environment:
      - USER_WS=/home/${USERNAME:-studio-user}/user_overlay_ws

Similarly, you can extend all the services from the base image as follows. This can be directly copied from the docker-compose.yaml that is installed with MoveIt Pro.

# Additional services
# Starts the MoveIt Pro Agent and the Bridge between the Agent and the Web UI
agent_bridge:
  extends: base
  privileged: true
  # Allow the user to use the host's network video4linux and usb_device devices.
  # "c 81:* rmw": This rule specifies that the container has read, write, and mknod access (rmw) to all character devices (c) with a major number of 81 (video4linux).
  # "c 189:* rmw": This rule gives the container read, write, and mknod access (rmw) to all character devices (c) with a major number of 189 (usb_device).
  device_cgroup_rules:
    - "c 81:* rmw"
    - "c 189:* rmw"
  volumes:
    # Allow the user to run graphical programs from within the docker container.
    - /tmp/.X11-unix:/tmp/.X11-unix:ro
    # Allow access to host hardware e.g. RealSense cameras
    - /dev:/dev
  deploy:
    restart_policy:
      condition: any
      delay: 2s
  command: agent_bridge.app

# Starts the REST API for the Web UI.
rest_api:
  extends: base
  depends_on:
    agent_bridge:
      condition: service_healthy
  healthcheck:
    test: "curl -f http://localhost:3200/objectives"
    interval: 5s
    timeout: 1m
  command: rest_api.app

# Starts the robot drivers.
drivers:
  extends: base
  privileged: true
  # Ensures the drivers container has RT priority
  ulimits:
    rtprio: 99
  devices:
    - "/dev/ttyUSB0:/dev/ttyUSB0"  # Allow access to the gripper.
  command: robot.app

# Starts the web UI frontend.
web_ui:
  image: picknikciuser/moveit-studio-frontend:${STUDIO_DOCKER_TAG:-main}
  ports:
    - "80:80"
  network_mode: host

# Starts RViz for visualization.
rviz:
  extends: base
  profiles:
    - rviz
  command: bash -c "ros2 launch moveit_studio_agent developer_rviz.launch.py"

# Starts MoveIt Setup Assistant for creating MoveIt configurations.
setup_assistant:
  extends: base
  profiles:
    - setup_assistant
  command: bash -c "ros2 launch moveit_setup_assistant setup_assistant.launch.py"

Finally, you can create a .env file containing the necessary variables to use when launching MoveIt Pro. For this example, you can include the following contents.

# Robot configuration package to launch
STUDIO_CONFIG_PACKAGE=picknik_ur_mock_hw_config

# MoveIt Pro version tag
# Be careful! Changing this without understanding the consequences may break your installation.
STUDIO_DOCKER_TAG=4.0.0

# Licensing -- enter your MoveIt Pro license below
STUDIO_LICENSE_KEY=

# User name, UID, and GID to use when building the container
# Ensure these settings match your host environment for mounted file permissions.
USERNAME=
STUDIO_USER_UID=
STUDIO_USER_GID=

Now, you should be able to build and launch your MoveIt Pro overlay release image:

docker compose up

You can find a completed version of this example in the moveit_studio_ur_ws repository.

Creating a Dev Container

With the release container workflow from the previous section, every time you change your source code you will need to rebuild the Docker image entirely for the changes to take effect when launching MoveIt Pro. One way to get around this is by making a developer container (or dev container) that mounts the source code and lets you build and run it repeatedly without restarting the container.

As an example, let us extend the base target in our Dockerfile with a development target that adds a few extra packages for debugging.

FROM base as user-overlay-dev

ARG USERNAME
ARG USER_WS=/home/${USERNAME}/user_ws
ENV USER_WS=${USER_WS}

# Install any additional packages for development work
# hadolint ignore=DL3008
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && \
    apt-get install -y --no-install-recommends \
        less \
        gdb \
        nano

CMD ["/usr/bin/bash"]

You can then extend the docker-compose.yaml file with a new service named dev as follows:

# Developer specific configuration
dev:
  extends: base
  build:
    target: user-overlay-dev
  image: moveit-pro-overlay-dev
  stdin_open: true
  tty: true
  privileged: true
  volumes:
    # Mount the source code, colcon generated artifacts, and ccache
    - ./src/:/home/${USERNAME:-studio-user}/user_ws/src:rw
    - ./build/:/home/${USERNAME:-studio-user}/user_ws/build:rw
    - ./install/:/home/${USERNAME:-studio-user}/user_ws/install:rw
    - ./log/:/home/${USERNAME:-studio-user}/user_ws/log:rw
    - ./.ccache/:/home/${USERNAME:-studio-user}/.ccache:rw
    - ${HOME}/.ros/log_moveit_pro:/home/${USERNAME:-studio-user}/.ros/log
    # Allow access to host hardware e.g. RealSense cameras
    - /dev:/dev
  command: sleep infinity
  # Making a separate profile prevents this service from being built when using `docker compose build`
  # and launched when using `docker compose up`.
  profiles: ["dev"]

Note that we mount several folders in addition to the src folder of the workspace. This ensures that artifacts generated by colcon build persist between container instances.

Now, you should be able to build and launch your MoveIt Pro overlay dev container:

docker compose build dev
docker compose up dev

Once you have started the dev container, you can enter an interactive Bash session and launch one of the MoveIt Pro launch files directly. For example:

docker compose exec -it dev bash

Once inside the container, you can compile, run tests, or even launch different parts of the MoveIt Pro application.

colcon build
source install/setup.bash
ros2 launch moveit_studio_agent developer_rviz.launch.py

To run MoveIt Pro in its entirety using a dev container, you will need to attach to multiple terminals using docker compose exec -it dev bash. In separate terminals, start all the individual backend services.

agent.app
robot.app
studio_bridge.app
rest_api.app

Once these services are all up, you can launch the web app.

docker compose up web_ui

Note

Using Docker containers for development is a common practice. Many IDEs, such as Visual Studio Code and PyCharm, have built-in support for developing with Docker containers. Once you have familiarized yourself with the steps above, we recommend setting up your favorite IDE(s) to help you develop new functionality for MoveIt Pro.