Integration¶
With the default AVOID=cp firmware, v2 speaks stock MAVLink to a stock
PX4. There is no plugin to install and no custom autopilot build: the board
emits OBSTACLE_DISTANCE (#330) and PX4's built-in collision prevention does
the avoiding.
Wiring¶
| Board | Host |
|---|---|
J5 pin 3 (TX) |
host RX |
J5 pin 2 (RX) |
host TX |
J5 pin 4 (GND) |
host GND |
J5 pin 1 |
regulated 5 V |
Both data directions must be connected. The board needs attitude back from the flight controller for tilt compensation, and the point-cloud link is gated on hearing from a host at all.
PX4 collision prevention¶
1. Give PX4 a MAVLink instance on that port¶
The board sends #330 at 10 Hz and needs ODOMETRY back. On a VOXL2, add this to
/usr/bin/voxl-px4-start before mavlink boot_complete:
# 8TOF obstacle array on /dev/ttyHS1. Sends OBSTACLE_DISTANCE (#330) for PX4
# collision prevention, and needs attitude back for tilt compensation.
# -m minimal, not onboard: the board only parses ODOMETRY (#331) and
# ATTITUDE_QUATERNION (#31), so a full onboard stream set is wasted bandwidth.
mavlink start -d /dev/ttyHS1 -b 921600 -m minimal -r 2000
mavlink stream -d /dev/ttyHS1 -s ODOMETRY -r 30
On other autopilots, point any spare TELEM port at the board at 921 600 and
make sure ODOMETRY is streamed back.
2. Set the parameters¶
| Parameter | Value | Why |
|---|---|---|
CP_DIST |
> 0 (e.g. 1.5) |
Gates collision prevention entirely. At -1 it is off and nothing else matters. |
MPC_POS_MODE |
see below | Determines whether the active flight task even has collision prevention. |
CP_GO_NO_DATA |
0 (default) |
Whether to allow movement into bins with no data. |
MPC_POS_MODE depends on your PX4 version
Collision prevention lives in a different flight task depending on release, and setting the wrong one produces a vehicle that flies happily through obstacles with no error message:
| PX4 | Where CP lives | Working MPC_POS_MODE |
|---|---|---|
| 1.14 | FlightTaskManualPosition (and …SmoothVel) |
3 |
| 1.18 | StickAccelerationXY |
4 |
On 1.14, MPC_POS_MODE=4 selects FlightTaskManualAcceleration, whose
StickAccelerationXY has no collision prevention at all. Check the
firmware version on the vehicle before trusting any guide — including this
one.
Collision prevention is position-mode only. It does not act in altitude or manual mode, and mission avoidance is a separate feature.
3. Verify PX4 is receiving it¶
You want a recent timestamp and a populated distances array. never published
means the messages are not arriving — check baud, wiring direction, and that the
mavlink instance is actually running on that device.
On a VOXL2 note the split architecture: mavlink runs on the apps processor
while commander, flight_mode_manager and mc_pos_control run on the SLPI
DSP. The topic crosses a muorb bridge, so check the subscriber count on the
DSP side too — a topic published on apps with zero DSP subscribers will look
alive and still do nothing.
What "clear" and "unknown" mean¶
For the 10 Hz / 10 ms candidate:
401cm is the MAVLink value for no obstacle within the advertised range. The candidate does not infer it from a missing echo.65535is unknown, including weak/no-target returns, masked zones, expired samples, and unmeasured directions.- Other accepted values are measured obstacle distances. Valid close returns are retained, including those below the older firmware's 50 cm cutoff.
Unknown can cause PX4 Collision Prevention to restrict movement. Do not set
CP_GO_NO_DATA merely to bypass missing measurements. Validate the installed
firmware's behavior with real targets before using it for collision prevention.
See wire fields.
Reading the raw cloud on a host¶
If you want the 512-zone cloud rather than (or as well as) avoidance:
python3 tools/tof8-stream.py --format jsonl # one JSON object per frame
python3 tools/tof8-stream.py --format csv -o cloud.csv
Standard library only, Python 3.6+, so it runs on a stock VOXL2 image. See Communications for the wire format if you are writing your own parser.
You cannot share the port with PX4
A tty has one owner. If PX4's mavlink holds /dev/ttyHS1, a second reader
does not get a copy — they race, and both get a corrupted subset. Stop the
mavlink instance on that device first, or read the board from a separate
machine over a USB-UART adapter.
Geometry, if you are building your own consumer¶
For an 8×8 grid with per-axis FoV fov_deg (45°), in the sensor's optical frame
(x-right, y-down, z-forward):
step = (fov_deg / 8) * π/180 # angular pitch between zones
ax = (col - 3.5) * step # azimuth off optical axis
ay = (row - 3.5) * step # elevation off optical axis
dir = normalize( tan(ax), tan(ay), 1 )
point = (distance_mm / 1000) * dir # metres, sensor optical frame
Then rotate by that channel's mounting bearing from
Hardware to reach the body
frame. The board ships those bearings in its INFO message, so a host can read
them rather than hard-coding a second copy.
Validating placement before flight¶
With the vehicle disarmed, block one sensor at a time and confirm the obstacle
appears in the expected body direction — in the
configurator, or via listener
obstacle_distance by checking which bins drop.
The single most common integration error is mounting rotation. On v2 the nose is
CH7 (J8), under the tip of the "A".