Skip to main content
Home/Guides/micro-ROS Embedded Guide 2026
⚡ Embedded ROSUpdated June 2026 · micro-ROS 3.x

micro-ROS Embedded Guide 2026

Run ROS 2 on microcontrollers — ESP32, STM32, and Raspberry Pi Pico 2W. Full guide from agent setup to working publisher/subscriber nodes on 520KB RAM.

micro-ROSESP32-S3STM32H743Raspberry Pi Pico 2WROS 2 JazzyFreeRTOSZephyr

Supported Boards — 2026 Comparison

Best for WiFi robots

ESP32-S3

Espressif · $4–$15

Flash

8MB

RAM

512KB SRAM + 8MB PSRAM

Transport

Serial / WiFi UDP

RTOS

FreeRTOS

Dual-core 240MHz Xtensa

Built-in WiFi/BT for wireless transport

Arduino + ESP-IDF frameworks supported

Best for industrial

STM32H743

ST Microelectronics · $8–$40 (Nucleo)

Flash

2MB

RAM

1MB

Transport

Serial / USB CDC / Ethernet

RTOS

FreeRTOS / ThreadX / Zephyr

480MHz Cortex-M7 with FPU + DSP

1MB RAM — largest in the class

Ethernet + USB HS built-in on some variants

Best budget/education

Raspberry Pi Pico 2 W

Raspberry Pi Ltd · $7

Flash

4MB

RAM

520KB

Transport

Serial / WiFi UDP

RTOS

FreeRTOS / bare-metal

RP2350 dual Cortex-M33 150MHz

Built-in WiFi on Pico 2W

Excellent SDK documentation

Best for prototyping

Arduino Portenta H7

Arduino · $103

Flash

16MB QSPI

RAM

8MB SDRAM

Transport

Serial / Ethernet / WiFi

RTOS

Mbed OS

STM32H747 dual core (M7 + M4)

8MB SDRAM — runs complex ROS 2 graphs

Official micro-ROS Arduino library

1. micro-ROS Agent Setup

The Agent runs on the host (PC, Jetson, Raspberry Pi) and bridges the microcontroller to ROS 2. Install it first.

Install the micro-ROS Agent

The micro-ROS Agent bridges between the microcontroller and ROS 2. Run it on any Linux machine (PC, Jetson, Raspberry Pi) connected to the MCU.

# Method 1: Docker (easiest — no build required)
docker run -it --net=host microros/micro-ros-agent:jazzy udp4 --port 8888
# For serial: docker run -it --device=/dev/ttyUSB0 microros/micro-ros-agent:jazzy serial --dev /dev/ttyUSB0

# Method 2: Build from source (ROS 2 Jazzy)
sudo apt install ros-jazzy-micro-ros-agent -y
ros2 run micro_ros_agent micro_ros_agent udp4 --port 8888

# Method 3: snap
sudo snap install micro-ros-agent
micro-ros-agent udp4 --port 8888

💡 UDP transport (port 8888) is recommended for WiFi-connected MCUs. Serial /dev/ttyUSB0 is best for wired ESP32/STM32. The agent auto-discovers entities — no config needed.

2. ESP32 — PlatformIO + Arduino

Fastest path: ESP32 + Arduino framework + micro_ros_arduino library.

ESP32 micro-ROS with PlatformIO

Create a PlatformIO project that publishes an Int32 topic from ESP32 over serial.

; platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
  https://github.com/micro-ROS/micro_ros_arduino

ESP32 publisher — publishes /counter every 1s

Minimal micro-ROS publisher that sends an incrementing counter to a ROS 2 topic.

#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/int32.h>

rcl_publisher_t publisher;
std_msgs__msg__Int32 msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;

void timer_callback(rcl_timer_t * timer, int64_t last_call_time) {
    (void) last_call_time;
    if (timer != NULL) {
        rcl_publish(&publisher, &msg, NULL);
        msg.data++;
    }
}

void setup() {
    // Transport: Serial (for wired) or WiFi UDP
    set_microros_serial_transports(Serial);
    // For WiFi: set_microros_wifi_transports("SSID", "PASS", "192.168.1.100", 8888);

    delay(2000);

    allocator = rcl_get_default_allocator();
    rclc_support_init(&support, 0, NULL, &allocator);
    rclc_node_init_default(&node, "esp32_counter", "", &support);
    rclc_publisher_init_default(&publisher, &node,
        ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
        "counter");
    rclc_timer_init_default(&timer, &support, RCL_MS_TO_NS(1000), timer_callback);
    rclc_executor_init(&executor, &support.context, 1, &allocator);
    rclc_executor_add_timer(&executor, &timer);

    msg.data = 0;
}

