Renode MCU Emulation¶
Renode runs unmodified ArduPilot STM32 firmware - the
same .elf/.apj you would flash to a board - on an emulated MCU on your
development machine. Unlike SITL,
which compiles ArduPilot as a native host program, Renode executes the real
ChibiOS build, so the real driver code, DMA setup and bus handling are
exercised rather than replaced by host stubs. The board’s own bootloader and the
independent watchdog can be brought into the picture as well, each behind its own
option.
This makes it possible to reproduce and debug board-specific problems without owning the board.
Note
Renode support is a developer tool. It is not intended for flight testing or for tuning, and its peripheral models are functional rather than physically accurate.
What is emulated¶
Renode board descriptions are generated from the board’s normal
hwdef.dat (and hwdef-bl.dat where the target has one) at launch time,
using the same hwdef compiler that ./waf configure uses. AP_Periph targets
without a bootloader hwdef reuse their application hwdef. There are no
hand-maintained per-board Renode descriptions to keep in sync - only one
hand-maintained base platform per MCU family, which every board of that family
shares.
Support is therefore driven by MCU family rather than by a board allowlist, and covers STM32 F1, F3, F4, F7, G4, H7 and L4 targets. All 109 STM32 AP_Periph hwdefs pass the generation audit, which checks that their expanded configuration translates into a valid Renode platform; booting and running is verified separately on representative targets rather than on every board.
The generated model provides:
MCU, flash layout, serial order, timers, buses, DMA, chip selects and SDMMC, taken from the compiled hwdef
representative IMU, barometer, compass, GPS, airspeed, rangefinder, battery, IOMCU, RAMTRON, dataflash and SD card models
persistent internal flash, FRAM/RAMTRON, crash dump data and microSD contents across restarts
UART/MAVLink, DroneCAN multicast and, on H743/H757 boards that declare an
ETH1hwdef entry, Ethernet connectivity
Run Tools/renode/run.py --list to see the targets the generator accepts.
Installing Renode¶
ArduPilot uses a patched Renode build; the stock release is usable but substantially slower. A prebuilt package for Linux x86_64 and aarch64 can be fetched with:
Tools/renode/tests/fetch_renode.sh build/renode
The graphical launcher can also download and update it for you with its
Download Renode button, caching it under ~/.cache/ardupilot/renode/.
run.py finds the emulator from --renode, the RENODE environment
variable, a gitignored Tools/renode/renode symlink, PATH, and finally
/opt/renode/renode or /usr/local/bin/renode. The symlink is the usual way
to pin a locally built, patched Renode without any environment setup. It also downloads the SVD file matching the board’s exact
MCU from firmware.ardupilot.org and caches it alongside.
To build Renode yourself, clone the ArduPilot performance branch
(pr-arudpilot-am32-perf), run git submodule update --init --recursive,
apply ./perf_patches/apply.sh and build with ./build.sh --net using a
.NET 10 SDK.
Running firmware¶
Build the board’s firmware normally, then launch it:
./waf configure --board KakuteF4 && ./waf copter
Tools/renode/run.py KakuteF4
This drops you into the interactive Renode monitor with the firmware running.
The first hardware UART in the board’s SERIAL_ORDER is served on
tcp:localhost:5762, so a GCS connects with:
mavproxy.py --master tcp:localhost:5762
That socket serves one client only; to reconnect a GCS, restart Renode.
Useful options:
--serial Nselects a differentSERIAL_ORDERentry--udsuses a Unix domain socket instead of a TCP port;run.pyprints the exact MAVProxy endpoint to use--elf(or--firmware) overrides the firmware; APJ, raw BIN, Intel HEX and ELF are accepted--bootloaderloads a real ArduPilot bootloader and starts from its vector table--port Ngives a telnet monitor instead of the console, and--execappends monitor commands
Note
Exposing a UART does not change firmware parameters. The selected serial port
must still have the desired SERIALn_PROTOCOL configured.
An ELF can also be downloaded from the official firmware server instead of being built locally:
Tools/renode/renode_firmware.py CubeBlack --vehicle Copter --channel latest
Graphical launcher¶
Tools/renode/launch.py is a graphical chooser around run.py:
Tools/renode/launch.py
The Target tab discovers supported boards and their built ELF images, picks a matching bootloader, and exposes CPU pinning, real IOMCU, UDS, USB/DFU, CAN and Ethernet TAP options.
The Config tab expands the selected board’s hwdef.dat and lists its
SERIAL_ORDER, I2C_ORDER and CAN_ORDER ports, so simulated devices can
be attached to the logical ArduPilot port rather than to a raw peripheral. The
initial device catalog includes u-blox GPS and Benewake/LightWare rangefinders on
UARTs, an IST8310 compass and MS4525/AUAV/ASP5033 airspeed sensors on I2C, and a
DroneCAN airspeed node on CAN.
Devices can be attached, removed or switched off while the firmware is
running, which allows testing driver probing, hot-plug and runtime
initialisation without rebooting the flight controller. The attachment list and
all tab selections are saved to launch-settings.json in the directory the
launcher was started from.
The runtime panel reports the current PC, configured and executed MIPS, and the
virtual-time speedup; paced execution targets 1.00x realtime.
Flight dynamics¶
A standalone physics sidecar reuses the existing libraries/SITL model factory
and dynamics, exchanging actuator and sensor state with Renode over a localhost
lockstep protocol:
./waf configure --board sitl
./waf --targets tool/renode-physics
build/sitl/tool/renode-physics --model quad --physics-port 9002
Quadcopter, plane, rover and quadplane models are offered, with latitude, longitude, altitude, heading and rate controls in the launcher’s Physics tab. Physics can be connected and disconnected while the firmware runs, so resets and runtime sensor initialisation can be tested without resetting the vehicle state.
Debugging with GDB¶
Build with debug symbols and pass --gdb:
./waf configure --board CubeBlack -g
./waf copter
Tools/renode/run.py CubeBlack --gdb
Renode starts the machine when GDB attaches. A ChibiOS-aware adapter sits in
front of Renode’s GDB server, so once chSysInit() has run, info threads,
thread N and thread apply all bt show the real guest threads and their
saved Cortex-M contexts. --gdb-port selects the adapter port (3333 by
default), and --no-xterm prints the attach script to run in another terminal
instead of opening one.
Adding --reverse-debug enables bounded reverse execution, so GDB’s
reverse-step, reverse-stepi and reverse-continue (rs, rsi,
rc) can be used to run backwards from a fault. --reverse-gdb-limit bounds
the retained history by guest instruction count and defaults to 1000; zero
selects Renode’s own unlimited history. The bounded mode requires the patched
ArduPilot Renode branch - on a stock build, use zero. Reverse execution is single core, and rs may
require several restore/replay cycles - use rsi to step back exactly one
machine instruction.
See also Debugging with GDB.
Logic analyser output¶
--sigrok exposes a continuous logic-analyser stream that
PulseView can read:
Tools/renode/run.py Pixhawk6X --sigrok
pulseview -d renode-la:conn=tcp/127.0.0.1/4242
The capture contains the main MAVLink UART’s TX and RX, the first SPI bus
(SCK, MOSI, MISO and every chip select) and every pin with a GPIO(n)
assignment in the compiled hwdef, named with their physical pin, hwdef signal and
logical GPIO names. --sigrok-channels limits the advertised channels using
shell wildcards, --sigrok-sample-rate changes the 10 MHz default, and
--sigrok-port changes the port.
Every hwdef GPIO(n) is also wired to an on-demand stimulus, which can generate
RPM pulse trains or quadrature wheel-encoder signals from the Renode monitor:
sysbus.gpioStimulus StartPulse 1 25
sysbus.gpioStimulus StartQuadrature 1 2 10 false
sysbus.gpioStimulus StopAll
CAN and DroneCAN¶
--can connects the generated CAN1 and CAN2 peripherals to separate ArduPilot
multicast buses, available to DroneCAN tooling as mcast:0 and mcast:1:
Tools/renode/run.py CubeOrange --can
Configure the CAN drivers as usual and reboot:
param set CAN_P1_DRIVER 1
param set CAN_D1_PROTOCOL 1
param set CAN_P2_DRIVER 2
param set CAN_D2_PROTOCOL 1
reboot
AP_Periph targets open their CAN buses by default, since CAN is their primary
transport. --can-base N moves CAN1 to mcast:N, which is useful when
running tests in parallel.
USB and firmware upload¶
On Linux, --usb exports the firmware-driven F4 or H7 USB controller through
Renode’s USB/IP server, so the emulated board appears as a real
/dev/ttyACM* device with entries under /dev/serial/by-id/. Run the helper
in a second terminal:
Tools/renode/run.py CubeOrange --usb \
--bootloader Tools/bootloaders/CubeOrange_bl.bin --hold-bootloader
Tools/renode/usbip_attach.py
Perform the one-time udev setup first so the helper can run as a normal user:
sudo Tools/renode/usbip_attach.py --install-rules
Firmware can then be uploaded through the same host path used for real hardware:
Tools/scripts/uploader.py \
--port /dev/serial/by-id/usb-Hex_ProfiCNC_CubeOrange-BL_*-if00 \
build/CubeOrange/bin/arducopter.apj
Leave execution paced while uploading. Under --unthrottled, guest time can
run past the bootloader’s receive timeout while the host is between USB writes.
Passing --usb --dfu exposes an STM32 factory-ROM-compatible DfuSe device
instead, which writes the board’s persistent flash image before Renode starts.
--dfu requires --usb and cannot be combined with --bootloader or
--gdb.
Warning
Renode’s USB/IP server listens on all host interfaces. Keep its TCP port firewalled from untrusted networks.
Ethernet¶
Pixhawk6X is the reference Ethernet target. Enable networking on the firmware and reboot:
param set NET_ENABLE 1
reboot
--ethernet-tap attaches the emulated MAC to a named host TAP interface,
which can be bridged to the physical LAN:
sudo ip tuntap add dev tap-renode mode tap user "$USER"
sudo ip link set tap-renode master br0
sudo ip link set tap-renode up
Tools/renode/run.py Pixhawk6X --ethernet-tap tap-renode
Warning
Bridging exposes the emulated autopilot directly to the local network. Use the same firewall precautions as for physical flight controller hardware.
Real IOMCU¶
H7 boards with an IOMCU_UART can run the real STM32F100 IOMCU bootloader and
firmware in a second emulated machine, connected to the FMU through a paced UART
hub:
Tools/renode/run.py CubeOrangePlus --real-iomcu \
--bootloader Tools/bootloaders/CubeOrangePlus_bl.bin
The IOMCU application comes from the FMU ELF’s embedded io_firmware.bin, and
its full 64 KiB flash persists between runs. Safety switch operation can then be
exercised over the normal FMU-to-IOMCU register path with MAVProxy’s
arm safetyoff and arm safetyon, and the FMU’s IOMC log message records
the real IOMCU status. The faster synthetic IOMCU remains the default.
Automated tests¶
test_all.py discovers firmware already built under build/*/bin and runs a
boot and parameter-download check against each:
Tools/renode/test_all.py --parallel 4
Tools/renode/test_all.py 'HolybroG4*' --parallel 2
Tools/renode/test_all.py 'CubeBlack/arducopter'
Flight controller tests wait for a heartbeat and require a complete param ftp
download; AP_Periph tests allocate a DroneCAN node ID and walk the parameter
table. Each worker gets private flash, SD card, Renode configuration and TCP
ports, and AP_Periph workers additionally get their own multicast CAN buses.
A GitHub Actions job (.github/workflows/test_renode.yml) runs the
Tools/renode/tests unit tests and then flies a CubeOrangePlus quadplane
mission against the physics sidecar. The CubeOrange mission test that downloads
a DataFlash log over MAVLink is run locally rather than in CI.
Limitations¶
STM32 targets only; there is no emulation of Linux, ESP32 or QURT boards
peripheral models are functional, not high-fidelity electrical or physical simulations
USB/IP, the DFU device and TAP networking are Linux only
a TCP-exposed UART serves a single client; reconnecting means restarting Renode
execution is paced to wall-clock time by default, and a demanding board or workload may not keep up.
--unthrottledremoves the pacing for benchmarks and batch testing, but must not be used for firmware upload over USB
Further information¶
Tools/renode/README.md in the ArduPilot source tree is the authoritative
reference, and includes the full option list, the peripheral model inventory,
performance analysis and the list of Renode bugs found during bring-up.