VTX Air Unit Software Guide
Configure video, OSD, and link settings on the VTX air unit.
Table of contents
- VOXL SDK Support
- voxl-vtx Service
- voxl-osd Service
- Using External Flight Controller (MSP DisplayPort)
- ADB Access
- Using VTX as Standard WiFi Modem
VOXL SDK Support
SDK Versions
VOXL SDK 1.8.0 is the current release (downloads); the VTX is supported from SDK 1.6.0. Stinger ships with SDK 1.8.0.
Run the same SDK version on the VTX and the VRX Ground Unit. voxl-vtx 3.3 (SDK 1.8.0) requires voxl-osd 1.2.0 or newer on the drone, and an SDK 1.8.0 drone needs VRX SDK 1.8.0. This page describes SDK 1.8.0; on SDK 1.6 and older the profile list, adaptive link, zoom, and AR waypoint settings below do not exist.
Core Services
The VTX runs the standard VOXL SDK. The services below do the video work:
| Service | Config file | Role |
|---|---|---|
voxl-camera-server | /etc/modalai/voxl-camera-server.conf | Publishes camera pipes, including the encoded video streams |
voxl-osd | /etc/modalai/voxl-osd.conf | Renders the on-screen display over the video |
voxl-vtx | /etc/modalai/voxl-vtx.conf | Transmits video + telemetry over the digital link |
voxl-vtx Service
voxl-vtx is the digital video transmitter service. It pulls encoded video from a camera pipe, applies forward error correction, and transmits it over the RF link (or UDP over an IP network). It runs as the systemd service voxl-vtx.service (starts after voxl-camera-server, restarts automatically).
The service is not enabled by simply installing the package — use voxl-configure-vtx:
voxl-configure-vtx --enable # load the VTX kernel module and enable the service
voxl-configure-vtx --disable # restore the standard WiFi driver and disable the service
The VTX radio and standard WiFi share the same hardware. To use WiFi, disable the VTX first — see Using VTX as Standard WiFi Modem.
voxl-configure-vtx
voxl-configure-vtx manages /etc/modalai/voxl-vtx.conf and can push settings live to a running service:
| Option | Meaning |
|---|---|
-h, --help | Show the help message |
-l, --list | Show the current configuration |
-F, --frequency <MHz> | Set the center frequency |
-a, --active_profile_idx <n> | Set the active video profile |
-m, --mcs <n> | Set the MCS index of the active profile |
-s, --source <pipe> | Set the video pipe of the active profile |
-p, --power <idx> | Set TX power by index for the active profile (not saved) |
-P, --power-mw <mW> | Set TX power in mW for the active profile |
-t, --toggle | Toggle between VTX mode and SoftAP (WiFi) mode |
-e, --enable | Load the VTX kernel module and enable voxl-vtx |
-d, --disable | Restore the standard WiFi driver and disable voxl-vtx |
-f, --factory_enable | Enable and write the default configuration |
-L, --factory_enable_lte | Preset for LTE |
-I, --factory_enable_fiber | Preset for fiber |
-D, --factory_enable_doodle | Preset for Doodle Labs radios |
--factory_enable_dtc | Preset for DTC radios |
--factory_enable_silvus | Preset for Silvus radios (SDK 1.8.0+) |
--d0013 | Preset for Stinger (D0013) |
--lepton_enable | Add a Lepton thermal profile |
--tracking_stereo | Use Tracking Left in place of Tracking Front for stereo tracking setups (SDK 1.8.0+) |
--enable_ip_fallback | Enable RF / IP automatic fallback |
--enable_rc_deadman | Enable the RC dead man’s switch (rc_deadman_en) |
-A, --add_udp_receiver <ip:port> | Add a UDP receiver |
-R, --remove_udp_receiver <ip:port> | Remove a UDP receiver |
-C 1, --clear_udp_receivers 1 | Remove all UDP receivers (the option takes a value) |
--ar_waypoints enable\|disable | Turn AR waypoint rendering on or off |
-w, --wizard | Start the interactive wizard |
Useful behaviors:
- Running with a missing config file writes factory defaults first.
--wizardwalks every setting interactively, including a video-profile editor.- Live changes (frequency, MCS, power, profile) are pushed to the running service via its control pipe — no restart needed.
- The radio presets (
-L,-I,-D,--factory_enable_dtc,--factory_enable_silvus) and vehicle presets (--d0013) write a complete configuration.--lepton_enableand--tracking_stereochange the camera profiles and can be combined with a preset.
Configuration File Reference
/etc/modalai/voxl-vtx.conf (JSON). Created with defaults on first run. The VRX must match frequency, bandwidth, and the FEC settings.
Wireless
| Field | Default | Meaning |
|---|---|---|
frequency | 5805 | Center frequency in MHz (VRX must match) |
bandwidth | 20 | Channel bandwidth in MHz: 20 or 40 (VRX must match) |
card | "wlan0" | Radio interface name |
enable_pcap | true | Enable the RF transmit path |
enable_pit | true | PIT mode: reduced TX power for bench testing |
enable_stbc | 0 | Space-Time Block Coding (spatial streams); off by default in SDK 1.8.0 |
regulatory_mode | "off" | "off" or "fcc" — when set, DFS frequencies are blocked and power is limited where required |
Forward Error Correction
| Field | Default | Meaning |
|---|---|---|
enable_fec | true | Enable FEC (VRX must match) |
fec_percent | -1 | FEC overhead %: -1 = auto (min 75%), 0 = headers only, >0 = explicit |
fec_block_size | 30 | Fragments per FEC block (larger = more compute) |
Video Profiles
profiles is an array of video stream profiles, selected by active_profile_idx, an RC switch, joystick buttons, or the OSD menu. In SDK 1.8.0, voxl-configure-vtx builds the list in this order:
| Profile | Source pipe | Added when | MCS | MTU | Power (mW) |
|---|---|---|---|---|---|
| Adaptive (default, index 0) | hires_default_misp_encoded | Always | 0 | 1000 | 1000 |
| Boson | boson_misp_encoded | A Boson camera is configured | 0 | 1341 | 1000 |
| Tracking Front | tracking_front_misp_encoded | A tracking_front camera is configured | 0 | 1000 | 1000 |
| Tracking Left | tracking_left_misp_encoded | --tracking_stereo (replaces Tracking Front) | 0 | 1000 | 1000 |
| Tracking Down | tracking_down_misp_encoded | A tracking_down camera is configured | 0 | 1000 | 1000 |
| Lepton | lepton0_encoded | --lepton_enable | 0 | 1341 | 1000 |
| Long Range | hires_long_range_misp_encoded | Always | 0 | 750 | 1000 |
| Low Latency | hires_low_latency_misp_encoded | Always | 3 | 1341 | 750 |
Camera profiles are detected from /etc/modalai/voxl-camera-server.conf when a vehicle preset, a radio preset, --lepton_enable, or --tracking_stereo is used. The Adaptive profile replaces the old Default profile and has the adaptive link enabled.
With a vehicle preset such as --d0013, the RC switch reaches only the camera profiles (Adaptive, Boson, Tracking, Lepton; at most five), and Long Range and Low Latency are selected from the OSD menu. The --d0013 preset sets rc_toggle to channel 11. Without a vehicle preset the RC switch reaches every profile except Long Range, again at most five.
| Field | Default | Meaning |
|---|---|---|
active_profile_idx | 0 | Index of the active profile |
rc_toggle | -1 | RC channel that cycles profiles (-1 = off) |
rc_switch_profiles | [] | Profile indices reachable from the RC switch (written by the presets as described above) |
osd_rc_toggle | -1 | RC channel for OSD on/off (LOW = on, HIGH = off) |
osd_joystick_toggle | -1 | Joystick button for OSD on/off |
led_joystick_button_off | 3 | Joystick button that selects LEDs off when pressed alone (-1 = off) |
led_joystick_button_ir | 4 | Joystick button that selects IR LEDs when pressed alone (-1 = off). Neither pressed = overt LEDs on |
Each profile entry:
| Field | Meaning |
|---|---|
name | Profile name shown in the OSD menu |
source | MPA pipe carrying encoded video (e.g. hires_default_misp_encoded) |
mcs | Modulation/Coding Scheme 0-7 (higher = faster, less robust) |
mtu | Payload size in bytes (1341 max for H.265, 1342 for H.264) |
power | TX power in mW, 0-1000; -1 = maximum |
udp_camera_bitrate_bps | Requested camera bitrate when streaming over UDP |
invert_toggle | RC channel for white/black hot (Boson profiles only, -1 = off; the Boson profile uses 12) |
joystick_toggle | Joystick button that selects this profile (-1 = none) |
ai_detection_enable | Send AI detections to the VRX for this profile |
ai_detection_source | Detection pipe (default object_tracker_meta) |
ai_detection_qty | Max detected objects sent to the VRX |
ai_detection_threshold | Detection confidence threshold 0.0-1.0 |
enable_adaptive_link and adaptive_link_* | Per-profile adaptive link settings, see Adaptive Link |
Adaptive Link
New in SDK 1.8.0. With enable_adaptive_link set on a profile, the VTX adjusts the MCS index and the camera bitrate and frame rate from the SNR and packet loss the VRX reports, so the video holds up as range changes. Only the Adaptive profile has it enabled by default. It needs a VRX that sends link-quality responses (enable_lq_resp, which voxl-configure-vrx turns on). With two VRX units on one VTX, turn it off on the observer’s VRX from the VRX SETTINGS menu so only the pilot’s VRX drives the adaptive link.
| Field | Default | Meaning |
|---|---|---|
enable_adaptive_link | true (Adaptive profile) | Enable adaptive link for this profile |
adaptive_link_timeout_ms | 800 | Time without link stats from the VRX before dropping to the most robust level |
adaptive_link_up_hold_count | 2 | Consecutive SNR readings above snr_up needed before stepping to a better level |
adaptive_link_loss_down_pct | 10 | Smoothed VRX packet loss (%) at or above which the VTX steps down even when SNR is good (0 = off) |
adaptive_link_loss_down_hold_ms | 500 | Time the smoothed loss must stay above adaptive_link_loss_down_pct before stepping down |
adaptive_link_loss_up_max_pct | 5 | Smoothed loss must be at or below this to step up (-1 = no gate) |
adaptive_link_levels | see below | Levels ordered best to worst |
Each level sets mcs, bitrate_mbps, fps, num_p_frames (-1 = leave the encoder GOP alone), snr_down (step to the next worse level below this SNR, -1 = never), and snr_up (step to the next better level above this SNR, -1 = never). The Adaptive profile defaults:
| Level | MCS | Bitrate | FPS | snr_down | snr_up |
|---|---|---|---|---|---|
| 1 | 2 | 5 Mbps | 60 | 22 | -1 |
| 2 | 1 | 2.5 Mbps | 60 | 15 | 26 |
| 3 | 0 | 1.5 Mbps | 30 | -1 | 20 |
Set adaptive_link_log to "on" or "arm" to record the controller’s inputs and decisions to a CSV in /data/mvx/vtx/logs/.
Zoom
| Field | Default | Meaning |
|---|---|---|
zoom_ch | 12 | RC channel that controls digital zoom on the hires stream |
zoom_max | 4.0 | Maximum zoom factor |
zoom_ch_deadband | 10 | Deadband on the zoom channel |
zoom_joystick_buttons | [14, 15, 16, 17, 18, 19] | Joystick buttons for zoom presets, evenly spaced from 1.0x to zoom_max. Buttons 0-15 come from MAVLink MANUAL_CONTROL.buttons, 16-31 from buttons2. [] turns them off; works alongside zoom_ch |
Channel 12 is shared with white/black hot on the Boson profile; SDK 1.8.0 resolves the conflict so the wheel zooms on hires streams and switches white/black hot on the Boson stream. With an external flight controller, zoom and white/black hot are also controlled over MSP (SDK 1.8.0+).
Telemetry & Link Behavior
| Field | Default | Meaning |
|---|---|---|
info_rate_hz | 5 | Rate VTX info packets are sent to the VRX |
mavlink_telem_rate_hz | 30 | Rate MAVLink telemetry is forwarded to the VRX |
lq_quiet_timeout_ms | 5 | After a link-stats request, hold non-video transmissions until the VRX answers or this time passes (0 = off). MAVLink is held only while armed |
team_race_en | "off" | Team race behavior: "off", "on", or "auto" (detect from the ELRS receiver settings) |
team_race_tx_timeout_ms | 0 | How long to keep transmitting after an ELRS failsafe in team race mode |
rc_deadman_en | false | Stop all TX when the flight controller stops reporting a healthy RC link (MAVLink SYS_STATUS RC receiver health, or the external FC RC failsafe). TX resumes when RC recovers |
rc_deadman_tx_timeout_ms | 60000 | How long to keep transmitting after RC loss before stopping |
UDP Mode (IP networks)
For streaming over LTE, Doodle Labs, DTC, or wired IP networks instead of (or alongside) the RF link. See the VRX Developer Guide for the full walkthrough.
| Field | Default | Meaning |
|---|---|---|
udp | false | Use UDP instead of RF packet injection |
udp_interface_ip | "" | Local IP of the interface to transmit from |
udp_interface_rx_port | 50001 | Local port to listen on |
udp_interface_tx_port | -1 | Local transmit port (-1 = OS assigns) |
udp_receiver_configs | [] | Remote receivers, each {"ip": ..., "port": ...} |
RF / IP Automatic Fallback
With both RF and UDP configured, the VTX can move video to IP automatically when the RF link degrades, and back when it recovers. Enable with voxl-configure-vtx --enable_ip_fallback.
| Field | Default | Meaning |
|---|---|---|
enable_ip_fallback | false | Enable automatic RF/IP switching |
snr_low_threshold | 15 | Switch RF→IP when RF SNR (dB) sustains below this |
snr_high_threshold | 20 | Switch IP→RF when RF SNR sustains above this (hysteresis) |
link_switch_dwell_ms | 1000 | How long the condition must hold before switching |
ip_liveness_timeout_ms | 2000 | IP counts as available only if a packet arrived this recently |
pcap_liveness_timeout_ms | 2000 | If RF goes silent this long and IP is up, switch immediately |
The VRX shows the current RF/IP source on its OSD.
System
| Field | Default | Meaning |
|---|---|---|
i2c_port | 0 | I2C bus for the power/temperature sensor (-1 disables) |
perf_mode | false | Performance CPU governor while armed (lower latency) |
disable_transmissions | false | Disable all wireless transmission (test/debug) |
debug_log | "off" | Disk logging: "off", "on", or "arm" (log when armed) |
adaptive_link_log | "off" | Adaptive link CSV logging: "off", "on", or "arm" |
AR Waypoints
SDK 1.8.0 adds AR waypoint rendering on the VRX, controlled by ar_waypoints_enabled (default false), ar_home_waypoint_enabled (home position, default true), and ar_location_waypoints_enabled (uploaded mission waypoints, default false), or with voxl-configure-vtx --ar_waypoints enable|disable. AR waypoints are not supported on Stinger (D0013) or the VTX Air Unit; the OSD menu shows UNSUPPORTED VEHICLE SKU there.
Supported Frequencies
voxl-configure-vtx --frequency accepts the following center frequencies (MHz). Default is 5805 (channel 161); bandwidth may be 20 or 40 MHz.
| Band | Frequencies |
|---|---|
| 2.4 GHz | 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 |
| 5 GHz | 5160, 5180, 5200, 5220, 5240, 5260, 5280, 5300, 5320, 5340, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5720, 5745, 5765, 5785, 5805, 5825, 5845, 5865, 5885 |
The OSD menu’s CHANNEL list ends at 5865 MHz (channel 173); 5885 MHz can only be set from the command line.
TX Power
- Per-profile
poweris set in milliwatts (0-1000);-1means maximum power. voxl-configure-vtx --power-mw <mW>changes the active profile’s power live and persists it.- PIT mode (
enable_pit) keeps TX power at a bench-safe minimum; toggle it from the OSD menu when ready to fly.
Encryption Key / Binding
VTX and VRX bind by sharing an encryption key file — there is no over-the-air pairing.
- Units ship with a default key and will link out of the box.
- Generate a new key with
voxl-vtx-keygen(on target, or any Linux host):-b <bind_phrase>makes the key deterministic from the phrase; without-ba random key is generated. Output isvtx.key. - To install a key, copy
vtx.keyonto a USB flash drive and plug it into the unit — it is detected and installed to/data/modalai/vtx.keyautomatically. Do this on both the VTX and VRX. - The VRX can also generate and provision a new key from its buttons — see the VRX Quick Start Guide.
Live Control & Inspection
A running voxl-vtx accepts commands on its control pipe:
voxl-send-command vtx_latency set_frequency 5805
voxl-send-command vtx_latency set_mcs 3
voxl-send-command vtx_latency set_mw_power 500
voxl-send-command vtx_latency set_profile_idx 1
voxl-send-command vtx_latency set_pit_mode 0
To watch link stats live (latency, throughput, temperature, TX power, FEC):
voxl-inspect-vtx -n
voxl-osd Service
voxl-osd renders the on-screen display: telemetry, flight mode, VIO state, warnings, and more, composited over the FPV video. It never touches pixels directly. It draws a character-cell text canvas and streams it as MSP DisplayPort commands, which voxl-vtx composites into the transmitted video. Alongside the canvas, voxl-osd sends structured MSP messages (190 MSP_VOXL_TELEM, 191 MSP_VOXL_STRINGS, 192 MSP_VOXL_MENU) that the VTX relays to the VRX, where the SDK 1.8.0 VRX draws its own OSD from them. This is why the VRX and drone must run the same SDK; see voxl-osd. The full pipe, config, and menu reference is on the voxl-osd page; source is at voxl-public/voxl-sdk/services/voxl-osd.
By default it consumes PX4 telemetry over MPA (mavlink_onboard), plus VIO quality, VFC state, VTX temperature/power, and CPU stats pipes.
voxl-configure-osd
voxl-configure-osd factory_enable # reset config to defaults and enable
voxl-configure-osd factory_enable_no_compass # defaults without the compass tape
voxl-configure-osd external_fc # OSD for an external (MSP) flight controller
voxl-configure-osd hdzero # output MSP DisplayPort over UART to an HDZero VTX
voxl-configure-osd enable | disable
Configuration File Reference
/etc/modalai/voxl-osd.conf (JSON), created with defaults on first run.
Positioning: every screen element has a *_col / *_row pair — a character cell on the OSD canvas, origin top-left. Set either to -1 to hide that element. Elements include RSSI, armed/disarmed status, flight mode, lat/lon, MGRS grid, velocity, altitude, distance-to-home, crosshair, compass, craft name, VTX temperature/power, and CPU warnings. Battery voltage, per-cell voltage, and current draw are fixed positions.
Key toggles and behavior fields:
| Field | Default | Meaning |
|---|---|---|
show_compass_tape | true | Scrolling compass tape at the top of the OSD |
show_compass_degrees | true | Numeric heading in degrees |
show_mgrs | true | MGRS grid reference line |
mgrs_precision | 5 | MGRS digits (0-5) |
compass_fov_deg | 120 | Compass tape field of view |
craft_name | "" | Free-text craft name shown on screen |
show_vtx_cpu_mem_usage | false | VTX CPU/memory usage lines |
input_protocol | 1 | 1 = MAVLink, 2 = MSP |
input_type | 1 | 1 = MPA pipes, 2 = UART |
input_port | "" | UART device when input_type is 2 (e.g. /dev/ttyHS1) |
output_type | 1 | 0 = none, 1 = MPA (to voxl-vtx), 2 = UART (HDZero), 3 = both |
output_port | "" | UART device when output includes UART |
resolution | 1 | OSD canvas: 0 = SD 30x16, 1 = HD 50x18, 2 = HD 30x16, 3 = HD 53x20 |
OSD Menu
With the vehicle disarmed, open the on-screen menu with the RC sticks: yaw up + throttle down + roll down + pitch down. The menu sets the VTX channel, profile, and PIT mode, the flight mode, and the ADVANCED options (local recording, MAVLink forwarding, battery cells, logging, AR waypoints, RC channel view, failsafe, ELRS), and opens the VRX SETTINGS menu (SDK 1.8.0+). The full tree is on the voxl-osd page. When flying over IP with voxl-joystick-server instead of RC, the menu responds to the joystick as well.
Using External Flight Controller (MSP DisplayPort)
The VTX can serve as the digital video system for a non-VOXL flight controller speaking MSP over UART:
voxl-configure-osd external_fc
This switches voxl-osd to poll the external FC over the OSD UART (arm state, RC, status) and render the OSD from it — no MAVLink link required. See the VTX Quick Start Guide for wiring and cable options.
Betaflight Note (Rotor Riot F7)
The UART for DVTX had a bug in the 4.5 Betaflight firmware that we tested against, so we fixed it using the 4.5 maintenance branch. Here’s a docker project that can build the FW like we did:
https://gitlab.com/voxl-public/support/betaflight-build-docker
ADB Access
The USB-C port is a standard VOXL 2 Mini USB-C port, with ADB access as needed.
Using VTX as Standard WiFi Modem
The following procedure applies to VTX-enabled sUAS (e.g. D0013 Stinger) or the stand-alone (MVX-T0001).
The VTX radio and standard WiFi are the same hardware. To switch to SoftAP or Station mode, first disable the VTX (this restores the standard WiFi driver), then configure WiFi with voxl-wifi:
voxl-configure-vtx --disable
voxl-wifi softap5 # or your desired voxl-wifi mode
When you are done using WiFi, re-enable the VTX:
voxl-configure-vtx --enable
WiFi Dongle Modes
When using an external USB WiFi dongle, two operation modes are supported:
Station Mode: The drone connects to a nearby WiFi access point (such as a router or mobile hotspot). This allows the drone to access the internet through the connected network.
SoftAP Mode: The drone creates its own WiFi access point (hotspot). Other devices (such as laptops, tablets, or ground control stations) can connect directly to the drone’s hotspot for communication.
VTX WiFi Limitation
If no external WiFi dongle is used and the VTX’s built-in radio is relied upon, there is an important limitation currently:
Station Mode is not available. The VTX cannot directly connect to an external WiFi network for internet access.
SoftAP Mode remains available. By running
voxl-wifiand selecting thesoftap5option, the VTX can still create its own hotspot. This allows ground devices to connect directly to the drone’s WiFi network for data transfer, but does not provide internet connectivity.
Practical Implications
- Use a WiFi dongle if your application requires the drone to join an existing WiFi network and gain internet access.
- Use the built-in VTX SoftAP mode (
softap5) when you only need a direct peer-to-peer WiFi link between the drone and a controller device, without internet access.