VOXL Vision Hub
Table of contents
Overview
voxl-vision-hub is the main hub managing communication between VOXL MPA services and autopilots such as PX4 and ArduPilot. It forwards VIO to the autopilot as MAVLink odometry, fuses obstacle sensors for Vision Obstacle Avoidance (VOA), and provides onboard autonomous flight behaviors in PX4 offboard mode — from simple demos (figure 8, trajectory following) up to VFC, the VOXL Flight Controller used on FPV platforms.
voxl-vision-hub also underpins other tools such as voxl-calibrate-px4-horizon, MAVROS, and MAVSDK, so you will often find it must be running in the background for those to work.
If you want to develop applications that involve flight control without using ROS, voxl-vision-hub is the recommended starting point and will save you thousands of lines of code.
How It Works
In the voxl-vision-hub GitLab, you will find all the source code for the project. An overview of what each module does:
autopilot_monitor.c: subscribes to themavlink_onboardpipe published byvoxl-mavlink-serverand tracks autopilot state (attitude, flight mode, armed state)config_file.c: reads/writes the config file/etc/modalai/voxl-vision-hub.conffixed_pose_input.c: accepts a secondary (non-VIO) pose input on thevvhub_fixed_pose_inputpipe to correct VIO drift; this should generally be a slow-but-accurate source (seeexamples/fixed_frame_pipe_example.cin the repo)geometry.c: helper functions for transforming coordinate frames, used for VIO, VOA, and relocalizationhorizon_cal.c/horizon_cal_file.c: in-flight IMU horizon calibration (find the orientation at which the drone hovers perfectly still) and its result file. See horizon calibration —voxl-vision-hubmust be running andvoxl-calibrate-px4-horizondrives the process.imu_manager.c: subscribes to theimu_appspipe and keeps a short ring buffer of IMU samples for the other modulesmain.c: starts every module, then starts the configured offboard modemavlink_for_ros.c: opens the localhost UDP port for MAVROS and MAVSDK to reachvoxl-mavlink-server. Only active whenen_localhost_mavlink_udpis enabled in the config (disabled by default).mavlink_io.c: reads/writes MAVLink to the autopilot and GCS throughvoxl-mavlink-server’s pipesobs_pc_filter.c: obstacle point-cloud filter; ring-buffers ~2 seconds of point cloud data, temporally filters it, and outputs a clean cloud at a constant rateoffboard_figure_eight.c: demo mode — flies a figure 8 around the point where offboard mode was engagedoffboard_follow_tag.c: demo mode — follows an AprilTag (ModalAI R&D only, see warning below)offboard_trajectory.c: follows polynomial trajectories received on theplan_msgspipe (e.g. fromvoxl-mapper); expects the input path to start at the drone’s current positionoffboard_vfc.c: VFC — the VOXL Flight Controller, a full onboard attitude/altitude/position controller with RC-selectable submodes (see VFC below)offboard_backtrack.c: records the last N seconds of flown path and, on RC-link loss or a switch trigger, flies it backwards to return toward where the link was healthyoffboard_wps.c: local-frame waypoint mission mode, reading waypoints from a CSV (supports photo capture, land, and return actions)offboard_mode.c: dispatches whichever offboard mode the config file selectspose_filter.c/tag_manager.c: low-pass filter over AprilTag localizations fromvoxl-tag-detector’stag_detectionspipe, used by the relocalization featurestate_manager.c: aggregates non-VIO state sources — thestatepipe fromvoxl-state-estimator(optic-flow state used by VFC flow submodes) and, in HITL mode, the simulator’shitl_viopipetrajectory_monitor.cpp: for trajectory mode; predicts collisions from current pose, VOA data, and the trajectorytransform_ringbuf.c: ring buffer of timestamped transforms used throughoutvio_manager.c: transforms VIO output from body frame to a gravity-aligned local frame on the floor, health-checks VIO, and manages the fallback to the secondary VIO pipevoa_manager.c: subscribes to the configured obstacle-sensor pipes (voa_inputs), converts them into point clouds, and fuses them for collision preventionvoxl_vfc_config.c: loader for the separate VFC config file/etc/modalai/vfc.conf
Pipes
Pipes published by voxl-vision-hub:
| Pipe | Type | Contents |
|---|---|---|
vvhub_body_wrt_local | pose_vel_6dof_t | body pose/velocity in the local (VIO-initialized) frame, at VIO rate |
vvhub_body_wrt_fixed | pose_vel_6dof_t | body pose/velocity in the fixed frame (AprilTag relocalization) |
vvhub_aligned_vio | vio_data_t | full VIO data re-aligned so the local frame origin sits under the takeoff center of mass with gravity along +Z |
voa_pc_out | point cloud | the fused, downsampled VOA point cloud (debug/inspection) |
horizon_cal_io | text + control | live status of the in-flight horizon calibration |
vfc | vfc_data_t | VFC status/telemetry, consumed by voxl-inspect-vfc |
It also creates the vvhub_fixed_pose_input sink pipe, where an external localizer can write a pose_4dof_t stream to correct VIO drift.
Pipes subscribed to include the primary and secondary VIO pipes, imu_apps, state (from voxl-state-estimator), tag_detections, plan_msgs, object_tracker, the MAVLink pipes from voxl-mavlink-server (mavlink_onboard, mavlink_to_gcs, mavlink_from_gcs), and every enabled voa_inputs entry.
Configuration
/etc/modalai/voxl-vision-hub.conf
The main config file is created with defaults on first start (or with voxl-vision-hub -c). A legacy /etc/modalai/voxl-vision-px4.conf from old SDKs is migrated automatically. Obsolete keys (all the QGC IP/port settings, ADSB, and PX4 UART settings) are removed from the file on load — GCS connectivity is now entirely voxl-mavlink-server’s job.
Ensure every parameter is reasonable before attempting flight.
MAVROS / MAVSDK:
| Field | Default | Description |
|---|---|---|
en_localhost_mavlink_udp | false | open a localhost-only UDP MAVLink port for on-target MAVROS/MAVSDK. Must be enabled for MAVROS/MAVSDK to work. |
localhost_udp_port_number | 14551 | port for that socket (14550 is reserved for an off-board GCS) |
VIO:
| Field | Default | Description |
|---|---|---|
en_vio | true | forward VIO to the autopilot as MAVLink ODOMETRY |
vio_pipe | qvio | primary VIO input pipe |
secondary_vio_pipe | ov | fallback VIO pipe (open-vins); empty string disables the fallback |
en_reset_vio_if_initialized_inverted | true | auto-reset VIO if it initialized upside-down or off-level |
vio_warmup_s | 3.0 | seconds of good VIO required before sending odometry to PX4 |
send_odom_while_failed | true | keep sending odometry with quality −1 during VIO failure so EKF2 dead-reckons (set false for PX4 older than 1.14) |
en_hitl | false | hardware-in-the-loop mode: VIO comes from the simulator’s hitl_vio pipe instead |
Note that your platform’s SKU configuration (voxl-configure-mpa) decides which VIO service actually runs — voxl-open-vins-server on current SKUs, voxl-qvio-server on older platforms.
Offboard behavior:
| Field | Default | Description |
|---|---|---|
offboard_mode | figure_eight | one of off, figure_eight, follow_tag, trajectory, vfc, backtrack, wps (SKU presets normally override this) |
follow_tag_id | 0 | AprilTag ID for follow_tag mode |
figure_eight_move_home | true | recenter the figure 8 where offboard mode was engaged |
robot_radius | 0.3 | collision radius (m) used by the trajectory monitor |
collision_sampling_dt | 0.1 | sampling step along the trajectory for collision checking |
max_lookahead_distance | 1.0 | max look-ahead distance (m) along the trajectory |
Waypoint (wps) mode:
| Field | Default | Description |
|---|---|---|
wps_move_home | true | shift the mission to start at the current position |
wps_stride | 0.0 | interpolate intermediate points every N meters (0 = none) |
wps_timeout | 0.0 | hover pause (s) at each waypoint |
wps_damp | 1.0 | deceleration damping |
wps_vfc_mission | true | fly the mission with the VFC controller instead of raw PX4 setpoints |
wps_vfc_mission_loop | false | loop the mission |
wps_vfc_mission_cruise_speed | 1.0 | cruise speed (m/s) for VFC missions |
Object-tracking trigger (used by VFC’s yaw-follow, see AOI yaw tracking):
| Field | Default | Description |
|---|---|---|
tracking_trigger_ch | 12 | RC channel that arms/latches/clears tracking yaw-follow |
tracking_trigger_ch_thresh_temp | 1200 | PWM threshold for momentary tracking |
tracking_trigger_ch_thresh_new | 1800 | PWM threshold to latch a new target |
Fixed-frame (AprilTag relocalization):
| Field | Default | Description |
|---|---|---|
en_tag_fixed_frame | false | enable the tag-relocalized fixed frame |
fixed_frame_filter_len | 5 | filter length for the fixed-frame pose |
en_transform_mavlink_pos_setpoints_from_fixed_frame | false | interpret incoming position setpoints in the fixed frame |
VOA (collision prevention — see VOA for the full guide):
| Field | Default | Description |
|---|---|---|
en_voa | true | enable Vision Obstacle Avoidance output to the autopilot |
voa_upper_bound_m / voa_lower_bound_m | -0.15 / 0.15 | vertical slice of the world considered for obstacles |
voa_voa_memory_s | 1.0 | how long obstacle points persist (yes, the key really is voa_voa_memory_s) |
voa_max_pc_per_fusion | 100 | max point clouds fused per output |
voa_pie_max_dist_m / voa_pie_min_dist_m | 20.0 / 0.25 | range limits of the pie-slice output |
voa_pie_slices | 36 | angular resolution of the obstacle pie |
voa_pie_bin_depth_m | 0.15 | depth bin size |
voa_pie_threshold | 3 | points required to mark a bin occupied |
voa_pie_under_trim_m | 1.0 | trim distance under the vehicle |
voa_send_rate_hz | 20.0 | output rate to the autopilot |
voa_inputs is an array of up to 6 sensor sources, each with enabled, type (point_cloud, tof, or rangefinder), input_pipe, frame, max_depth, min_depth, cell_size, threshold, x_fov_deg, y_fov_deg, and conf_cutoff. If the array is empty, defaults are created for dfs_point_cloud, stereo_front_pc, stereo_rear_pc, tof, and rangefinders — disable or delete the entries that don’t exist on your vehicle.
/etc/modalai/vfc.conf
Since voxl-vision-hub 1.9.2 the VFC controller has its own config file, /etc/modalai/vfc.conf, also auto-created with defaults. It holds:
- RC mapping —
vfc_thrust_ch3,vfc_roll_ch1,vfc_pitch_ch2,vfc_yaw_ch4,vfc_submode_ch6, plus stick deadbands - Submode PWM windows —
vfc_<submode>_mode_rc_min/_maxpairs mapping positions of the submode switch to VFC submodes; a0/0window disables that submode (see Flight Modes below) - Backtrack —
backtrack_seconds60,backtrack_rc_chan10,backtrack_rc_thresh1500 - Limits —
vfc_max_thrust0.8,vfc_tilt_max0.436 rad,vfc_yaw_rate_max3.0,vfc_vxy_max3.0,vfc_vz_max1.0,vfc_thrust_hover0.25 - Control gains — separate PID gain sets for flow submodes (
vfc_kp_z,vfc_kp_xy, …) and VIO submodes (vfc_kp_z_vio,vfc_kp_xy_vio, …), plus filters and transition times - VIO health gates —
vfc_q_min15 (minimum VIO quality),vfc_points_min - Misc —
vfc_rate100 Hz,vfc_en_submode_announcement(send submode changes to the GCS as STATUSTEXT),vfc_disable_fallback,vfc_vio_pipe(defaults toov),vfc_traj_csvpath
VFC tuning values placed in
/etc/modalai/voxl-vision-hub.confare ignored. Since voxl-vision-hub 1.9.2 the VFC configuration lives in/etc/modalai/vfc.conf.
voxl-configure-vision-hub
The service’s configuration helper. voxl-configure-vision-hub wizard runs interactively; the notable non-interactive presets are:
voxl-configure-vision-hub enable # enable + start the service
voxl-configure-vision-hub disable # stop + disable
voxl-configure-vision-hub factory_enable # reset config to factory default
voxl-configure-vision-hub factory_enable_trajectory
voxl-configure-vision-hub factory_enable_backtrack
voxl-configure-vision-hub factory_enable_vfc_fpv # VFC preset for FPV platforms
voxl-configure-vision-hub factory_enable_vfc_starling # VFC preset for Starling
voxl-configure-vision-hub configure_hitl # hardware-in-the-loop setup
voxl-configure-vision-hub update_vfc_settings # pull measured hover thrust into vfc.conf
Per-SKU presets (e.g. d0013) also exist and are what voxl-configure-mpa applies at SKU configuration time. reset_config_file_to_default deletes both voxl-vision-hub.conf and vfc.conf and regenerates defaults.
Offboard Demo Modes
voxl-vision-hub includes demonstration offboard modes that run out of the box: figure_eight and trajectory (plus the R&D-only follow_tag).
follow_tagmode is for ModalAI R&D only and is not recommended — the vehicle will chase a tag with no obstacle awareness.
Other Requirements to Run
voxl-vision-hub subscribes to pipes published by other services, which must be running:
voxl-mavlink-servervoxl-imu-server- a VIO service —
voxl-open-vins-server(current SKUs) orvoxl-qvio-server(legacy platforms) voxl-camera-servervoxl-tag-detector(only forfollow_tag)
For trajectory mode, another service such as voxl-mapper must be publishing trajectories to the plan_msgs pipe.
Running
Power on your VOXL-equipped drone, ensuring that all the required services are running. In manual mode, using a radio transmitter, bring your drone to a hover in a safe and open space. When ready, switch the drone into offboard mode with your radio transmitter, and the configured autonomous behavior will begin.
The legacy offboard demo modes (
figure_eight,follow_tag,trajectory) do not support autonomous takeoff and landing. The VFCwpsmission mode does support takeoff, RTL, and land (voxl-vision-hub 1.8.23 / 1.9.1 and newer).
Offboard Flight Modes
voxl-vision-hub can fly the UAS in OFFBOARD mode using VFC (the VOXL Flight Controller) — a complete onboard attitude/altitude/position controller selected with offboard_mode: "vfc". VFC is the flight stack used on ModalAI FPV platforms such as Stinger.
Flight Modes
The following vision-enabled flight modes are supported through VFC in OFFBOARD mode:
- Manual (thrust + attitude)
- Altitude Hold
- Flow (optic-flow position hold, works with thermal flow)
- Hybrid Flow
- Position (Visual Inertial Odometry)
- Trajectory (replays the CSV at
vfc_traj_csv) - Backtrack
VFC automatically falls back to a safer submode when VIO, flow, or altitude health checks fail (disable with vfc_disable_fallback), announces submode changes to the GCS as STATUSTEXT messages, and auto-tunes hover thrust in flight. With object tracking running, VFC can also yaw-follow a tracked target, gated by the tracking_trigger_ch RC channel (see AOI yaw tracking).
Backtrack
Backtrack continuously records the last backtrack_seconds (default 60) of position and yaw. When triggered — by RC-link loss, or by the switch on backtrack_rc_chan crossing backtrack_rc_thresh — it flies the recorded path in reverse to return the vehicle toward where the link was healthy, then hands control back. It is available both as a VFC submode and as a standalone offboard_mode: "backtrack".
Waypoint Missions (wps)
offboard_mode: "wps" flies a local-frame waypoint mission from a CSV file (written by tools like voxl-mapper to /tmp/voxl-mapper-traj_waypoints.csv). Each waypoint carries x, y, altitude, and an optional action — supported actions include taking a hires snapshot and land/return. The wps_* config fields above control interpolation, pauses, and whether the VFC controller flies the mission.
PX4 Configuration
In PX4 the flight mode is mapped to channel 6 with the majority of positions as “offboard mode” which is integer value 7 in the PX4 config. When the channel 6 mode switch is away from the user it has a high PWM value, so PX4 flight modes 5 and 6 that correspond to that position are set to “altitude mode” which is a value of 1:
1 1 COM_FLTMODE1 7 6
1 1 COM_FLTMODE2 7 6
1 1 COM_FLTMODE3 7 6
1 1 COM_FLTMODE4 7 6
1 1 COM_FLTMODE5 1 6
1 1 COM_FLTMODE6 1 6
Once that channel 6 mode switch is in either the middle position or all the way towards the user, PX4 goes into offboard mode and simply takes roll/pitch/yaw/thrust commands from VFC.
VFC monitors the same channel 6 switch position to decide which offboard submode to be in. By default the middle position (roughly 1500 µs) is VFC position mode, which uses VIO. When the switch is all the way towards the user (roughly 2000 µs), VFC swaps into the flow submode. This is configurable via /etc/modalai/vfc.conf (voxl-vision-hub 1.9.2 and newer); the relevant section looks like:
"vfc_submode_ch": 6,
"vfc_alt_mode_rc_min": 0,
"vfc_alt_mode_rc_max": 0,
"vfc_flow_mode_rc_min": 1700,
"vfc_flow_mode_rc_max": 2100,
"vfc_hybrid_flow_mode_rc_min": 0,
"vfc_hybrid_flow_mode_rc_max": 0,
"vfc_position_mode_rc_min": 1300,
"vfc_position_mode_rc_max": 1700,
"vfc_traj_mode_rc_min": 0,
"vfc_traj_mode_rc_max": 0,
Debugging
voxl-inspect-vfc prints live VFC state from the vfc pipe — per-axis setpoint/current/error, thrust, hover thrust, and desired vs actual submode. Use -t for tuning data and -v for a live plot.
Run voxl-vision-hub --debug_offboard on the bench over ADB, with propellers removed and a radio connected, to validate which submodes are being triggered in VFC. Running the binary manually automatically stops the background service. Other useful flags:
voxl-vision-hub -c # regenerate/validate the config files and exit
voxl-vision-hub -o # print odometry being sent to the autopilot
voxl-vision-hub -b # print MAVLink messages being sent
voxl-vision-hub -d # print MAVLink messages being received
voxl-vision-hub -r # print VOA filter debug info
For general service debugging (logs, restarts), see Debugging Services.