ROS 2 Humble is the latest LTS of the Robot Operating System (ROS), the de facto framework for robot application development. Yocto and ROS 2 allow you to build custom Linux-based production-grade operating systems for robots that obtain best performance for your use case. This article provides a walkthrough on how to build a Linux operating system with ROS 2 Humble for the NVIDIA Jetson Nano board and showcase our contribution to the ROS 2 community bringing ROS 2 Humble support for Yocto Honister release. Lastly, we show how to get better performance with ROS 2 Humble using ROBOTCORE hardware acceleration framework for ROS.

Why Yocto/PetaLinux instead of Ubuntu? production-grade robotic systems

Most people these days develop robots in Ubuntu, so it's only normal that many engineers demand Ubuntu (a developer-known rootfs) for their robotic creations. This however comes with a technical debt that often new roboticists don't consider. There're two aspects of special relevance that are often misunderstood in robotics:

  • security: cybersecurity is a process that requires a periodic effort including monitoring, research and updates of your robot's root file system (rootfs). Keeping it (your rootfs) minimal and monitored is key for a security-driven service. Regardless of whether you're cooking your own Linux rootfs or you're paying for it (someone else building it, and you pay either via telemetry data or via direct payment), a first-class security response requires you to take ownership of cybersecurity. You cannot fully externalize cybersecurity to a third party if you want your users to have a first-class security response. Also, cybersecurity needs to be observed from an attacker's perspective. While doing so, one would understand that attackers are mostly driven by financial opportunities. A common rootfs for robots is certainly a very interesting target. Besides the economics behind an attacker's mindset, from a technical perspective, compromising an operating system that's shared and common across multiple robots with common defaults (e.g. Ubuntu) is indeed a much easier target than "your own Linux distro" cooked for your specific use case and with a minimalistic attack surface (that you or someone else should study by threat modeling it). In a nutshell, you might be exposing yourself by picking a "popular" development-oriented rootfs for your robot.
  • real-time: robots are inherently deterministic machines. Information is shared across robot networks between sensors and actuators in real-time. Skipping deadlines can lead to catastrophic missbehaviors. Ensuring an OS is real-time requires all its components to execute in a time-bounded manner. General purpose development-oriented OSs like Ubuntu are generally really bad at meeting real-time deadlines for 3 main reasons: a) their Linux kernel isn't engineered enough (even when applying PREEMPT_RT patches to their kernel forks, they need lots of engineering hours from knowledgeable embedded folks to assess their real-time performance issues), b) Linux kernels need to also be real-time capable and c) there're lots of daemons and processes thought for monitoring and sending telemetry back to the OS vendor that simply break completely the real-time assumptions.

Opposed to this, production-grade embedded systems often rely on strong multidisciplinary engineering teams that build custom and minimalistic Linux distributions for a particular use-case by leveraging Yocto, a project to build embedded Linux. Rationale is that instead of relying on common development-oriented Linux distros (such as Ubuntu), Yocto allows you to build a customized Linux system for your use case. This allows you an unmatched granularity wherein you can customize from the bootloader, going through the Linux kernel and all the way into userspace libraries, such as those required to enable ROS 2 support.

ROS 2 Humble in NVIDIA Jetson Nano with Yocto

Acceleration Robotics is a firm focused on designing customized brains for robots to hasten their response time. The company creates custom compute architectures for high performance robots through hardware acceleration solutions. In a nutshell, we deliver semiconductor building blocks for robots while remaining accelerator-agnostic (FPGAs or GPUs) and as such, building custom high-performing Linux distributions becomes second nature. Adding ROS to such distributions while using Yocto or derivatives (such as PetaLinux) can be done with the meta-ros layers.

As an active member of the ROS and ROS 2 communities, we're among the early contributors of meta-ros (back in the old ROS 1 days) and first ported meta-ros to ROS 2 a few years back. To get ROS 2 Humble into custom embedded Linux OSs, our team at Acceleration Robotics contributed a series of Yocto recipes by updating the meta-ros project (see Pull Request). In total our contributions modified 60K LOC across more than 1000 files.

To get ROS 2 Humble into custom embedded Linux OSs, our team at Acceleration Robotics contributed a series of Yocto recipes by updating the meta-ros project (see Pull Request). In total our contributions modified 60K LOC across more than 1000 files.

