ESP32 (ESP-IDF component)
Single-node starter on ESP32-family chips via the ESP-IDF
component path — Espressif’s native C / C++ build system. For the
bare-metal Rust (esp-hal) path, see ESP32 (esp-hal).
Prereqs. Two independent toolchains.
ESP-IDF itself — ≥ 5.1, installed through Espressif’s own installer so
idf.pyis onPATH(source $IDF_PATH/export.sh).nros setupdoes not replace this; the IDF toolchain comes fromidf.py install/ Espressif’s tooling.The nano-ros side — the RMW host daemon (and any nano-ros host tools you use for testing) come from the
nrosCLI:source ./activate.sh # OR: direnv allow / source ./activate.fish just setup-cli # builds packages/cli/target/release/nros (Phase 218) nros setup esp32 --rmw zenoh # lands the RMW host daemon # (zenohd for zenoh, the # Micro-XRCE-DDS agent for xrce) # in ${NROS_HOME:-~/.nros}/sdk, AND clones the # transport submodules # (zenoh-pico + mbedtls for zenoh) # into the nano-ros checkout # so the IDF build can compile # them in-tree.
Project layout
ESP-IDF apps are CMake projects with idf.py as the orchestrator.
nano-ros plugs in as a component pulled by IDF’s component manager
or by a local path during development.
my_idf_app/
├── CMakeLists.txt # top-level: `project(my_app)`
├── sdkconfig # IDF Kconfig (generated)
├── main/
│ ├── CMakeLists.txt # `idf_component_register(REQUIRES nano-ros …)`
│ ├── idf_component.yml # declares nano-ros as a managed dependency
│ ├── app_main.c | app_main.cpp
│ └── nros.toml # (optional) runtime locator + domain
└── components/ # (optional) local components override
The idf_component.yml is the dependency manifest:
dependencies:
nano-ros:
# During development — local path to your nano-ros clone:
path: ../../../nano-ros/integrations/nano-ros
# Once published to the Espressif Component Registry:
# version: "*"
The shell at integrations/nano-ros/ wraps the nano-ros root CMake
into a standard IDF component, mapping IDF Kconfig knobs to
NANO_ROS_* cache vars.
Configure
After idf.py menuconfig:
Component config → nano-ros
RMW backend (zenoh) zenoh | xrce | cyclonedds
ROS 2 edition (humble) humble | iron
The nano-ros component itself exposes only those two knobs.
Wi-Fi credentials + zenoh locator are NOT in this Kconfig —
provide them via your app’s own Kconfig.projbuild (Espressif’s
standard pattern) or via environment variables, then pass them to
nros::init(locator, domain_id) at startup.
Build
cd my_idf_app
idf.py set-target esp32c3 # or esp32s3, esp32, esp32c6
idf.py build
First build cross-compiles nano-ros’s Rust staticlibs + IDF components (~5 min). Re-builds finish in seconds.
Run
# Flash + monitor:
idf.py -p /dev/ttyUSB0 flash monitor
# Expected serial output:
# I (1234) nano-ros: Wi-Fi connected
# I (1456) nano-ros: zenoh session opened
# I (1567) nano-ros: Published: 0
# Verify from stock ROS 2 on the same network:
source /opt/ros/humble/setup.bash
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
# Talker publishes best-effort; stock `ros2 topic echo` defaults to
# RELIABLE, so the QoS-mismatched echo silently delivers nothing.
# Force best-effort to receive:
ros2 topic echo /chatter std_msgs/msg/Int32 --qos-reliability best_effort
QEMU ESP32 testing path: see the just esp_idf recipes — they
boot the IDF binary in qemu-system-xtensa via Espressif’s
patched QEMU.
Readiness signal. After idf.py flash monitor, expect
I (XXXX) nano-ros: Wi-Fi connected followed by
I (XXXX) nano-ros: Published: 0 within 10 seconds — Rust + C + C++
all start the counter at 0 (Phase 208.D.9). If no Published: line:
- Wi-Fi creds — IDF Kconfig under
Component config → nano-rosmust carry SSID + password OR yournros.tomlmust. - Wrong locator — confirm host running
zenohdis on the same Wi-Fi subnet (or routable to it). NAT will block discovery. idf.py menuconfigshows theComponent config → nano-rossubmenu (the component is wired) andCONFIG_NROS_RMWis set to a backend name (zenoh/xrce/cyclonedds). There is no separateCONFIG_NROS_ENABLEDtoggle on ESP-IDF; the component’s presence inmain/idf_component.ymlis the on-switch.- See Troubleshooting — First 10 Minutes.
GitHub source
- IDF component shell:
integrations/nano-ros/ - Component manifest:
integrations/nano-ros/idf_component.yml - Kconfig surface:
integrations/nano-ros/Kconfig.projbuild
A complete reference app showing Wi-Fi + zenoh wiring on top of the
component is not in-tree yet; the bare-metal
examples/qemu-esp32-baremetal/rust/talker/
is the closest worked example.
Next
- Bare-metal
esp-halRust path: ESP32 (esp-hal). - Multi-component IDF apps: nano-ros sits next to other Espressif components (network, storage, sensors) — IDF’s component manager resolves them all.