void loop() {
    delay(100);
    rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
}

💡 Flash this to ESP32 via PlatformIO (`pio run -t upload`). Then start the agent: `ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyUSB0 -b 115200`. After 2s you should see `/counter` in `ros2 topic list`.

3. Raspberry Pi Pico 2 W — CMake SDK

Official micro-ROS Pico SDK using CMake. Supports both RP2040 and RP2350.

Raspberry Pi Pico 2 — micro-ROS CMake setup

Use the official micro-ROS SDK for Pico. Clone the example repo and build with CMake.

# Clone micro-ROS Pico SDK
git clone -b jazzy https://github.com/micro-ROS/micro_ros_raspberrypi_pico_sdk
cd micro_ros_raspberrypi_pico_sdk

# Set up Pico SDK environment
export PICO_SDK_PATH=/path/to/pico-sdk

# Build
mkdir build && cd build
cmake .. -DPICO_BOARD=pico_w   # or pico2_w for RP2350
make -j$(nproc)

# Flash the generated .uf2 file to the Pico
# (hold BOOTSEL and plug in USB → drag pico_micro_ros_example.uf2 to RPI-RP2 drive)

Pico subscriber — receive commands from ROS 2

Subscribe to /cmd from ROS 2 and toggle the onboard LED based on the value.

#include <stdio.h>
#include "pico/stdlib.h"
#include <rcl/rcl.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/bool.h>
#include "pico_uart_transports.h"

// LED pin on Pico (GP25 on original Pico, GP32 on Pico W)
#define LED_PIN 25

rcl_subscription_t subscriber;
std_msgs__msg__Bool msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;

void subscription_callback(const void * msgin) {
    const std_msgs__msg__Bool * msg = (const std_msgs__msg__Bool *) msgin;
    gpio_put(LED_PIN, msg->data ? 1 : 0);
}

int main() {
    stdio_init_all();
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);

    rmw_uros_set_custom_transport(true, NULL,
        pico_serial_transport_open,
        pico_serial_transport_close,
        pico_serial_transport_write,
        pico_serial_transport_read);

    allocator = rcl_get_default_allocator();
    rclc_support_init(&support, 0, NULL, &allocator);
    rclc_node_init_default(&node, "pico_led", "", &support);

    rclc_subscription_init_default(&subscriber, &node,
        ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Bool), "cmd");

    rclc_executor_init(&executor, &support.context, 1, &allocator);
    rclc_executor_add_subscription(&executor, &subscriber, &msg,
        &subscription_callback, ON_NEW_DATA);

    while (true) {
        rclc_executor_spin_some(&executor, RCL_MS_TO_NS(10));
    }
    return 0;
}

💡 After flashing, send from ROS 2: `ros2 topic pub /cmd std_msgs/msg/Bool '{data: true}'` — the Pico LED lights up within 10ms.

4. STM32 — Zephyr RTOS

Production-grade micro-ROS on STM32 using Zephyr RTOS. Best for industrial embedded systems.

STM32 with Zephyr RTOS (recommended for production)

Zephyr provides the most robust RTOS foundation for micro-ROS on STM32. Works with STM32H743, STM32F4, and 100+ other boards.

# Install Zephyr SDK
pip install west
west init ~/zephyrproject
cd ~/zephyrproject
west update
west zephyr-export
pip install -r zephyr/scripts/requirements.txt

# Download Zephyr SDK toolchain
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.0/zephyr-sdk-0.17.0_linux-x86_64.tar.xz
tar -xf zephyr-sdk-0.17.0_linux-x86_64.tar.xz
cd zephyr-sdk-0.17.0
./setup.sh

# Build micro-ROS Zephyr example for STM32H743-NUCLEO
cd ~/zephyrproject/zephyr
west build -p auto -b nucleo_h743zi \
  samples/subsys/bindesc -- \
  -DEXTRA_CONF_FILE="overlay-microros.conf"

# Flash
west flash

💡 Zephyr's native USB CDC-ACM transport is the most reliable for STM32. No USB-to-serial adapter needed — plug directly into PC.