ROS, Docker and WSL

ROS1 is not very well supported in Windows, but it is very useful to be able to do robot simulation on a desktop PC even when Linux systems are not available.

The best way I’ve found to do this is by combining the power of WSL2 (the Windows Subsystem for Linux) and Docker containers to run allow ROS to run in Linux with minimal overhead. It’s even possible to run the graphical applications such as Gazebo and RViz for simulation purposes. The setup is a little long-winded, so I’ve written it down in the hope it might help somebody (probably me, as I tend to forget these things).

Getting started

First, make sure WSL2 is installed on your Windows PC. If you don’t know, open up a terminal and execute

wsl -l -v

which should come back with something like this (not with the same names):

  NAME                   STATE           VERSION
* Ubuntu-20.04           Stopped         2
  docker-desktop-data    Stopped         2
  docker-desktop         Stopped         2

If it doesn’t recognise the wsl command, then WSL is not installed. If the “VERSION” column only has ‘1’s in it, then you may need to update to WSL2 from WSL.

The installation instructions from Microsoft walk you through it. You’ll need admin rights to do the install.

To set the default version to WSL 1 or WSL 2 when a new Linux distribution is installed, use the command:

wsl --set-default-version <Version#>

replacing <Version#> with either 1 or 2.

If you’ve had WSL installed for a while, it might be worth doing wsl --update and then restarting it after wsl --shutdown. This is because the most recent iteration has the ability to run linux GUI applications without any other software and at time of writing this was quite new. And also rather gobsmacking. Sadly, it doesn’t work directly with Docker images, because it requires a modified linux distribution. But there’s another way, as we will see.

Install an X server

To use GUI apps running in Docker containers, the host PC needs to be running an X server. There are several to choose from. The one I use is VcXsrv, which is free and does a pretty good job. This will need to be running on your host PC if you wnt to use a GUI app from a Docker container.

Make sure Git is installed

I don’t need to remind you of this.

Make sure Visual Studio Code is installed

You should also add the Git extension and the Docker extension

Make sure Docker Desktop is installed

You don’t have to use Docker to work with ROS on WSL, but it offers some benefits. Most notably, you can create separate docker images for ROS1, ROS2, and different OS/version combinations of those. You can install device-specific libraries and versions of libraries without messing up your global installation. And you can share effective installations with other people. It’s worth the effort.

You don’t need to use Docker Desktop, either. If you’re happy with command line docker, that’s fine. I like the convenience of the GUI app.

You can get Docker Desktop from their website https://www.docker.com/products/docker-desktop/. They’ll suggest you sign up for an account, but you don’t need to. You can use the direct download link if you wish.

Create the base Docker image

Create the base docker image using the docker file:

FROM osrf/ros:noetic-desktop

RUN apt-get update
RUN apt-get install -y git && apt-get install -y python3-pip
RUN apt-get install -y ros-noetic-ros-control && \
    apt-get install -y ros-noetic-ros-controllers && \
    apt-get install -y ros-noetic-gazebo-ros-control && \
    apt-get install -y ros-noetic-joint-state-publisher-gui && \
    apt-get install -y ros-noetic-rqt-robot-steering

RUN mkdir -p /root/limo_ws/src && cd /root/limo_ws/src && \
    git clone https://github.com/limo-agx/limo.git && \
    git clone https://github.com/limo-agx/limo_desktop.git && \
    git clone https://github.com/limo-agx/limo_simulator.git && \ 
    cd /root/limo_ws &&\
    rosdep install --from-paths src --ignore-src -r -y

SHELL ["/bin/bash", "-c"]

RUN cd /root/limo_ws &&\
    source /opt/ros/noetic/setup.bash && \
    catkin_make && \
    echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc

Build the docker volume (this will take some time):

docker build . --tag=robots/r1_noetic_limo_sim

Then create the compose.yaml file:

services:
  app:
    container_name: r1_limo_n
    image: robots/r1_noetic_limo_sim:latest
    stdin_open: true # docker run -i
    tty: true        # docker run -t
    environment:
      - DISPLAY=host.docker.internal:0.0
    volumes:
      - test-volume:/root/test

volumes:
  test-volume:

docker-compose up will start the container. It will also create a new docker volume, mounted at /root/test in the container’s filesystem. Changes to the contents of this volume will persist between sessions (and can be shared amongst containers) whereas changes to the filesystem of the container itself will be lost as soon as it shuts down. The volume is therefore the sensible place to put development files.

Developing code in the docker volume

Although Docker volumes are stored locally on the computer, It is not easy to access the files inside them. When they are mounted in a docker container, volumes appear as part of the container’s file system and any applications which would normally access the file system can read or write them. This means that one way to edit the files within a volume is to use editing tools in the container. As we’ve seen it is possible to run GUI applications from within a container, so a text editor like gEdit will work perfectly well for this purpose.

However, there is a better solution. Microsoft’s Visual Studio Code editor has an extension which enables it to edit files within a docker volume as if they were files hosted in the local file system. This makes it a very appealing way to edit files that are inside a container even while the container is running. It also makes it easier to manage those files through source controls such as Github because they are treated as local files rather than files in the container and so VS Code manages the required SSH authentication. It becomes much more problematic to operate SSH within a container, because the required keys must be stored as part of the image (and will therefore be shared if the image is, which is a security concern).

Procedure for setting up new development in the volume

Set up a new repository on Github, and make sure it creates a .gitignore file with a ROS template. Clone it to a local folder on the host machine (this is only temporary). I’ll assume this is called Ros1Test for the time being. You’ll use this later.

Make sure that the volume has been created by your docker compose up command. You can check this in the Docker Desktop app, or from the command line using docker volume list which will probably report something like

DRIVER    VOLUME NAME
local     docker_test-volume
local     ros-connect-four
local     vscode

docker_test-volume is the one we defined in the compose.yaml file, so it’s definitely there!

Now fire up Visual Studio Code, and make sure you’ve got the Docker extension installed. Click on the little whale icon, and you’ll be offered something like this:

VS Code files!200

Right-clicking on the docker_test-volume and selecting ’explore in a dev container’ menu item will start a new container and open this volume up as a file system in it. You can then edit the files as if they were on the local filesystem. It’ll be empty to begin with. Now we need to set this up so that it’s under source control, and is configured as a catkin workspace for ROS development. This is the slightly clunky part, because some of it is done in Windows, and some on the command line in the container.

Now, use drag and drop from Windows Explorer to copy all the files (including the hidden .git folder) from the cloned Ros1Test repository you made earlier to the volume in VS Code. If you didn’t create an appropriate .gitignore file at the same time as the repository, now would be a good time to do that, before we start adding more files.

Here’s a sample .gitignore for ROS1.

Now you can switch back to your container, and do some command line stuff to set up the ROS workspace. As you do this, you will see files appearing in the volume in Visual Studio Code, because both containers are using the same volume for persistent storage.

cd /root/test
mkdir src
source /opt/ros/noetic/setup.bash
catkin_make

If all is well, this should result in the creation of a number of files and folders, almost all of which will be ignored by source control. You might think that the CMakeLists.txt file should be added to git, but this is not a good idea. It’s actually a symbolic link created by catkin, and its references will not survive source control. It will be recreated by catkin as needed in any case.

Now you should be able to use VS code to commit and push your source code. Further development (for example the ROS Tutorials) can be done from the command line and/or through VS code. Just remember that while commits can be done from the command line in the container ,pushes can only be done from VS Code (because of the SSH issue).

Next: simple ROS tutorial using containers