micro-ROS Devices
Microcontrollers are the backbone of robotics sensor networks and actuator nodes. RosFit supports two paths for MCU connectivity: micro-ROS for full ROS 2 topic compatibility, and native MQTT for lightweight devices that publish directly to the broker.
micro-ROS vs native MQTT
Choosing between micro-ROS and native MQTT depends on whether your MCU needs to participate in the ROS 2 graph or simply push telemetry to the cloud.
| Criteria | micro-ROS | Native MQTT |
|---|---|---|
| ROS 2 topic compatibility | Full — the MCU appears as a native ROS 2 node | None — publishes raw JSON/CBOR to MQTT topics |
| Requires micro-ROS Agent | Yes — runs on a host (RPi, laptop, or Docker) | No — connects directly to the MQTT broker |
| Transport options | Serial UART, UDP over Wi-Fi, BLE | Wi-Fi (TCP/TLS), Ethernet |
| Message serialization | CDR (ROS 2 native) | JSON, CBOR, MessagePack, or custom |
| Firmware complexity | Higher — needs RTOS, micro-ROS client library | Lower — standard MQTT client + JSON |
| Best for | Sensor nodes that feed into Nav2/MoveIt, mixed ROS 2 graphs | Standalone telemetry devices, IoT sensors, simple actuators |
Rule of thumb: If the MCU data needs to be consumed by other ROS 2 nodes on the robot (e.g., for SLAM or motion planning), use micro-ROS. If the data only needs to reach the cloud dashboard, native MQTT is simpler and requires no agent.
ESP32 with micro-ROS
The ESP32 family is the most popular target for micro-ROS thanks to its low cost, built-in Wi-Fi/BLE, and active community support.
Supported boards
| Chip | CPU | Wi-Fi | BLE | micro-ROS | Native MQTT | Notes |
|---|---|---|---|---|---|---|
| ESP32-WROOM-32E | Dual-core Xtensa LX6 @ 240 MHz | 802.11 b/g/n | BLE 4.2 | Yes | Yes | Most common; recommended starting point |
| ESP32-S3 | Dual-core Xtensa LX7 @ 240 MHz | 802.11 b/g/n | BLE 5.0 | Yes | Yes | AI/ML acceleration, USB OTG |
| ESP32-C3 | Single-core RISC-V @ 160 MHz | 802.11 b/g/n | BLE 5.0 | Yes | Yes | Low-power, smaller footprint |
| ESP32-C6 | Single-core RISC-V @ 160 MHz | 802.11 b/g/n/ax (Wi-Fi 6) | BLE 5.3 | Experimental | Yes | Wi-Fi 6 and Thread/Zigbee support |
Toolchain setup
Install the micro-ROS build system for ESP-IDF:
# Install ESP-IDF (v5.1+ recommended)
mkdir -p ~/esp && cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git -b v5.1.2
cd esp-idf && ./install.sh esp32
source export.sh
# Create a micro-ROS component
cd ~/my_project
git clone https://github.com/micro-ROS/micro_ros_espidf_component.git components/micro_ros_espidf_component
Transport options
| Transport | Pros | Cons | Config |
|---|---|---|---|
| Wi-Fi UDP | Wireless, easy setup | Higher latency on congested networks | CONFIG_MICRO_ROS_TRANSPORT=udp4 |
| Serial UART | Lowest latency, most reliable | Requires physical cable to agent host | CONFIG_MICRO_ROS_TRANSPORT=serial |
| BLE | Low power, no Wi-Fi infrastructure needed | Limited throughput (~20 KB/s) | Custom transport layer required |
ESP32 native MQTT
For devices that only need to push telemetry to RosFit and receive commands, native MQTT over Wi-Fi is the simplest approach. No micro-ROS Agent is required — the ESP32 connects directly to the EMQX broker.
Arduino example
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
const char* WIFI_SSID = "your-wifi";
const char* WIFI_PASS = "your-password";
const char* MQTT_HOST = "cloud.rosfit.io";
const int MQTT_PORT = 1883;
const char* DEVICE_ID = "esp32-sensor-01";
const char* MQTT_USER = "esp32-sensor-01";
const char* MQTT_PASS = "mqtt_tok_xxxxx";
WiFiClient net;
PubSubClient mqtt(net);
void publishTelemetry() {
StaticJsonDocument<256> doc;
doc["temperature"] = analogRead(34) * 0.1;
doc["humidity"] = analogRead(35) * 0.1;
doc["soil_moisture"] = analogRead(32) * 0.1;
doc["timestamp"] = millis();
char buf[256];
serializeJson(doc, buf);
String topic = String("rosfit/") + DEVICE_ID + "/telemetry";
mqtt.publish(topic.c_str(), buf);
}
void onCommand(char* topic, byte* payload, unsigned int length) {
StaticJsonDocument<256> doc;
deserializeJson(doc, payload, length);
const char* cmd = doc["command"];
if (strcmp(cmd, "set_valve") == 0) {
int pin = doc["data"]["pin"];
bool open = doc["data"]["open"];
digitalWrite(pin, open ? HIGH : LOW);
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onCommand);
while (!mqtt.connected()) {
mqtt.connect(DEVICE_ID, MQTT_USER, MQTT_PASS);
delay(1000);
}
String cmdTopic = String("rosfit/") + DEVICE_ID + "/command";
mqtt.subscribe(cmdTopic.c_str());
}
void loop() {
mqtt.loop();
publishTelemetry();
delay(5000);
}
ESP-IDF with X.509 mTLS
For production deployments, use ESP-IDF with TLS client certificates instead of username/password authentication:
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = "mqtts://cloud.rosfit.io:8883",
.broker.verification.certificate = server_ca_pem,
.credentials = {
.authentication = {
.certificate = client_cert_pem,
.key = client_key_pem,
},
},
};
ESP-IDF also enables advanced features:
- Device Shadow — Subscribe to
rosfit/{device_id}/shadow/desiredand publish reported state torosfit/{device_id}/shadow/reported. - OTA updates — Listen on
rosfit/{device_id}/otafor firmware URLs, download and flash using the ESP-IDF OTA API. - Persistent sessions — Use MQTT clean session = false so the broker queues messages while the device sleeps.
STM32
STM32 microcontrollers are common in industrial and safety-critical robotics applications. micro-ROS supports several STM32 families via the micro_ros_stm32cubemx_utils package.
Supported boards
| Series | Example boards | RTOS | Transport | Notes |
|---|---|---|---|---|
| STM32F4 | Nucleo-F446RE, F407VG Discovery | FreeRTOS | Serial UART | Most widely tested with micro-ROS |
| STM32L4 | Nucleo-L476RG | FreeRTOS, Zephyr | Serial UART | Low-power variant for battery-operated nodes |
| STM32F7 | Nucleo-F767ZI | FreeRTOS | Serial UART, Ethernet | Dual-core, hardware crypto for TLS |
| STM32H7 | Nucleo-H743ZI, H745 Discovery | FreeRTOS, Zephyr | Serial UART, Ethernet | High-performance, up to 480 MHz |
Getting started
# Clone the micro-ROS tools
git clone https://github.com/micro-ROS/micro_ros_setup.git src/micro_ros_setup
rosdep update && rosdep install --from-paths src --ignore-src -y
colcon build
source install/setup.bash
# Create and configure the firmware workspace
ros2 run micro_ros_setup create_firmware_ws.sh freertos nucleo_f446re
ros2 run micro_ros_setup configure_firmware.sh nucleo_f446re --transport serial
ros2 run micro_ros_setup build_firmware.sh
ros2 run micro_ros_setup flash_firmware.sh
Connect the STM32 to a micro-ROS Agent host (Raspberry Pi or laptop) via USB/UART:
ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyACM0 -b 115200
Other MCUs
micro-ROS and native MQTT support extends beyond ESP32 and STM32. The following boards have community-tested RosFit integrations:
| Board | Architecture | micro-ROS | Native MQTT | Notes |
|---|---|---|---|---|
| Teensy 4.0 / 4.1 | ARM Cortex-M7 @ 600 MHz | Yes (serial) | Yes (Ethernet on 4.1) | Excellent real-time performance |
| Arduino Portenta H7 | Dual-core STM32H747 | Yes (serial, Wi-Fi) | Yes (Wi-Fi, Ethernet) | Industrial IoT form factor, MicroPython support |
| Renesas RA6M5 | ARM Cortex-M33 @ 200 MHz | Yes (serial, Ethernet) | Yes (Ethernet) | TrustZone security, official micro-ROS support |
| Raspberry Pi Pico W | RP2040 dual-core ARM M0+ | Experimental (serial) | Yes (Wi-Fi) | Ultra low-cost, good for sensor arrays |
For any board that supports a serial connection to a micro-ROS Agent, the RosFit bridge running on the agent host will forward topics to the cloud automatically. For boards with native MQTT, configure them to publish to the standard rosfit/{device_id}/telemetry topic structure.