Setup ROS2 with CLion and Docker

6 minute read



I’ve been working with ROS since my sophomore year in undergrad. I enjoy working with robots and teaching people the basics of ROS and how to get up and running. My first job out of college with AWS RoboMaker was open source development for ROS2!

What bothers me to this day is how difficult it is to get up and running with ROS. As if the learning curve isn’t enough, setting up a good development workflow is pretty annoying in my opinion. There’s no standard workflow or tools (a la virtualenv’s for python or gradle) that come with out-of-the-box support for many IDEs and other tools.

The ecosystem is still weak in my opinion and the only tool you get is colcon, the only supported way to build ROS2 packages 1. AWS RoboMaker is a great (commercial) tool for getting setup with a ROS environment and has a good end-to-end development workflow, but I can’t fork over $300/month for a beefy EC2 running ROS.


Why another workflow

I wrote this guide in the hopes that some poor soul (i.e. future me) will find this helpful when setting up their ROS development workspace.

I’ve gone through various approaches and found this to be the least obtrusive and fastest workflow in the long run.

Some questions on my approach:

Why Docker?

Docker is the solution for keeping your system environment clean. To the best of my knowledge, there is no better or easier way to isolate a workspace than to create Docker container (which is what we did at RoboMaker with launch_ros_sandbox).

Why CLion?

It’s a great IDE overall and I value code completetion and insights. Yea vim is great, powerful, extensible, etc. but I want to get up and running fast. I’ve also been able to get it for free thanks to the academic license but it’s also generally available at any respectable company.


1. Install Docker

Follow the official installation guide for Docker here.

2. Create a Dockerfile for Your Workspace

You’ll need to create a Dockerfile that configures an SSH daemon for CLion and any other user specific config you’d like. I usually put this in my ros_ws folder (i.e. where src and build usually are).

Here’s the minimal Dockerfile you’ll need:

# Replace with the distro you want to use
FROM ros:foxy

RUN apt-get update \
  && apt-get upgrade -y \
  && apt-get install -y ssh \
      build-essential \
      gcc \
      g++ \
      gdb \
      clang \
      cmake \
      rsync \
      tar \
      python \
      wget \
  && apt-get clean

RUN ( \
    echo 'LogLevel DEBUG2'; \
    echo 'PermitRootLogin yes'; \
    echo 'PasswordAuthentication yes'; \
    echo 'Subsystem sftp /usr/lib/openssh/sftp-server'; \
  ) > /etc/ssh/sshd_config_test_clion \
  && mkdir /run/sshd

# Change the password 'password' to something more secure
RUN useradd -m user && yes password | passwd user

CMD ["/usr/sbin/sshd", "-D", "-e", "-f", "/etc/ssh/sshd_config_test_clion"]

With my Dockerfile, I add vim so I can edit in the terminal as needed. I also modified root’s password using RUN echo 'root:password' | chpasswd. Obviously change the password to something more secure :).

3. Build the Image and Run the Container

Navigate to the directory with your Dockerfile and run:

docker build -t ros-dev .

You can change ros-dev to whatever name you want your image tagged with.

Now run your container with:

docker run -td --cap-add sys_ptrace -p127.0.0.1:2222:22 --name clion_remote_env ros-dev

Pro-tip: I usually add -v /Users/allabana/ros_ws:/ros_ws to mount my ROS workspace into the container.

The -td flags tell docker to allocate a pseudo-tty and run in the background as a daemon. --cap-add sys_ptrace adds the ptrace capability, which is necessary for debugging. The -p part specifies a port mapping. It exposes the default SSH port inside the container (22) as port 2222 on the host environment. You can specify any available port numbers here.

Ssh into your Docker container as if it were a remote machine to verify everything is working.

ssh user@localhost -p2222

You might need to clear cached SSH keys if you’ve ssh’ed into a host with similar settings before:

ssh-keygen -f "$HOME/.ssh/known_hosts" -R "[localhost]:2222"

4. Setup CLion

Most of the steps here are borrowed from the official Intellij Tutorial on CLion: Toolchains in Docker.

Open up your CLion settings/preferences and add a new remote toolchain. Call it whatever, but I’m calling it Docker. Use the credentials we used in the Dockerfile to setup SSH. Make sure to set it as the default.

CLion Toolchain Settings

5. Setup your Workspace

We need to trigger at least one build in our container so that we can get all the environment variables CLion needs. IMO, I consider this step to be a workaround and there should be a better way to automate it somehow.

ssh user@localhost -p2222
# We default to a `sh` terminal so run `bash` if you want a Bourne Again SHell
cd /ros_ws
# Change according to your distro
. /opt/ros/foxy/
colcon build

Source the workspace’s file to setup your environment with the new build.

source install/

Now run the following script to get a string of all the environment variables CLion needs to build a package.

for e in ${ros_env}; do
echo "$env_string"

Copy and paste the output into CLion’s CMake environment setting.

CLion Environment Settings

Reload the CMake project and you’re good to go! Now CLion will provide you with auto-completion and code hints. The most helpful feature IMO is being able to easily write and debug tests.

What Didn’t Work

Using a CMakeLists in the Top Level Workspace

Dan (@rotu) created a gist of a top level CMakeLists for a ROS2 Workspace. While this does provide IDE features, I couldn’t get running/debugging nodes/test working. CLion kept complaining that it couldn’t find the file for the target executable tests.


Some links that proved to be helpful when setting up this workflow.

  1. I appreciate the work put into this amazing tool, but ROS2 needs some good UX and colcon doesn’t provide good developer UX. 

Leave a Comment