74072 Commits
Author SHA1 Message Date
Andrew Tridgell 08803c4ab3 Tools: run bounded storage-race tests on SITL and Linux
Accept successful completion of StorageRace and kill and reap finite examples that exceed their deadline. Run the native Linux regression with disposable storage as an unprivileged user, since container root cannot necessarily create realtime threads. Use tmpfs so per-round fsync calls do not turn the regression into a disk-latency test.
2026-09-28 11:35:44 +10:00
Andrew Tridgell 1413c3e8dc AP_HAL: test concurrent storage writes on SITL and Linux
Exercise same-line updates and concurrent dirtying of another line for
one million rounds, yielding so single-CPU runners make progress. On Linux
hosts, also stall backend IO to verify buffer access and persistence of
concurrent writes, and inject a SITL write failure to check dirty-line retry.
2026-09-28 11:35:44 +10:00
Andrew Tridgell 0fc39f6d26 AP_HAL_Linux: protect storage buffers and dirty-mask updates
Concurrent writes and flushes can lose dirty bits or race on the buffer. Snapshot and dequeue dirty lines under a semaphore, then write outside that lock so disk latency does not block buffer access; serialize flushes separately to preserve write order.
2026-09-28 11:35:44 +10:00
Andrew Tridgell 131d83de4b AP_HAL_SITL: serialize storage writes and flushing
A writer could update a line before the flusher cleared its dirty bit,
leaving the new value only in RAM. Snapshot and dequeue under the buffer
semaphore, then perform backend IO under a separate flush semaphore so
parameter and mission reads remain accessible. Use a separate flash image
for compaction, and requeue failed writes without losing concurrent updates.
2026-09-28 11:35:44 +10:00
Slava MedvedievandClaude Sonnet 5 d589336d4e AP_NavEKF3: fix stale comment on InitialiseFilterBootstrap
The comment has said since it was added (41744c884d) that gyros are
recalibrated first when on the ground and stationary. No code in the
reset path does this; the filter always resets with the existing gyro
biases. Correct the comment to match the behaviour.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VpiNLTCnk5xHmTfPD7Uo8z
2026-09-28 08:22:02 +10:00
Tim Tuxworth 4c98c9221a AP_Networking: accept UDP client replies from a different source port
pre-commit / ci (push) Canceled after 0s
test Renode / cubeorangeplus-quadplane (push) Canceled after 0s
test scripts / build (astyle-cleanliness) (push) Canceled after 0s
test scripts / build (check_autotest_options) (push) Canceled after 0s
test scripts / build (logger_metadata) (push) Canceled after 0s
test scripts / build (param-file-validation) (push) Canceled after 0s
test scripts / build (param_parse) (push) Canceled after 0s
test scripts / build (python-cleanliness) (push) Canceled after 0s
test scripts / build (shellcheck) (push) Canceled after 0s
test scripts / build (validate_board_list) (push) Canceled after 0s
NET_Pn set to UDP_CLIENT connect()'d its socket to the configured
destination, which makes the kernel filter incoming packets to match
that exact source address *and port*. That's fine for the common case
of a device that replies from the same socket it was queried on, but
some devices (confirmed against a real Topotek KHP415 gimbal) reply
from a different, fixed source port instead - every reply was silently
dropped before ArduPilot's own code ever saw it, regardless of NET_Pn
config being otherwise correct.

For a unicast destination, stop calling connect() and use sendto()/an
unconnected recv() instead, checking the source IP ourselves (but not
the port) before accepting a packet. Broadcast and multicast
destinations keep the original connect()-based path unchanged, since
connect() also does necessary setup for them (joining the multicast
group via IP_ADD_MEMBERSHIP) unrelated to this fix, and neither is a
point-to-point relationship that could hit this problem in the first
place.

