Skip to content Link Search Menu Expand Document
ModalAI DOCS
Store

voxl-elrs

Project badge Project badge Project badge

Table of contents

  1. voxl-elrs
    1. Overview
      1. Supported hardware
      2. Installation
    2. Ports and Transports
    3. Verify the Link
    4. Binding
    5. Firmware Updates
      1. Recovering a bricked ESP receiver
      2. Firmware — M0220 (MRC bundles)
    6. PWM Outputs
    7. SKU Presets — Automatic Configuration
    8. Wiring
      1. BetaFPV Nano RX
    9. Tips

Overview

ExpressLRS (ELRS) is a completely open, high-refresh, long-range radio control link using the CRSF protocol. voxl-elrs is ModalAI’s tool for managing ELRS radios attached to VOXL: verifying the link, binding, flashing firmware, reading and writing receiver parameters, mapping PWM outputs, and applying whole configurations automatically by SKU.

voxl-elrs was rewritten as a compiled CLI in version 1.0.0. The old Python tool and its interactive wizard (voxl-elrs -w) no longer exist, and several old flags changed meaning (-b is now --baud, not --bind; -p is now --port, not --setid). If you are following instructions that mention the wizard, --scan, or /etc/modalai/voxl-elrs.conf, they predate the rewrite — the current equivalents are all on this page.

Supported hardware

Firmware bundled with voxl-elrs (currently ELRS 3.5.3.x) covers:

DeviceRoleNotes
ModalAI M0184Receiversee M0184
ModalAI M0193Transmitter (a receiver build is also bundled) 
BetaFPV Nano 900MHzReceiver 
ModalAI M0220Transceiverdifferent update mechanism (MRC bundles) — see M0220 and Firmware — M0220 below

In theory any ELRS-compatible receiver can be talked to over CRSF, but bind/PWM/preset functionality depends on ModalAI firmware modifications. To see exactly what firmware your installed version bundles, run voxl-elrs list-firmware on target.

Installation

voxl-elrs ships with the VOXL SDK, and can be installed on VOXL or any Debian/Ubuntu machine with the ModalAI package repository configured:

sudo apt install voxl-elrs

Bash completion is included; voxl-elrs version prints the git version and which transports/APIs were compiled in — useful first diagnostic when reporting issues.

Ports and Transports

By default voxl-elrs uses --port auto: when voxl-px4 is running it talks over the MPA pipe (mpa:crsf_raw) so it can coexist with the autopilot, otherwise it opens the radio UART (qup7) directly. Override with -p:

voxl-elrs ping                      # auto port selection
voxl-elrs -p qup7 ping              # explicit VOXL 2 radio UART
voxl-elrs -p /dev/ttyUSB0 ping      # USB serial adapter on a host PC
voxl-elrs -p mpa:crsf_raw ping      # explicit MPA pipe

-b/--baud overrides the serial baud rate (default 420000). Three passthrough modes exist for radios that aren’t wired directly to VOXL, all requiring an explicit /dev/... port:

  • -B/--betaflight — receiver behind a Betaflight flight controller: sets up serial passthrough (the Betaflight configurator must be disconnected). Passthrough persists until the FC power cycles.
  • -E/--edgetx — internal TX module in an EdgeTX handset connected via USB (Serial/VCP mode).
  • -T/--tx — talk directly to a TX module’s CRSF UART (TX addressing and TX default baud).

For flashing across a bootloader that runs at a different baud than the app, add --boot-baud <baud> (e.g. -b 420000 --boot-baud 921600).

Always start with ping — it prints the device name, serial, hardware/firmware ID, and parameter count:

voxl2:/$ voxl-elrs ping

If the device doesn’t respond, check the wiring and the ELRS LED status of the receiver.

Binding

voxl-elrs bind        # put the connected receiver into bind mode
voxl-elrs unbind      # unbind a bound transmitter

Receiver and transmitter must be on the same major ELRS version to bind (3.x with current firmware). A binding phrase can instead be set through the SKU preset system or voxl-portal, which converts the phrase to a UID and writes it to the receiver.

