First micro-ROS Application on Linux

In this tutorial, you’ll learn the use of micro-ROS with Linux by testing a Ping Pong application. In the follow-up tutorial First micro-ROS application on an RTOS, you’ll learn how to build and bring this application on a microcontroller running the RTOS NuttX, FreeRTOS, or Zephyr. Finally, in the tutorial Zephyr Emulator you’ll learn how to test a micro-ROS application on a Zephyr emulator.

Installing ROS 2 and the micro-ROS build system

First of all, install ROS 2 Humble Hawksbill on your Ubuntu 22.04 LTS computer. To do so from binaries, via Debian packages, follow the instructions detailed here.

TIP: Alternatively, you can use a docker container with a fresh ROS 2 Humble installation. The one that serves the purpose is the container run by the command:

docker run -it --net=host -v /dev:/dev --privileged ros:humble

Once you have a ROS 2 installation in the computer, follow these steps to install the micro-ROS build system:

# Source the ROS 2 installation
source /opt/ros/$ROS_DISTRO/setup.bash

# Create a workspace and download the micro-ROS tools
mkdir microros_ws
cd microros_ws
git clone -b $ROS_DISTRO src/micro_ros_setup

# Update dependencies using rosdep
sudo apt update && rosdep update
rosdep install --from-paths src --ignore-src -y

# Install pip
sudo apt-get install python3-pip

# Build micro-ROS tools and source them
colcon build
source install/local_setup.bash

These instructions will setup a workspace with a ready-to-use micro-ROS build system. This build system is in charge of downloading the required cross-compilation tools and building the apps for the required platforms.

The build system’s workflow is a four-step procedure:

  • Create step: This step is in charge of downloading all the required code repositories and cross-compilation toolchains for the specific hardware platform. Among these repositories, it will also download a collection of ready to use micro-ROS apps.
  • Configure step: In this step, the user can select which app is going to be cross-compiled by the toolchain. Some other options, such as transport, agent’s IP address/port (for UDP transport) or device ID (for serial connections) will be also selected in this step.
  • Build step: Here is where the cross-compilation takes place and the platform-specific binaries are generated.
  • Flash step: The binaries generated in the previous step are flashed onto the hardware platform memory, in order to allow the execution of the micro-ROS app. Further information about micro-ROS build system can be found here.

Creating a new firmware workspace

Once the build system is installed, let’s create a firmware workspace that targets all the required code and tools:

# Create firmware step
ros2 run micro_ros_setup host

Once the command is executed, a folder named firmware must be present in your workspace.

This step is in charge, among other things, of downloading a set of micro-ROS apps for Linux, that are located at src/uros/micro-ROS-demos/rclc. Each app is represented by a folder containing the following files:

  • main.c: This file contains the logic of the application.
  • CMakeLists.txt: This is the CMake file containing the script to compile the application.

For the user to create a custom application, a folder <my_app> will need to be registered in this location, containing the two files just described. Also, any such new application folder needs to be registered in src/uros/micro-ROS-demos/rclc/CMakeLists.txt by adding the following line:


In this tutorial, we will focus on the out-of-the-box ping_pong application located at src/uros/micro-ROS-demos/rclc/ping_pong. You can check the complete content of this app here.

This example showcases a micro-ROS node with two publisher-subscriber pairs associated with a ping and a pong topics, respectively. The node sends a ping package with a unique identifier, using a ping publisher. If the ping subscriber receives a ping from an external node, the pong publisher responds to the incoming ping with a pong. To test that this logic is correctly functioning, we implement communication with a ROS 2 node that:

  • Listens to the topics published by the ping subscriber.
  • Publishes a fake_ping package, that is received by the micro-ROS ping subscriber. As a consequence, the pong publisher on the micro-ROS application will publish a pong, to signal that it received the fake_ping correctly.

The diagram below clarifies the communication flow between these entities:


The contents of the host app specific files can be found here: main.c and CMakeLists.txt. A thorough review of these files is illustrative of how to create a micro-ROS app in this RTOS.

Building the firmware

Once the app has been created, the build step is in order. Notice that, with respect to the four-steps workflow delined above, we would expect a configuration step to happen before building the app. However, given that we are compiling micro-ROS in the host machine rather than in a board, the cross-compilation implemented by the configuration step is not required in this case. We can therefore proceed to build the firmware and source the local installation:

# Build step
ros2 run micro_ros_setup
source install/local_setup.bash

Creating the micro-ROS agent

The micro-ROS app is now ready to be connected to a micro-ROS agent to start talking with the rest of the ROS 2 world. To do that, let’s first of all create a micro-ROS agent:

# Download micro-ROS-Agent packages
ros2 run micro_ros_setup

Now, let’s build the agent packages and, when this is done, source the installation:

# Build step
ros2 run micro_ros_setup
source install/local_setup.bash

Running the micro-ROS app

At this point, you have both the client and the agent correctly installed in your host machine.