Here is how to build a custom ROS 2 Humble embedded Linux for NVIDIA Jetson Nano board:

Step 0. Fetch meta-tegra BSP and checkout Honister's branch

git clone https://github.com/OE4T/tegra-demo-distro -b honister tegra-bsp-honister
 cd tegra-bsp-honister/; git submodule update --init

Step 1. Add ROS 2 Humble meta layer

git clone https://github.com/vmayoral/meta-ros -b honister-humble repos/meta-ros
ln -s $(pwd)/repos/meta-ros $(pwd)/layers/meta-ros

Step 2. Build basic example BSP for NVIDIA Jetson Nano:

. setup-env --machine jetson-nano-2gb-devkit --distro tegrademo build
bitbake demo-image-full  # get the basic demo image building

Step 3. Add meta-layers for ROS 2 Humble and configure them in Yocto/PetaLinux:

The meta-ros layer should be configured to be built by editing build/conf/bblayers.conf and adding the following at the end:

  <your-project-path>/layers/meta-ros/meta-ros2 \
  <your-project-path>/layers/meta-ros/meta-ros2-humble \
  <your-project-path>/layers/meta-ros/meta-ros-common \

In addition, add the following (e.g. at the beginning of the file) as well, which defines some variables to be used by the meta-ros recipes:

# define the ROS 2 Yocto target release
ROS_OE_RELEASE_SERIES = "honister"

# define ROS 2 distro
ROS_DISTRO = "humble"

Step 4. Create a Yocto recipe image including ROS 2 Humble:

There're various ways to build the meta-ros recipes. The following creates a new Yocto image recipe with bare minimum packages required to execute pub/sub examples while including ROS 2 Humble with two open source DDS implementations:

demo-image-ros2.bb
mkdir -p layers/meta-tegrademo/recipes-demo/images/
cat << 'EOF' > layers/meta-tegrademo/recipes-demo/images/demo-image-ros2.bb
require demo-image-full.bb

SUMMARY = "An image including a bare-minimum installation of ROS 2 and including some basic pub/sub examples. It includes two DDS middleware implementations, FastDDS and Cyclone DDS"
DESCRIPTION = "${SUMMARY}"

inherit ros_distro_${ROS_DISTRO}
inherit ${ROS_DISTRO_TYPE}_image

TOOLCHAIN_HOST_TASK:append = " nativesdk-packagegroup-cuda-sdk-host"

ROS_SYSROOT_BUILD_DEPENDENCIES = " \
    ament-lint-auto \
    ament-cmake-auto \
    ament-cmake-core \
    ament-cmake-cppcheck \
    ament-cmake-cpplint \
    ament-cmake-export-definitions \
    ament-cmake-export-dependencies \
    ament-cmake-export-include-directories \
    ament-cmake-export-interfaces \
    ament-cmake-export-libraries \
    ament-cmake-export-link-flags \
    ament-cmake-export-targets \
    ament-cmake-gmock \
    ament-cmake-gtest \
    ament-cmake-include-directories \
    ament-cmake-libraries \
    ament-cmake \
    ament-cmake-pytest \
    ament-cmake-python \
    ament-cmake-ros \
    ament-cmake-target-dependencies \
    ament-cmake-test \
    ament-cmake-version \
    ament-cmake-uncrustify \
    ament-cmake-flake8 \
    ament-cmake-pep257 \
    ament-copyright \
    ament-cpplint \
    ament-flake8 \
    ament-index-python \
    ament-lint-cmake \
    ament-mypy \
    ament-package \
    ament-pclint \
    ament-pep257 \
    ament-pycodestyle \
    ament-pyflakes \
    ament-uncrustify \
    ament-xmllint \
    cmake \
    eigen3-cmake-module \
    fastcdr \
    fastrtps-cmake-module \
    fastrtps \
    git \
    gmock-vendor \
    gtest-vendor \
    pkgconfig \
    python-cmake-module \
    python3-catkin-pkg \
    python3-empy \
    python3 \
    python3-nose \
    python3-pytest \
    rcutils \
    rmw-implementation-cmake \
    rosidl-cmake \
    rosidl-default-generators \
    rosidl-generator-c \
    rosidl-generator-cpp \
    rosidl-generator-dds-idl \
    rosidl-generator-py \
    rosidl-parser \
    rosidl-runtime-c \
    rosidl-runtime-cpp \
    rosidl-typesupport-c \
    rosidl-typesupport-cpp \
    rosidl-typesupport-fastrtps-cpp \
    rosidl-typesupport-interface \
    rosidl-typesupport-introspection-c \
    rosidl-typesupport-introspection-cpp \
    foonathan-memory-vendor \
    libyaml-vendor \
"

