← How-Tos
electronics 55 min ago ◯ 4 min read

Micro-ROS and ESP32: Bridging Microcontrollers into a ROS2 Robotics Stack

esp32micro-rosros2roboticsxrce-ddsrclcmicro ros agentfreertossensorshowto

Running full ROS2 on an ESP32 doesn't work; the chip doesn't have the RAM or the Linux kernel ROS2's DDS middleware expects. Micro-ROS exists to close that gap: it lets an ESP32 (or any sufficiently capable microcontroller) act as a first-class ROS2 node, publishing and subscribing to topics, serving services, and showing up in ros2 topic list right alongside nodes running on a Raspberry Pi or a full Linux robot controller. This guide covers how micro-ROS actually works, getting it running on an ESP32, and the design decisions that matter once you have real motors and sensors attached.

How Micro-ROS Actually Works

Micro-ROS doesn't shrink ROS2 down to fit on a microcontroller; it uses a lightweight transport protocol called XRCE-DDS (DDS for Extremely Resource Constrained Environments) to bridge the gap. The architecture has two halves:

The transport between client and agent can be serial (UART over USB, the simplest option for a first project), UDP over Wi-Fi (useful since the ESP32 already has a radio), or even CAN. For a first build, serial-over-USB is the easiest to debug because you can watch the raw byte stream if something goes wrong.

Getting It Running: Two Paths

PathBest for Arduino IDE + micro_ros_arduino libraryFastest start; precompiled static libraries are provided for common ESP32 variants, and you write familiar Arduino-style setup()/loop() code ESP-IDF + micro-ROS componentProduction firmware, FreeRTOS task integration, and projects that already live in ESP-IDF rather than Arduino

For the Arduino path: install the micro_ros_arduino library, select the matching ESP32 board definition, and build a sketch that calls rclc_support_init(), creates a node and a publisher or subscriber, and spins the executor in loop(). On the agent side, run the micro-ROS agent in a Docker container or built from source on your Pi or PC with ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyUSB0, matching whichever transport your firmware uses.

A Minimal Publisher Example (Conceptual)

A typical first project publishes a sensor reading, say a temperature value from a DS18B20 or a distance reading from a VL53L0X, as a std_msgs/Float32 message at a fixed rate. The firmware pattern is: initialize the micro-ROS transport, create a node named something like esp32_temp_node, create a publisher on a topic like /esp32/temperature, and in the main loop call rclc_executor_spin_some() on a timer so the agent connection stays alive while you also publish new readings. Once the agent is running and the ESP32 boots, ros2 topic list on the Pi should show your topic, and ros2 topic echo /esp32/temperature should show live readings, exactly as if the sensor were attached directly to the Pi.

Where This Actually Helps a Real Robot

Practical Gotchas

ProblemWhat's usually happening ESP32 never shows up as a nodeAgent and client transport settings don't match (wrong serial port, baud rate, or UDP port); check both ends Node appears, then dropsLoop isn't calling the executor spin function often enough, usually because something else (a blocking sensor read, a long delay()) is starving it Timing jitter on published dataMixing blocking Wi-Fi or Bluetooth calls into the same loop as the micro-ROS executor; move sensor reads to a separate FreeRTOS task on ESP-IDF builds Memory errors on startupToo many publishers/subscribers/services for the default micro-ROS memory pool; tune the number of handles in your colcon.meta build configuration

Where to Go From Here

Once a single ESP32 node is reliably publishing and subscribing, the natural next steps are adding more nodes across a robot, wiring in tf2 transforms for sensor placement, and moving the agent itself onto the same Raspberry Pi running your navigation stack rather than your dev machine. Micro-ROS is also the cleanest path if you want ROS2-native sensor nodes without committing an entire Pi to each one, which matters a lot on weight- and power-constrained builds like small rovers or drones.