To give micro-ROS access to the ROS 2 dataspace, run the agent:

# Run a micro-ROS agent
ros2 run micro_ros_agent micro_ros_agent udp4 --port 8888

And then, in another command line, run the micro-ROS node (remember sourcing the ROS 2 and micro-ROS installations, and setting the RMW Micro XRCE-DDS implementation):

source /opt/ros/$ROS_DISTRO/setup.bash
source install/local_setup.bash

# Use RMW Micro XRCE-DDS implementation
export RMW_IMPLEMENTATION=rmw_microxrcedds

# Run a micro-ROS node
ros2 run micro_ros_demos_rclc ping_pong

Testing the micro-ROS app

Now, we want to check that everything is working.

Open a new command line. We are going to listen to the ping topic with ROS 2 to check whether the micro-ROS Ping Pong node is correctly publishing the expected pings:

source /opt/ros/$ROS_DISTRO/setup.bash

# Subscribe to micro-ROS ping topic
ros2 topic echo /microROS/ping

You should see the topic messages published by the Ping Pong node every 5 seconds:

user@user:~$ ros2 topic echo /microROS/ping
  sec: 20
  nanosec: 867000000
frame_id: '1344887256_1085377743'
  sec: 25
  nanosec: 942000000
frame_id: '730417256_1085377743'

At this point, we know that our app is publishing pings. Let’s check if it also answers to someone else’s pings. If this works, it’ll publish a pong.

So, first of all, let’s subscribe with ROS 2 to the pong topic from a new shell (notice that initially we don’t expect to receive any pong, since none has been sent yet):

source /opt/ros/$ROS_DISTRO/setup.bash

# Subscribe to micro-ROS pong topic
ros2 topic echo /microROS/pong

And now, let’s publish a fake_ping with ROS 2 from yet another command line:

source /opt/ros/$ROS_DISTRO/setup.bash

# Send a fake ping
ros2 topic pub --once /microROS/ping std_msgs/msg/Header '{frame_id: "fake_ping"}'

Now, we should see this fake_ping in the ping subscriber console, along with the micro-ROS pings:

user@user:~$ ros2 topic echo /microROS/ping
  sec: 0
  nanosec: 0
frame_id: fake_ping
  sec: 305
  nanosec: 973000000
frame_id: '451230256_1085377743'
  sec: 310
  nanosec: 957000000
frame_id: '2084670932_1085377743'

Also, we expect that, because of having received the fake_ping, the micro-ROS node will answer with a pong:

user@user:~$ ros2 run micro_ros_demos_rcl ping_pong
Ping send seq 1706097268_1085377743
Ping send seq 181171802_1085377743
Ping send seq 1385567526_1085377743
Ping send seq 926583793_1085377743
Ping send seq 1831510138_1085377743
Ping received with seq fake_ping. Answering.
Ping send seq 1508705084_1085377743
Ping send seq 1702133625_1085377743
Ping send seq 176104820_1085377743

As a consequence, in the pong subscriber console, we should see the micro-ROS app answer to our fake_ping:

user@user:~$ ros2 topic echo /microROS/pong
  sec: 0
  nanosec: 0
frame_id: fake_ping

Multiple Ping Pong nodes

One of the advantages of having a Linux micro-ROS app is that you don’t need to buy a bunch of hardware in order to test some multi-node micro-ROS apps. So, with the same micro-ROS agent of the last section, let’s open four different command lines and run the following on each:

cd microros_ws

source /opt/ros/$ROS_DISTRO/setup.bash
source install/local_setup.bash

export RMW_IMPLEMENTATION=rmw_microxrcedds

ros2 run micro_ros_demos_rclc ping_pong

As soon as all micro-ROS nodes are up and connected to the micro-ROS agent you will see them interacting:

user@user:~$ ros2 run micro_ros_demos_rclc ping_pong
Ping send seq 1711620172_1742614911                         <---- This micro-ROS node sends a ping with ping ID "1711620172" and node ID "1742614911"
Pong for seq 1711620172_1742614911 (1)                      <---- The first mate pongs my ping
Pong for seq 1711620172_1742614911 (2)                      <---- The second mate pongs my ping
Pong for seq 1711620172_1742614911 (3)                      <---- The third mate pongs my ping
Ping received with seq 1845948271_546591567. Answering.     <---- A ping is received from a mate identified as "546591567", let's pong it.
Ping received with seq 232977719_1681483056. Answering.     <---- A ping is received from a mate identified as "1681483056", let's pong it.
Ping received with seq 1134264528_1107823050. Answering.    <---- A ping is received from a mate identified as "1107823050", let's pong it.
Ping send seq 324239260_1742614911
Pong for seq 324239260_1742614911 (1)
Pong for seq 324239260_1742614911 (2)
Pong for seq 324239260_1742614911 (3)
Ping received with seq 1435780593_546591567. Answering.
Ping received with seq 2034268578_1681483056. Answering.