Why ROS 2 and Docker
One of my primary objectives is to acquire knowledge on ROS 2, and I strongly believe that this project would be an excellent opportunity to utilize ROS 2. Moreover, I am convinced that Docker could play a crucial role in this project, providing multiple benefits as follows:
Docker can facilitate cross-compiling and building applications that are compatible with both desktop machine (X86/amd64) and Jetson Nano (arm64) devices. This is especially advantageous as it allows for fast compilation on powerful desktop machines, which can then be used on the low-power Jetson Nano processor.
Finally, with Docker, I can conveniently package all the application files along with their dependencies, simplifying deployment across multiple DonkeyJets.
Multiplatform Docker Build
Being able to create a docker image that works on multiple platforms is crucial. One question that arises is why it’s necessary to support a X86 machine if the intention is to use the application on Jetson Nano. I have three reasons for this. First, sometimes the computational demands of certain algorithms are too high for Jetson Nano, so some of the ROS nodes will run on a desktop machine on the same network. Therefore, we require the same ROS 2 environment on the desktop. Second, the robot lacks a screen, and for debugging purposes, it’s necessary to visualize certain data, sensors, or messages. In such cases, I’ll use the ROS environment on the desktop. Third, it is cool 🙂
In this blog I would like to cover building our base docker images that has both CUDA and ROS 2 for both arm64 and amd64 machines.
I am using two different docker image as the base. One that runs on amd64 and one that run on arm64. For the amd64 I am using nvcr.io/nvidia/cudagl:11.4.2-devel-ubuntu20.04 and for the arm64 I am using nvcr.io/nvidia/l4t-jetpack:r35.2.1 . There are clever ways to fit these two base images into a single docker file.
I am using docker buildx to build images for multiple platforms.
ros2_base.Dockerfile
It’s worth noting that the initial three lines of the Dockerfile are crucial in ensuring compatibility with both amd64 and arm64 architectures. Additionally, it’s important to remember that this Dockerfile will be used to create two distinct images, not just one. Throughout the build process, docker buildx defines the ${TARGETARCH}
variable based on the specified platforms in the build command, and selects the appropriate container accordingly based on the naming convention.
We are building ROS 2 from the source in this Dockerfile based on Ubuntu 18.04. It is possible to start with Ubuntu 20.04 as base and directly use the binary packages to install ROS 2 but we would lose the use of CUDA on Jetson Nano since there is no docker image for Jetson Nano with Ubuntu 20.04 and CUDA support (At least I couldn’t make it work). The CUDA version inside the docker image would be higher than the CUDA version in the host Jetson and then none of the CUDA API calls would work properly inside the container (learned the hard way). To test that I used CUDA Samples git repository, specifically queryDevice
example to make sure it returns as expected inside the container on the Jetson Nano.
# define a registry to push the images to
export REGISTRY=<your dockerhub username>
# create new buildx that support multiple platforms
docker buildx create --use --driver-opt network=host --name MultiPlatform
# build the image for two different platforms and push the images
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f ros2_base.Dockerfile \
-t ${REGISTRY}/ros2_base:latest \
--push .
Keep in mind that the execution of this command may require a considerable amount of time to complete. This is due to the fact that it’s building two distinct images, and using an emulator to build for the arm64 platform on an amd64 machine. Additionally, certain commands take some time to execute since we are compiling ROS 2 foxy from source in the docker image.
docker run \
--rm \
-it \
--runtime nvidia \
--network host \
--gpus all \
-e DISPLAY \
${REGISTRY}/ros2_base:latest \
bash
Conclusion
At this point, we should have a foundational Docker image that meets our requirements – it includes CUDA and ROS 2, and can be executed on both amd64 and arm64 platforms. Moving forward, we’ll utilize this image to run ROS 2 nodes, and I’ll also create additional docker images that build on top of it, such as those that support RealSense sensors. It’s an exciting time!
Hey,
we are a group of students and are working on basically the some projekt as you do (in the end we would like to create some SLAM algorythm’s with Matlab Simulink).
I really like your ideas and approach to this project, so big thumbs up :).
Currently we are also trying to setup ROS(2) on our Jetson Nano (Ubuntu 18.04) but struggling with the fact that it is not supported for this version.
It would be really appriciated if you could give us some more detailed information about how to set up ROS2 on the Jetson Nano and in the next step get the PCA9685 running.
Thanks a lot in advance and greetings from Germany
Fabian