Small embedded team at a startup, weighing an idea before we commit to it. As far as I can tell, none of the MCU ROS stacks support I²C out of the box — micro-ROS does UART/UDP/CAN-FD, zenoh-pico does serial/UDP/TCP, Cyphal does CAN/serial. I²C isn’t on any of those lists. So if we want a board to be a ROS node talking over I²C, it looks like we’d have to write that transport layer ourselves. micro-ROS at least exposes a custom-transport API (the open/close/write/read hooks + set_custom_transport), so in principle an I²C transport is writable. My question is whether anyone actually has.
Context for why I²C at all: our STM32 boards sit behind a GMSL camera link, which tunnels an I²C channel through to the host side. The wire is already there, so an I²C transport would cost us no extra wiring — that’s the whole appeal.
So: Has anyone implemented a custom micro-ROS transport over I²C, or pushed zenoh-pico / Pico-ROS down onto an I²C link? How did it go — did the request/response and discovery patterns map onto a master-driven bus okay, or did that mismatch (the host has to poll, the MCU can’t initiate) become the whole problem? And if you tried and bailed — what made you bail? Rather hear where it broke now than find out the hard way later. (Not asking whether I²C is a “real” bus for this — I know it’s unusual. Asking specifically whether anyone’s made a ROS middleware transport work on top of it.)
Haven’t seen one that actually works. Closest thing is micro-ROS/micro_ros_platformio#127 from 2024, someone wrote a custom I2C transport for micro-ROS on a Pi Pico and it crashed the board. I2C only lets the master start a transaction, the MCU can’t push data or kick off discovery on its own, it can only answer whatever the host asks for. That assumption is baked into both micro-ROS and zenoh, so writing the transport doesn’t fix it, you’re on the hook for handling it yourself inside open/write/read, and #127 is what that looks like when it goes wrong.
What I did instead on my own robot (Autonomous_GOKU) was skip putting ROS on the MCU entirely, ros2_control hardware interface polls I2C/SPI as plain registers, ROS2 only runs on the host. If that route ever gets too painful to maintain, crosstalk is worth a look too, request/response struct exchange instead of raw registers, and it maps onto a polled bus a lot more naturally than a pub/sub transport does.
ros2_control has an issue tracking basically what you’re describing, #2171, and it points at topic_based_ros2_control, same idea as above. zephyr-zenoh-integration is the only project I know of actually running real ROS session logic on an MCU, no bridge process, but it’s built for network links (ESP32 to a zenoh router), not a bus like yours. not official docs: GSoC2026-almost-Zephyr-Zenoh-embedded - Google Drive
Since the wire’s already there for free, still think it’s worth trying.
So, for I2C I would suggest a lighter weight protocol than Zenoh, micro-ROS or Cyphal. Because I2C is mainly a single-primary with N secondaries transport, pubsub isn’t going to really work here. Connection management and session creation adds overhead to what is a very slow and electrically error-prone transport.
I would say start with a transport-neutral serialization scheme (tag-length-value, protobuf, modbus-style register-value pairings, etc.), and add I2C-specific framing (CRC, device identifiers, etc.)
This seems like something that proton, a protocol I developed for Clearpath Robotics, could work on. I didn’t develop any I2C-specific transport framing, but the serialization scheme is lightweight (protobuf) and has a ROS-native message-mapping layer. It also runs on embedded systems without any hardware or RTOS requirements. If you figure out some I2C-specifics to make it work, PR’s are always welcome