bind and unbind aren’t special cases: any command parameter the receiver exposes over CRSF can be invoked by name the same way. Use enumerate to see everything the device offers, and get-param <idx> / set-param <idx> <val> to read and write individual parameters. get-rc, get-link-stats, and failsafe are also available for checking RC input, link quality, and failsafe behavior.

Firmware Updates

For M0184 / M0193 / BetaFPV devices, firmware ships on-target under /usr/share/modalai/voxl-elrs/firmware:

voxl-elrs list-firmware              # what's bundled, per target
voxl-elrs update                     # auto-detect device, flash if out of date
voxl-elrs update --target MODALAI_M0184_RX    # skip detection + version check

update stops voxl-px4 if it’s running (to free the UART), flashes over XMODEM (ModalAI targets) or esptool (ESP targets), and restarts the autopilot after. The --target form is also the recovery path for a receiver that no longer responds to detection.

upload-firmware <file> [xmodem|esp] flashes an arbitrary firmware file — for firmware built yourself with the ExpressLRS Configurator.

Recovering a bricked ESP receiver

Manually enter the bootloader: power off, hold the boot button, power on while holding it for a second. Then flash directly with esptool:

python3 -m esptool --port /dev/slpi-uart-7 --chip ESP8266 --baud 115200 \
    --before no_reset --after soft_reset write_flash 0x00 <firmware.bin>

Bootloader button

Firmware — M0220 (MRC bundles)

The M0220 uses a different update mechanism: MRC bundles staged over MAVLink FTP, with an A/B bootloader so a failed update is non-bricking.

voxl-elrs -p /dev/ttyUSB0 update-mrc <bundle.mrc>

Expect 6–10 minutes plus a reboot; add -E when updating through an EdgeTX handset. The M0220’s web UI is an alternative update path. Full details on the M0220 page.

PWM Outputs

For receivers with PWM output pins (M0184 and M0193: 4 pins), three commands manage the channel mapping:

voxl-elrs pwm-map 0                       # decode and plot pin 0's current mapping
voxl-elrs pwm-map-set 0 1 50 1500         # set pin 0 map point 1: 50% input -> 1500us out
voxl-elrs pwm-map-tune 0                  # interactive editor for pin 0

pwm-map-set accepts --mode off|step|interp and --yes to skip confirmation. Outputs flagged as arm-gated in the receiver firmware only drive once armed — voxl-elrs arm, disarm, and get-arm-status control that gate.

SKU Presets — Automatic Configuration

Receiver configuration (PWM maps, binding phrase, LED behavior, and other parameters) is managed as JSON presets under /usr/share/modalai/voxl-elrs/config, matched by regex against the vehicle’s SKU:

voxl-elrs list-presets                    # everything on disk
voxl-elrs list-presets-for-sku <regex>    # what applies to a given SKU
voxl-elrs get-merged-preset <sku>         # the fully merged result
voxl-elrs configure-sku                   # apply presets matching this vehicle's SKU
voxl-elrs configure                       # update firmware first, then configure-sku

voxl-elrs configure is what voxl-configure-mpa runs during SDK installation on ELRS-equipped SKUs, so a freshly configured vehicle comes up with the right receiver firmware and settings automatically. Individual presets can be inspected and applied with load-preset <name> and preset-get, and whole device configurations exported/imported with save-json / load-json.

Wiring

BetaFPV Nano RX

BetaFPV Nano RX Wiring Diagram

For ModalAI radios, see the wiring sections of the M0184 and M0220 pages.

Tips

  • Receiver and transmitter must share the same ELRS major version to bind.
  • The receiver’s LED blink pattern tells you its state — see the ELRS LED status page.
  • voxl-elrs update compares versions before flashing; if you run custom receiver firmware, avoid plain update (it will overwrite you) and use upload-firmware or update --target deliberately.
  • General ELRS background lives at the ELRS quickstart.

Table of contents