IMAGE_INSTALL:append = " \
    ros-base \
    examples-rclcpp-minimal-action-client \
    examples-rclcpp-minimal-action-server \
    examples-rclcpp-minimal-client \
    examples-rclcpp-minimal-composition \
    examples-rclcpp-minimal-publisher \
    examples-rclcpp-minimal-service \
    examples-rclcpp-minimal-subscriber \
    examples-rclcpp-minimal-timer \
    examples-rclcpp-multithreaded-executor \
    examples-rclpy-executors \
    examples-rclpy-minimal-action-client \
    examples-rclpy-minimal-action-server \
    examples-rclpy-minimal-client \
    examples-rclpy-minimal-publisher \
    examples-rclpy-minimal-service \
    examples-rclpy-minimal-subscriber \
    demo-nodes-cpp \
    demo-nodes-cpp-rosnative \
    demo-nodes-py \
    cyclonedds \
    rmw-cyclonedds-cpp \
    tmux \
    python3-argcomplete \
    glibc-utils \
    localedef \
    rt-tests \
    stress \
    ${ROS_SYSROOT_BUILD_DEPENDENCIES} \
    opencv-staticdev \
    lttng-tools lttng-modules lttng-ust \
    libstdc++ \
    libstdc++-dev \
    libnvvpi1 \
    libnvvpi1-dev \
"

IMAGE_LINGUAS = "en-us"
GLIBC_GENERATE_LOCALES = "en_US.UTF-8"

EOF

Step 5. Build the image

What's left is to build the project and generate the embedded artifacts desired (kernel, bootloader firmware, rootfs, sysroot, etc.):

. setup-env --machine jetson-nano-2gb-devkit --distro tegrademo build
bitbake demo-image-ros2

This will take a while and in time. Once it finalizes, you'll have your rootfs with ROS 2 Humble 🙂.

ROBOTCORE™ to accelerate your robots

So, now that you have a custom ROS 2 Humble embedded Linux, how do you improve ROS 2 Humble beyond its CPU-centric execution? By using hardware acceleration in the Jetson Nano GPU. To improve your robot's performance and speed it up you should rely on hardware acceleration. The NVIDIA Jetson Nano can speed up ROS computations with its GPU and our work at Acceleration Robotics focuses on getting you everything you need to create robot cores to boost your ROS 2 Humble architectures with NVIDIA Jetson Nano.

ROBOTCORE™ Hardware Acceleration Framework for ROS: ROBOTCORE™ helps build custom compute architectures for robots, or robot cores, that make robots faster, more deterministic and power-efficient. Simply put, it provides a development, build and deployment experience for creating robot hardware and hardware accelerators similar to the standard, non-accelerated ROS development flow. 
ROBOTCORE | Hardware Acceleration framework for ROS
ROBOTCORE™ helps build custom compute architectures for robots, or robot cores, that make robots faster, more deterministic and power-efficient.

ROBOTCORE™ improves robotics development productivity

ROBOTCORE™ implements the ROS 2 Hardware Acceleration Architecture and Conventions REP and supports the most popular hardware acceleration solutions and development kits to build robots with hardware acceleration and ROS. While doing so, ROBOTCORE™ simplifies the ROS 2 development flow for accelerators providing pre-packaged firmware artifacts that allow you to improve your robotics development productivity. With ROBOTCORE™ building accelerators takes just the following:

# 1. Create ROS 2 workspace
mkdir -p ~/ros2_ws/src; cd ~/ros2_ws
wget https://<your-customer-id-url>/humble_repos.ros
vcs import src --recursive < humble_repos.ros

# 2. build your workspace for dev. machine arch
colcon build --merge-install  

# 3. source the overlay to enable ROBOTCORE™
source install/setup.bash  

# 4. build your workspace for embedded arch
#    and build acceleration kernels altogether
colcon build --merge-install --mixin jetson_nano

Get in touch to acquire a ROBOTCORE™ license including documentation, examples and reference designs.