Verified against the real KHP415 (which replies from a fixed but
different port than it's queried on) by hand-crafting its wire
protocol and sending it from an unconnected socket. Regression-tested
against the existing TestLogDownloadMAVProxyNetwork suite (unicast/
multicast/broadcast UDP client, UDP server, TCP client/server) and the
full AP_Mount network autotest suite - no regressions.
2026-09-26 08:07:18 +10:00
Peter BarkerandClaude Opus 5 6af0fba1f2 autotest: add tests for QuadPlane MAVLink message handling
Exercise the QuadPlane-specific parts of ArduPlane/GCS_MAVLink_Plane.cpp
which no existing test reached:

 - AVAILABLE_MODES including the VTOL modes
 - ATTITUDE_TARGET from the VTOL attitude controller
 - PID_TUNING from the VTOL rate and vertical acceleration controllers
 - HIGH_LATENCY2 target heading and altitude in VTOL modes
 - NAV_TAKEOFF and DO_VTOL_TRANSITION rejection paths, and NAV_TAKEOFF
   as COMMAND_INT
 - precision landing using LANDING_TARGET

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-26 08:05:40 +10:00
Peter BarkerandClaude Opus 5 484ca5d8ad autotest: add tests for Plane MAVLink command and message handling
Coverage analysis of the Plane and QuadPlane autotest suites showed
large parts of ArduPlane/GCS_MAVLink_Plane.cpp were never executed.
These tests exercise that code:

 - AVAILABLE_MODES, including FLTMODE_GCSBLOCK and single-index requests
 - rejection paths of DO_REPOSITION, DO_CHANGE_ALTITUDE, DO_CHANGE_SPEED,
   GUIDED_CHANGE_SPEED/ALTITUDE/HEADING, MISSION_START, DO_LAND_START
   and the VTOL commands on a non-VTOL Plane
 - flying headings and course-over-ground with GUIDED_CHANGE_HEADING
 - SET_POSITION_TARGET_LOCAL_NED altitude offsets
 - SET_ATTITUDE_TARGET and SET_POSITION_TARGET_GLOBAL_INT being ignored
   outside GUIDED, and an invalid frame being reported
 - DO_RETURN_PATH_START as a command
 - SET_HAGL triggering the landing flare
 - DO_PARACHUTE enable, disable, unknown action and repeated release
 - DO_SET_MISSION_CURRENT as a command
 - DO_REPOSITION loiter radius and direction
 - DO_SET_HOME while in RTL
 - HEARTBEAT system_status through standby, active, failsafe and crash
 - EXTENDED_SYS_STATE landed_state through a fixed-wing flight
 - PID_TUNING axes selected by GCS_PID_MASK, including the landing PID

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-26 08:05:40 +10:00
FlyingRC-Official c1f6786ede bootloaders: add FlyingRCH7DPro bootloader 2026-09-26 08:03:40 +10:00
FlyingRC-Official e031a6db39 hwdef: add FlyingRCH7DPro board support 2026-09-26 08:03:40 +10:00
FlyingRC-Official ae887b3124 AP_Bootloader: add FlyingRCH7DPro board ID 2026-09-26 08:03:40 +10:00
cuav-chen2 0be5fcbb88 AP_InertialSensor: ADIS16607 IMU support sync clock input 2026-09-26 08:02:45 +10:00
Peter Barker b5021ae6e9 autotest: fixes to make MAVProxy termnination more reliable
MAVProxy can do some funky things with SIGTERM, accomodate it

also cut out a 0.1s pause during pexpect shutdown by nuking some of its attributes when we know the process is dead
2026-09-26 07:38:16 +10:00
Peter BarkerandClaude Fable 5.1 f9b1bacb39 AP_NavEKF3: don't square the wind-state variance limit when seeding
WIND_VEL_VARIANCE_MAX is already a variance: the airspeed-present
path constrains tasDataDelayed.tasVariance with it, and
ConstrainVariances() clamps P[22][22] and P[23][23] to it directly.
Three seeding paths nevertheless applied sq() to it, asking for a
160,000 m^2/s^2 (400m/s 1-sigma) covariance on the wind states:

 - the no-usable-airspeed branch of setWindMagStateLearningMode()
 - the no-valid-heading branch below it
 - the "allow EKF to relearn wind states rapidly" path, taken when
   the wind states stop being treated as truth

This changes no estimator behaviour.  All three seeds are clamped
back to WIND_VEL_VARIANCE_MAX by ConstrainVariances() before any
fusion step sees them: within one UpdateFilter() cycle
controlFilterModes() seeds, CovariancePrediction() (which contains
both the third site and the ConstrainVariances() call) runs next,
and the fusion selectors run after it.  A four-run alternating A/B
on Plane.DeadreckoningNoAirSpeed shows the two arms indistinguishable
in wind estimate, convergence time (283-287 simulated seconds in all
four runs) and dead-reckoning divergence.  The only observable
difference is in logging: a seed landing on a frame where
runUpdates is false is not clamped until the next prediction, so
XKV2 can record 160,000 for that one sample where it now records 400.

The value of the change is that it removes a units error that is
invisible only because a later clamp masks it, and that would bite
the moment the clamp moved, was relaxed, or a fourth site copied the
pattern.

The "use 2-sigma for faster initial convergence" comment on the
first site is replaced: the seed is the constant itself (20m/s
1-sigma), identical to the bound the airspeed-present branch clamps
to, and ConstrainVariances() would flatten any inflation regardless.

The first two sites arrived together in 59d31cc7d5 ("Rework
non-airspeed wind estimation"), which introduced the constant and
substituted it for a "typical wind speed" of 5.0f without dropping
that speed's sq(); the third repeated the pattern in ffde7f815c.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-26 07:09:08 +10:00
Peter Barker c9ba77a861 AP_AHRS: set origin via backend list rather than switch statement
one less thing to do when adding a backend
2026-09-26 07:07:37 +10:00
Peter Barker 9f648ccabc Tools: Vagrant: add support for resolute
Vagrant: compile wxpython in home for resolute and future releases

switch to excluding older versions to avoid needing to change this when making new releases
2026-09-25 11:59:11 +10:00
Pierre Kancir 4965c4e84a .github: shorten board name on size table comment
counter part of https://github.com/ArduPilot/ardupilot/pull/34469
2026-09-24 20:17:01 +10:00
Peter Barker 05d7002393 autotest: check listing a ROMFS file as a directory is refused
Listing @ROMFS/locations.txt, a file, must be refused with FileNotFound
rather than listing whatever follows its name in memory.
2026-09-24 18:35:09 +10:00
Peter Barker c5022fd90c AP_ROMFS: don't list a file as though it were a directory
dir_list() accepted a name matching dirname exactly, so opendir() of a
file's path succeeded, and readdir() then skipped past the end of that
file's name, taking the name from whatever followed it in memory. Over
MAVFTP, listing a path such as @ROMFS/locations.txt was enough.

Match only names with a separator after dirname.
2026-09-24 18:35:09 +10:00
Peter Barker 9a2da82264 autotest: check listing missing ROMFS directories leaves @ROMFS listable
Each listing of a missing @ROMFS directory must be refused with
FileNotFound, and after five of them @ROMFS must still list.
2026-09-24 18:35:09 +10:00
Peter Barker 5fac29cd7f AP_Filesystem: give a ROMFS directory record back when opendir fails
opendir() took one of the four directory records, and kept it when the
directory turned out not to exist. Four such attempts left every later
ROMFS opendir() failing with ENFILE until a reboot; over MAVFTP, four
listings of a missing @ROMFS path were enough. It also returned without
setting errno.

Free the record and set ENOENT.
2026-09-24 18:35:09 +10:00
Peter Barker ec00ad8e0d AP_Filesystem: test ROMFS entries with names too long for a directory entry
Reading SITL's 300 character ROMFS names must give names cut short and
terminated, and ending the directory's name at its separator must not
write into another open listing's entry. Both fail against the readdir()
these follow.
2026-09-24 18:35:09 +10:00
Peter Barker af04ad7253 AP_Filesystem: keep a ROMFS directory's terminator within d_name
readdir() ends a directory's name by writing a terminator at the
directory separator's index, which is past the end of d_name for a
directory name that long. Only shorten the name to the directory where
that falls within the name as copied.
2026-09-24 18:35:09 +10:00
Peter BarkerandDavid Buzz 55ed85764b AP_Filesystem: always terminate a ROMFS directory entry's name
readdir() copied the name with strncpy(), which leaves it unterminated
when it fills d_name, so anything reading it as a string - GCS_FTP's
listing among them - could run off the end of it.

Truncate to leave room for the terminator, as the FATFS backend does.

Co-authored-by: David Buzz <davidbuzz@gmail.com>
2026-09-24 18:35:09 +10:00
Peter Barker 6f22144676 AP_Filesystem: always terminate a LittleFS directory entry's name
readdir() copied at most sizeof(d_name) bytes including the terminator,
so a name as long as d_name was left without one. On ChibiOS d_name is
MAX_NAME_LEN (255) bytes and LittleFS allows 255 character names, so
such an entry's name ran on into d_type and, for a directory, beyond it,
for anything reading it as a string - GCS_FTP's listing among them.

Truncate to leave room for the terminator, as the FATFS backend does.
2026-09-24 18:35:09 +10:00
Peter Barker ac24bd56e3 autotest: check listing ROMFS names too long for a directory entry
Neither of SITL's 300 character ROMFS names fits in a listing packet, so
listing their directory gives nothing, but finding them must not read or
write outside the names around them. Run under --asan, this caught
AP_ROMFS::dir_list() reading past the previous name.
2026-09-24 18:35:09 +10:00
Peter Barker 36b5ce80fb waf: embed ROMFS files named like the directory beside them
SITL's ROMFS gains files which sort just before a directory of the same
name, at the top level and below it, so MAVFTPListROMFS checks such a
directory is still listed.
2026-09-24 18:35:09 +10:00
Peter Barker bbb6c224aa AP_ROMFS: list a directory which follows a file named like it
dir_list() lists a directory once, for its first file, by skipping any
file whose leading directory matches the previous file's. It compared
the directory's name without the separator after it, so "sub.txt",
which sorts just before "sub/", was taken for it and the directory was
never listed. At the top level the name was also taken to start one
character in.

Compare through the separator, from the start of the name.
2026-09-24 18:35:09 +10:00
Peter Barker 818be63b54 AP_ROMFS: don't read past a shorter name when skipping duplicate directories
dir_list() compares an entry's leading directory with the previous
entry's using memcmp() over the directory's length, which reads past the
end of the previous name when that is shorter. strncmp() stops at its
end.
2026-09-24 18:35:09 +10:00
Peter Barker 7296d28042 autotest: check FTP lists and reads @ROMFS
Nothing listed @ROMFS. Walk it as a GCS browsing it would, and check every
file named in the build's embedded header is found, at its decompressed
size, with nothing extra and no directory listed twice. Then read
vehicleinfo.json out of it, which is stored compressed and takes many
reads, and check it matches the file it was built from.
2026-09-24 18:35:09 +10:00
Peter Barker 2778384644 waf: embed ROMFS entries with names too long for a directory entry
SITL's ROMFS gains a file and a directory, each with a 300 character name,
so the tests can check listing them is safe: a directory entry's d_name
is 255 bytes on ChibiOS and 256 with glibc, so neither name fits. They go
under autotest_fixtures, where autotest's fixtures are kept apart from
anything a user embeds.
2026-09-24 18:35:09 +10:00
PhipsmonET ee0c343fa1 AP_Baro: fix MS5837-02BA temperature integer overflow
pre-commit / ci (push) Canceled after 0s
test Renode / cubeorangeplus-quadplane (push) Canceled after 0s
test scripts / build (astyle-cleanliness) (push) Canceled after 0s
test scripts / build (check_autotest_options) (push) Canceled after 0s
test scripts / build (logger_metadata) (push) Canceled after 0s
test scripts / build (param-file-validation) (push) Canceled after 0s
test scripts / build (param_parse) (push) Canceled after 0s
test scripts / build (python-cleanliness) (push) Canceled after 0s
test scripts / build (shellcheck) (push) Canceled after 0s
test scripts / build (validate_board_list) (push) Canceled after 0s
In AP_Baro_MS5837::_calculate_5837_02ba, the multiplication (dT * _cal_reg.c6) overflows a signed 32-bit integer when dT is positive (~250,000 at ~25-30 degC) and c6 is ~28,000, exceeding INT32_MAX (~7e9 vs 2.14e9). This resulted in truncated/invalid temperature readings (e.g. ~19 degC).

Cast dT to int64_t before multiplication to prevent overflow.
2026-09-24 13:57:00 +10:00
phesam 06e7f4ec6d autotest: cover MAVFTP virtual write bounds 2026-09-24 13:54:42 +10:00
phesam 917f648f88 AP_Filesystem: bound virtual upload writes 2026-09-24 13:54:42 +10:00
Peter Barker 251092473a Tools: shorten column names in global size summary table
Use Periph, tracker and iofw in the header to keep the table narrow.
2026-09-24 13:35:21 +10:00
Randy Mackay c5d75e9e77 Periph: version to 4.8.0-dev 2026-09-24 11:28:09 +10:00
Randy Mackay 8e67c21500 Tools: allowed_subsystems accepts Periph as prefix 2026-09-24 11:28:09 +10:00
Peter Barker 51772d0971 autotest: detect MAVFTP fetch completion by MAVProxy's success message
fetch_file_via_ftp() polled 'ftp status' for 'No transfer in progress'
and took that as completion, within a timeout measured in simulated
time.  Both are wrong:

 - the loop is paced by MAVProxy and pexpect, not the simulation.  At
   full speedup a single one-second expect consumes the whole
   twenty-second sim-time budget, so a status poll which lands
   mid-transfer fails the fetch about a second after it began, even
   though the file arrived:

     Wrote 7403 bytes to /tmp/tmptcsw8tm2 in 0.02s 391.1kByte/s
     Timed out looking for No transfer in progress
     Exception caught: expected complete transfer

 - 'No transfer in progress' is also true before the transfer starts,
   and after one is aborted, so it can yield an empty or truncated
   file.  PerfInfo has failed both ways:

     Expected TasksV2 as first line first not ()
     Expected EFI last not (AP_Generator::update ...)

Expect MAVProxy's 'Wrote N bytes to' message instead, which is printed
only once the whole file has been written, with a wall-clock timeout,
and retry the fetch a couple of times if it does not arrive.
2026-09-24 11:24:26 +10:00
Peter BarkerandClaude Opus 5 1a88f20be1 autotest: remove the script we installed, not the one we installed from
install_script() honours install_name when choosing the destination, but
install_applet_script_context() recorded the source name for removal, so
a script installed under a different name was never cleaned up when the
context went away.

AerobaticsScripting installs Aerobatics/FixedWing/Schedules/AirShow.txt
as trick72.txt: context pop then tried to unlink scripts/AirShow.txt,
which had never existed, and left scripts/trick72.txt behind after every
run.  The scripting engine itself never loads that leftover - it takes
only names ending in .lua - but plane_aerobatics.lua searches scripts/
for trick<n>.txt, so a later run reads the stale copy and would still
pass even if the install had broken.

install_script_module_context() and install_driver_script_context()
already resolve install_name this way; do the same here, and spell the
parameter out as they do rather than taking it through **kwargs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 08:05:35 +10:00
Andy Piper 66c8985079 autotest: test a range finder to baro switch in ground effect
Fails without the fix (EKF height 2.5 m high above 5 m), with only the
baro offset held (3.0 m drop at liftoff) and with only the reset skipped
(2.5 m high). Takeoff only; the touchdown half of the fix is not covered.
2026-09-23 18:47:38 +10:00
Andy Piper bb615f0f93 AP_NavEKF3: keep baro ground effect out of a height source switch
With EK3_RNG_USE_HGT, Copter uses a range finder that reads on the ground
for height while taking off, so the baro offset filter runs while the
motors spool up and learns the prop-wash baro error as offset. ALT_HOLD's
takeoff ends as the vehicle leaves the ground, the source goes back to baro
there, and the offset carries the error into the flight: in SITL with
SIM_BARO_GEFF_M 3 the EKF height read 2.5 m high from then until landing.

While takeoff or touchdown is expected, do not update the offset, and do
not reset the height to the baro on switching to it. Either alone is not
enough: with only the offset held, the reset drops the height by the whole
error at liftoff (3.0 m); with only the reset skipped, the offset still
carries it (2.5 m). With both, -0.17 m worst in the takeoff and 0.03 m mean
above 5 m.

Baro drift is not learned while the flags are set, which on Copter
includes the whole time it sits armed on the ground. Learning only the
upward part of the error was tried: in SITL it did no better, and baro
noise ratchets it upwards (0.07 m after a 10 s armed wait with
SIM_BARO_RND 0.2). Fixed wing sets the flags for a launch rather than for
rotor wash, so it is left as it was.
2026-09-23 18:47:38 +10:00
Noah Markert caadaf7daf .github: added SECURITY.md 2026-09-23 18:20:10 +10:00
Andy Piper 2ddafaf0ed autotest: count FlowGyroZBiasNoYawReference's aiding stops in flight only
The check is about aiding in flight. With the flow focus floor from #34292
the flow on the ground after touchdown is not fused, so relative aiding
stops before the disarm and would count against this test. Count only
between NOT_LANDED and LAND_COMPLETE.
2026-09-23 18:10:54 +10:00
Andy Piper 5f5c38c937 autotest: check optical flow aiding restarts without compass yaw
Fail every compass in flight, remove optical flow until aiding stops,
then restore it. Aiding has to restart, which needs the gyro bias check
to ignore the Z axis while no yaw is being fused.
2026-09-23 18:10:54 +10:00
Andy Piper df00d97233 autotest: check optical flow learns no Z gyro bias without yaw fusion
Covers no yaw source, a compass that stops delivering data and GPS yaw
lost. The simulated gyro has no bias, so any Z bias the EKF learns is
phantom. The yaw reference is removed at arming and the flow scale error
doubled, so the bias grows within 40 s of flight rather than 240 s: yaw
fused during the climb otherwise holds it down.

Flow has to have been fused for a zero bias to mean anything. XKF5 flow
innovations do not show that, as they are written before the innovation
gate and never cleared, so the test requires that flow fusion started
and that aiding never stopped while armed, which with flow as the only
aiding source means an update passed the gate at least every 5 s.

Debug build, max Z gyro bias in deg/s against a 0.1 limit. Merge-base:
no yaw source 0.26 to 0.27 (4 runs), compass lost 0.95 to 1.10 (4
runs), GPS yaw lost 1.09 to 1.26 (3 runs). With the fix: 0.00, 0.01 and
0.01 to 0.02 (3 runs). The test takes about 23 s.
2026-09-23 18:10:54 +10:00
Randy Mackay 4e7cf1f2b2 AP_NavEKF3: gps-for-yaw fuse time fixed
Adds an additional check that fuseEulerYaw actually fused the yaw rather than just attempting to fuse it.  The most likely reason they can be different is the yaw value's innovations are higher than the gate
2026-09-23 18:10:54 +10:00
Andy Piper 5e20d90fd2 AP_NavEKF3: record the anchored compass yaw fusion
On the ground with EK3_MAG_CAL 7 the compass yaw is fused as an anchor
before 3-axis fusion. If the 3-axis fusion then fails its innovation
check, last_mag_yaw_fuse_ms was not refreshed although a yaw update
was applied.
2026-09-23 18:10:54 +10:00
Andy Piper b7615b241d AP_NavEKF3: skip the Z gyro bias check while no yaw is being fused
checkGyroCalStatus() only drops the Z axis from the delAngBiasLearned
test when no yaw source is configured. Optical flow no longer learns
the Z gyro bias while no yaw is being fused, so with a yaw source that
is configured but not fusing, such as a failed compass, P[12][12] stays
above the threshold. delAngBiasLearned then stays false, and once a
flow dropout has stopped aiding, readyToUseOptFlow() never lets it
restart.

Use the same fusion test as the flow mask, so a configured source that
is not being fused is treated like no yaw source.

SITL, flow-only Copter, all compasses failed in flight, flow removed
until aiding stopped and then restored: before, aiding did not restart
within 30 s; after, it restarted 1.0 s after flow returned. Boot on a
default compass and GPS Copter and on Plane is unchanged: compass yaw
is first fused 0.2 s and 2.0 s after covariance init, long before the
bias variances converge.
2026-09-23 18:10:54 +10:00
Andy Piper 6b0f88ba26 AP_NavEKF3: learn Z gyro bias from optical flow only after yaw fusion
With optical flow as the horizontal aiding source and no yaw reference
being fused, heading and the Z gyro bias are only poorly observable.
Flow fusion can absorb a flow-velocity error as a phantom Z gyro bias,
which then drifts yaw and walks the dead-reckoned position.

Mask state 12 out of the flow Kalman update unless GPS, compass or
external nav yaw has been fused within the last 5 s. The test reads
fusion timestamps, never the configured source: a source that is
configured but lost in flight, or a compass that stops delivering
data, is the case the mask is for. GPS yaw already records
last_gps_yaw_fuse_ms; external nav and the compass now record theirs
where a fusion is applied (last_extnav_yaw_fusion_ms is refreshed by
rejected samples too), and a yaw fusion only counts if FinishFusion()
applied it. Anything else inhibits, which is safe because any real yaw
fusion learns the bias through its own gains.

X/Y gyro bias remain observable via gravity and are unaffected. This is
the same K-only mask FuseVelPosNED already applies to poorly observable
gyro bias axes in AID_NONE.

SITL, flow-only Loiter for 240 s with a 20 percent flow scale error and
no real gyro bias, maximum learned Z gyro bias with no yaw source 0.30
-> 0.00 deg/s, with all compasses failed 0.30 -> 0.03, with GPS yaw
lost 0.23 -> 0.01.
2026-09-23 18:10:54 +10:00
VinayakPundhir b9305b396d AP_ExternalAHRS: fix Aeron PLX3 build with EXTERNALAHRS_BARO or COMPASS disabled
publish_sens_para() declared baro_ok and mag_ok unconditionally but only
used them inside the AP_BARO_EXTERNALAHRS_ENABLED and
AP_COMPASS_EXTERNALAHRS_ENABLED blocks. With either feature disabled the
variable is unused and -Werror=unused-variable fails the build:

  ./waf configure --board sitl --disable-EXTERNALAHRS_BARO && ./waf copter
  AP_ExternalAHRS_Aeron_plx.cpp:432:16: error: unused variable 'baro_ok'

Move each declaration inside the block that uses it. No behaviour change
with the default feature set.
2026-09-23 18:09:23 +10:00