I’m building a small ROS 2 robot with an STM32 microcontroller and an SBC running a Zenoh router (rmw_zenoh). I want to keep the MCU side Zenoh-native with Zephyr RTOS, and I’m trying to figure out the best communication stack between the STM32 and the rest of the graph.
I’ve been looking at three options:
micro-ROS (classic) — well documented, but I’m not sure whether I’d still need zenoh-bridge-dds on the SBC side given I’m already running rmw_zenoh there
Zenoh-Pico with rmw_zenoh_pico (eSOL) — conceptually a perfect fit, but the repo seems to only target Linux/RPi so far, and I’m not sure how much work porting to STM32 + Zephyr would be
Pico-ROS — appeals to me architecturally (native Zenoh, no micro-ROS overhead), but documentation is very sparse and I couldn’t find real-world STM32 examples
I’m not necessarily looking for a solution that works out of the box — I’m happy to do integration work. What I’m really after is whether anyone has actually tried any of these on STM32 + Zephyr, what pain points they hit, and whether there’s a better path I’m missing.
Any experience or pointers would be greatly appreciated!
What physical interface ( UART /Serial, Ethernet, or CAN ) are you planning to use between the STM32 and the SBC, and also which STM32 series chip are you targeting, and what SBC are you using ?
When we had the same issue, I decided on neither because I don’t want us to be locked in for a specific middleware just because of the microcontroller.
Also, the existing solutions seemed quite complicated for something as simple as data exchange.
Instead, I developed this little helper to exchange arbitrary data structs using C++ reflection
We use this to pass information between the microcontroller and a separate ROS 2 node on the PC, communicating over USB serial.
The node handles ROS 2 communication and bridges the data exchange between ROS and the microcontroller.
Hi I am just in the process to switch the communication between SPC (Raspberry Pi 4) and my STM32 (Core2 from Husarion) from Micro-ROS to serial communication with Crosstalk (thanks @StefanFabian ). Currently the ros2_control interface works with a small MCU simulator. The next step will be to implement crosstalk in my firmware.
Some pitfalls I had were installing libserial (in the end build from source works) and the integration of libserial in the CMakefile.txt. The simulation works with socat.
What issues did you have with libserial?
We use it with rosdep key without installing from source.
For example, in our open-source ESP32-based remote E-Stop:
I first installed libserial with apt get install and then while colcon build I got an error message about CMake_config (don’t remember the correct text). This message disappeared after buildind libserial from source…
The bigger problem was the configuration of libserial in CMakeLists.txt because I could not find an example of libserial usage in ros2 packages. Because of this a link to your esp32_estop_ros package in the crosstalk library would be very helpful.
My current problem is that my firmware uses mbed 6 which seems to be not compatible with refl-cpp because of
include/crosstalk.hpp:4593:27: error: reference to 'debug' is ambiguous
errors. Maybe I switch to the Arduino framework (mbed has EOL in July 2026).
For a robot I’m currently working on, I went back and forth about this quite a bit before deciding to give the micro-ROS + micro-XRCE-DDS serial protocol + micro-xrce-DDS-agent stack a try. This is on a (Nucleo) STM32L432KC, and I even decided to forgo a proper RTOS for now, and am just rolling baremetal with platformio.
I ultimately landed on micro-ROS for the following reasons:
I was trying to avoid creating my own communication solution.
ROS already has an interface description language for defining interfaces and generating code for them, so I was keen on letting micro-ROS handle this for me. I was originally considering protobufs/nanoPb, but I wanted to give the existing micro-ROS solution a chance.
Further, a communication protocol is more than just message definitions. Depending on how crazy you want to get, you need rules to decide what to do when you send/receive messages, what to do when a checksum fails, do we need to use a CRC, or will a simple parity bit work? For my project, I wasn’t looking to develop an entire protocol, and this is exactly the kind of thing that the micro-XRCE-dds serial protocol was designed for (as far as I can gather).
micro-ROS is more than just communication: Outside of the communication, micro-ROS lets us easily set up timers, subscribers, publishers, callbacks, Nodes, etc. For most projects, I think you can easily get away with not needing any of that stuff, but it made development much easier for me.
Back to communication, though: micro-ROS (like ROS) is, from what I can gather, supposed to be rmw-agnostic, for the most part. I.e., it (in theory) shouldn’t matter if I want to use rmw_embedded_rtps or rmw_zenoh_pico (or maybe even SafeDDS). As long as I have some kind of networking/lwip stack available, both should work. AND, all your publisher/subscriber code can remain unchanged.
However, I don’t love my setup currently. I still have a number of grievances:
micro-ROS is a leaky-abstraction. I spent way more time than I wanted to learning more about how it is set up in order to get certain features working.
Ultimately, I want a setup using micro-ROS + rmw_zenoh_pico + zephr, on an MCU with some kind of ethernet interface, but I haven’t had time to investigate / make that happen yet.
I know no-one asked for all that context above, but I wanted to write my chain-of-thought down here, as I am still looking for a solution like you. Maybe someone with more intimate micro-ROS knowledge can comment, as well.