Skip to content

Development environment

Will Heitman edited this page Oct 30, 2021 · 2 revisions

Note from Will: I wrote this to give us all a head start with Docker. However, I am not a Docker expert at all! I'm still a beginner. Please edit anything here if you find an error, an alternative, or if you just want to add some tips.


Our goal is to use a development that:

  • Can be easily replicated on any host machine
  • Will run the same way, no matter the host
  • Can be easily shared and installed

We draw inspiration from Autoware's ADE by using Docker. However, we choose a more granular approach. Our approach is powerful, portable, and lightweight.

About Docker

Docker is a developer framework that breaks the various parts of a runtime environment into containers, where each one performs a specific task. Each container can be easily added, removed, and shared across many individual environments. The best part: the behavior of a Docker container is not dependent on its host, so a container running on a smartphone will produce the same results as it would on a supercomputer (albeit slower). I would highly recommend reading more about Docker here.

Starting the environment

Let's walk through how to start our development environment, and afterwards we can look at the details.

The whole env revolves around a single file called docker-compose.yml. It's just a short text file that defines the different parts of our env and how they interact which each other. The file is loaded by Docker Compose, which is the official tool to run multiple Docker containers together. Our file as of 3/6/21 looks like this:

version: "3.9"
services:
        base:
                build: ./build
                image: ghcr.github.io/Nova-UTD/vde-base
                command: tail -F /dev/null #keep the base running
                hostname: basecontainer # self-explanatory
                volumes:
                        - "ros-volume:/opt/ros"
                        - "autoware-volume:/opt/autoware"
        autoware:
                image: registry.gitlab.com/autowarefoundation/autoware.auto/autowareauto/arm64/binary-foxy:master
                volumes:
                        - "autoware-volume:/autoware"
        ros:
                image: ros:foxy
                volumes:
                        - "ros-volume:/ros"
volumes:
        ros-volume: {}
        autoware-volume: {}

Notice that we define three services: base, autoware, and ros.

  • autoware pulls the official Docker image from their GitLab registry. This is exactly where ADE gets it. We tell Docker to put the files in a folder called "autoware", and Autoware's official Dockerfile handles the setup from their.
  • ros pulls the official ROS2 Foxy image from Docker Hub, which is Docker's official repository for Docker images. Since it's coming from the official source, we just need to put ros:foxy.
  • base is our entrypoint. You can think of it of our virtual machine that we log into (although it's a bit different). All of the other containers plug into this one.
    • build: This is where the Dockerfile for our base container is stored. To be honest, I'm not sure how this works since we're specifying a remote image. I needed this for creating the base image, and I think we'll need it to edit the image later on.
    • image: We pull it from our GitHub organization's container registry, which is accessed through ghcr.io/Nova-UTD/. While anyone can pull the container, you'll need to create a Personal Access Token to push new versions. Learn more here. Note that the token is already added to the Jetson, so no login is necessary when working from there.
    • command: We run a command that keeps our base container open. Without this the container would immediately close, since we don't assign it any tasks to work on.
    • hostname: This is the hostname of our base container. Without it, the hostname is a random mess (I think it's the container ID).
    • volumes: Here we "mount" the volumes from ros and autoware. We choose to mount them to the customary /opt, but it could be anywhere.

Notice that our three containers can only communicate through the volumes they share. Otherwise, you can think of them as separate machines altogether. It's possible to modify our config so that the containers can communicate on a shared network as well. The ROS and Autoware containers simply provide their libraries for us to use, but containers can be much more powerful.

Installing the environment for first use

This is simple:

  1. Install Docker, Docker Compose, and the NVIDIA Container Runtime. The last tool is needed for GPU-accelerated tasks, and is a prereq for Autoware.Auto. Step 1 is the hardest by far-- everything is is a breeze.
  2. Download our docker-compose.yml file, or just paste its contents into your own file. Put this file in an empty folder. I called mine "base/", but you can call it whatever.
  3. Using your terminal/command line, navigate to the new folder and run docker-compose up -d. The "-d" tells Compose to run in the background.
  4. Now run docker-compose exec -u docker base bash run enter our base container. That's it!

If you're on Ubuntu, you can optionally download our start.sh script into /base. At the moment it just runs these two commands for you. We can add more functionality later on as needed. Don't forget to give it proper permissions with sudo chmod +x start.sh.

Tested host systems

  • Jetson TX2 (Ubuntu 18.04, arm64)
Clone this wiki locally