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.
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.
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.
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.
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.
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.
terrain_srtm_alt_ms is zero until the first writeTerrainData, and
imuSampleTime_ms counts from boot, so for the first five seconds of uptime
the age test passes against a terrain altitude that is still zero.
terrain_srtm_alt_valid then reports a terrain height the core has never
received: FuseOptFlow scales flow from it, getHeightControlLimit drops the
optical flow altitude cap, and getFilterStatus counts it towards relative
position validity.
On the ground at boot that costs little, since the value it invents is the
height above an origin the vehicle is sitting on. It matters after an
in-flight watchdog reset, where millis() restarts at zero and the vehicle
comes back armed and flying.
gndHgtValidTime_ms is guarded against exactly this one expression away, so
this is the same idiom rather than a new one. The 5 s is named while it is
being touched, because it is about to have a second user.
No autotest: the window is the first five seconds of uptime and closes
before healthy() opens, so SITL cannot enter it from a cold boot, and the
in-flight reset that reaches it is not something the harness can stage.
EK3_OptflowTerrainScaleHeight flies above the rangefinder range with
EK3_OPTIONS bit 2, so the flow scale height comes from the terrain
database, and off the Kalaupapa cliffs where the ground falls about 160 m
below the EKF origin. Where the terrain sits at the origin altitude both
sign conventions agree, so a flat field would discriminate nothing.
GPS navigates, which keeps flow out of the velocity solution and makes the
trajectory independent of the scale height, so the two builds fly the same
path. The scale height reaches the innovation only through vehicle
velocity, so the window read is the traverse rather than a hover at the end
of it: over a stationary hold the signal is absent whichever expression is
in use. Measured across the traverse, the XKF5 consistency ratio is 0 with
the height right and 255 - the logged ceiling - with it inverted.
It flies at 60 m rather than 40 m because the terrain 50 m north of home
rises to 185.8 m AMSL against a 165.25 m home. At 40 m the margin over that
ridge is 19.5 m, and any lower would put the rangefinder back in range and
bypass the branch under test.
The test does not prove the database rather than the terrain offset state
supplied the height. With the option cleared the frozen terrain state gives
a scale height about 3.7x low, which measures a ratio of 3 - inside the
gate, and indistinguishable from a pass. A negative leg on this signal
would not discriminate, so none is claimed.
terrain_srtm_alt is the terrain height above the EKF origin, positive up:
AP_AHRS::writeTerrainAMSL() converts the AMSL height AP_Terrain supplies
with alt_amsl_m - origin.alt, and the core stores it verbatim. pd is the
vehicle's position.z, positive down. Height above ground is therefore (-pd)
minus the terrain height, not the terrain height minus pd. The neighbouring
terrainState expression is right because terrainState is itself a D
coordinate, built as position.z + rngOnGnd, so the two branches of one
variable were being differenced in opposite conventions.
Where the AHRS and core origins coincide the old error is 2 x
terrain_srtm_alt, so it is smallest where the origin sits at field
elevation and grows with relief - and it moves the wrong way, reading high
over ground that is above the origin. AP_AHRS subtracts the one public
origin and hands the same figure to every core, which then differences it
against its own position.z, so where a core's own origin altitude has moved
- ekfGpsRefHgt drift, or lanes aligning against different receivers under
EK3_AFFINITY - the corrected form still carries that difference. The trace
here is complete only for the default EK3_OGN_HGT_MASK.
A terrain height that disagrees with the datum still collapses the scale
height to the on-ground range through the MAX, exactly as it does today.
The old expression could go negative too - over ground that sits further
below the origin than the vehicle sits above it - so this is pre-existing,
and the sign fix moves which geometry triggers it rather than closing it.
Falling back to terrainState there is the obvious repair and it does not
work: the enclosing condition has already declared that state stale.
Measured in SITL off the Kalaupapa cliffs, holding 60 m above an origin the
ground falls to 160 m below, so the true height above ground reaches 220 m.
GPS navigates, so flow is not fused into velocity and both builds fly the
same trajectory; only the scale height differs. Across the traverse the
logged flow innovation consistency ratio saturates its 255 ceiling - at
least 2.55, so flow at that geometry is rejected outright - against a peak
of 0 with this change. The raw innovation is deliberately not quoted: XKF5
logs it as an int16 scaled by 1000, and the old expression drives it past
the wrap point, so the logged figure there is an aliased value rather than
the real one.
Unlike the v3 IMUs, where the sensor ODR is programmed to the backend
rate, the v1 FIFO fills at the 8kHz sensor rate when fast sampling and
the backend rate is a software decimation. Reading a non-primary at 2x
loop rate left 20 samples in the FIFO between beats, and with bus
latency on top it reached the depth at which _read_fifo() already
expects corrupt samples: an MPU6000 in the second slot gave a
continuous stream of "stop at 8 of 48" and temperature resets.
Hold a fast-sampling non-primary at 1kHz, one read buffer of samples
per beat, so the FIFO stays well clear of that depth. The 2x loop rate
scaling now only applies without fast sampling, where the FIFO fills at
the backend rate as it does on v3.
Mirror the v3 driver's set_primary(): with the fast rate loop's dynamic
FIFO enabled a non-primary IMU is read at 2x loop rate, bounded to
400..1000Hz, and the primary at the full backend rate. Without the
override the v1 driver ignored primary changes and read every IMU at
the full backend rate.
RCOutput_iofirmware.cpp carried a second copy of the decode table, used by
the reversed-channel decoder on STM32F1. That copy is live: PB8 and PA1 are
declared BIDIR on iomcu-f103-dshot, so those channels kept the old
one-in-sixteen false accept rate while the main path was fixed.
Hoist the table, the quintet check and the checksum into one helper so the
two cannot drift again. Removing the duplicate saves 172 bytes on the F103,
which has 8k of flash left.
The GCR decode table used 0 for the sixteen quintets the encoding never emits,
which is indistinguishable from the legitimate 0 at index 25. A corrupt quintet
therefore decoded silently to nibble 0, leaving only the checksum between it and
a bad eRPM - and four bits of checksum let roughly one in sixteen corruptions
through.
Mark the impossible quintets and reject any word containing one. Betaflight
reports 5-8% of frames failing to decode with motors running, so this path is
exercised constantly, and a bad eRPM feeds RPM-referenced harmonic notch
tracking.
The loop was meant to wait for the 14 FIR settling samples to reach the
FIFO before flushing them, but tested the opposite sense. The FIFO is
empty on entry, so it fell through on the first poll and discarded at
most the single sample that had arrived by then.
This does not change a vehicle's ground reference: AP_Baro::calibrate()
throws away a second of readings before it averages ground pressure, so
the transient never reached it. AP_Periph never calibrates, and there
the first readings go straight out over CAN.
At the 120Hz ODR of the preceding commit the wait costs ~120ms of
bus-semaphore hold during probe. It would be ~350ms at the 40Hz this
driver used before.
Mode 2 is the low power mode - 2.5 Pa per sample at 49uA, against 1 Pa
at 222uA for mode 1. The current saving is not worth the noise on a
flight controller.
Measured on the bench on a SkySakuraH743, mode 2 gave 1.10 Pa sd at the
10Hz frontend rate, against the 1.25 Pa expected from averaging four
40Hz samples of the datasheet 2.5 Pa. Mode 1 puts twelve 120Hz samples
into each update instead.
Mode 0 is quieter per sample but only runs at 25Hz, so it ends up at the
same output noise with several times the FIR group delay.
The higher ODR does not change the read path: the FIFO is drained and
averaged in full on each 80Hz poll, into a 16 packet FIFO.
Checks the baro fallback drops the altitude gate rather than the
compensation beyond 20m from the launch point; the previous
AP_GroundEffect reported 0s there.
The baro fallback gates touchdown on height-since-takeoff assuming flat
ground. Beyond 20m from the launch point that assumption may not hold,
but disabling touchdown compensation there left mission landings and
rally-point RTLs on baro-only vehicles with none at all, a regression
from the pre-gate behaviour, while the no-position branch assumed flat
ground everywhere.
Beyond 20m fall back to any gentle descent counting as a landing, as
before the gate existed and as the comment on the constant already
described. Rangefinder, near-launch and no-position paths are
unchanged.
SITL, GNDEFF_ALT=1.0, GUIDED to 3m, land 30m from takeoff:
touchdown_expected 0.0s -> 9.6s (6.9s landing at the takeoff point,
9.8s with GNDEFF_ALT=5).
EKF3's HAGL is not zero on the ground: the EKF substitutes the
rangefinder ground clearance (RNGFNDx_GNDCLR) while the sensor is out
of range low. Gating on absolute HAGL therefore released the takeoff
window before liftoff whenever GNDCLR >= GNDEFF_ALT, and the touchdown
gate could never be met on the same vehicle.
Anchor HAGL alongside the takeoff altitude while on the ground and
gate on the climb since then, matching the relative-to-takeoff
fallback. Without a rangefinder behaviour is unchanged.
SITL, GNDEFF_ALT=0.5 GNDEFF_TMO=0, RNGFND1_TYPE=100 RNGFND1_GNDCLR=0.6:
takeoff_expected 0.0s -> 4.9s, touchdown_expected 0.0s -> 6.9s
(baro-only baseline 5.0s).
Replaces Copter's built-in ground-effect detection with the
AP_GroundEffect library and wires its AC_PosControl and per-cycle
vehicle state.
A stored GND_EFFECT_COMP=0 is migrated to GNDEFF_ALT=-1; the enabled
default needs no migration.
With the default GNDEFF_ALT of 0.5m touchdown_expected now also
requires the vehicle to be near the ground (within 0.5m of the takeoff
height, and within 20m horizontally of the launch point when no
rangefinder is available), where the old code asserted it for any slow
descent at any height. GNDEFF_ALT=0 restores the old behaviour.
Vehicle-agnostic detector that tells the EKF when to expect baro
disturbance from rotor downwash near the ground, driving AP_AHRS
set_takeoff_expected and set_touchdown_expected. Adds GNDEFF_ALT
(altitude threshold and master enable) and GNDEFF_TMO (takeoff hold
time).
The three config registers were written once and never verified. A
corrupted write on the bus left the sensor misconfigured with no way
back. Register them as checked and validate one per sample.
STATUS_REG bit 3 is Zyxda, set when X, Y and Z all have new data. The
mask also covered bits 0-2, the per-axis flags, so a sample could be
taken when only one axis had updated.
The datasheet gives 1.5 mgauss/LSB typical. The previous 100/65.535
came from assuming the +/-50 gauss range maps exactly onto the 16-bit
output, which reads 1.7% high.
Mirror the anchored XKFS.MAG_FUSION value and add a Sub leg asserting
it while disarmed and stationary, that arming releases the anchor, and
that disarming restores it. Without the anchoring change the leg fails
with mag fusion selection 2 where 3 is expected.
When EK3_MAG_CAL=7 (GroundAndInflight) learns the field states on the
ground, a stationary vehicle gives the 3-axis fusion no yaw
observability: a yaw error is absorbed by the body field states with
zero innovation and each core then free-integrates its own gyro bias.
On a vehicle whose local field disagrees with the WMM tables the yaw
walks away from the compass heading as soon as the origin is set and
the earth field states reset to the tables - each core in its own
direction, which trips the pre-arm yaw consistency check and blocks
arming. Observed on the bench at 0.35 deg/s and 150 deg of walk while
DCM held the true heading throughout, with the mag test ratio never
exceeding 0.34.
Fuse the magnetic heading alongside the 3-axis fusion while disarmed
and stationary. That pins yaw to the compass, and with the earth field
held to the tables the body field states become observable at a fixed
heading - which is the battery-signature learning the mode exists for.
The heading measurement comes from the raw compass, not the learned
field states, so the anchor is not circular.
Holding the earth field to the tables requires EK3_MAG_EF_LIM non-zero
and a table field, which is the default. With EK3_MAG_EF_LIM=0 the
earth field is initialised from the measurement instead, so the table
mismatch that drives the walk does not arise; the anchor still pins yaw
there, but three mag components cannot separate the earth and body
field states at a fixed attitude.
Gate on onGroundNotMoving rather than !inFlight. Rotation is what makes
yaw observable to the 3-axis fusion, so the anchor is only needed while
stationary, and onGroundNotMoving already gates the equivalent STATIC
yaw fusion used to stop ground yaw drift without a yaw sensor. It also
avoids !inFlight, which stays true well past takeoff on planes and
through the first 1.5 m of climb on copters.
That gate also requires the motors to be disarmed, so an armed vehicle
idling on the pad or taxiing runs 3-axis fusion with no anchor, as it
does today. That is deliberate: anchoring there would pin yaw to a
heading the running motors are disturbing. Mode 4 has the same on-ground
observability gap, but its behaviour is long-standing and is left alone.
The anchor inherits the limitation heading fusion has always had. A
body field component perpendicular to the horizontal earth field is not
separable from yaw by a heading measurement, so it lands in yaw as an
offset of asin(b_perp/H) - 5.7 deg for H = 0.2 G and b_perp = 0.02 G -
rather than being learned. Subtracting body_magfield from the heading
measurement would remove that on paper, at the cost of making the
anchor circular.
Leaving the yaw test ratio live while anchored is deliberate. It feeds
the pre-arm compass variance check, the GPS yaw check and the 5 second
ground heading reset, none of which mode 7 could reach while the ratio
was forced to zero. Modes 0, 2 and 3 already fuse the same heading and
leave the same ratio live on the ground, so this reports a yaw
disagreement mode 7 used to hide rather than adding a failure mode of
its own - a sustained 40 deg disagreement blocks arming on copter in
either mode.
While anchored the same compass sample is fused twice, once as a
heading and again as three components, with no allowance for the
correlation. At the converged ground yaw variance the heading gain is
0.005, so it moves the subsequent 3-axis innovations by around 1%; the
gain starts at 0.5 on the first sample after a yaw reset and decays
over the following few seconds. Decimating the anchor would cut the
double count but also weakens the z gyro bias observation, which is the
part that stops the walk rather than just opposing it.
Log the anchored case as its own XKFS.MAG_FUSION value so a log reader
can tell it from unanchored 3-axis fusion.
Replay reproduces the unfixed walk on the two bench logs that hit this,
54 to 207 deg over 105 s.
update() cleared _gyro_healthy/_accel_healthy for every instance and relied
on the backends to set them true again a few microseconds later. Those flags
are read from other threads - AP_RCTelemetry::check_sensor_status_flags()
runs from the CRSF frame handler on the RC input thread - so every main loop
iteration left a window in which a perfectly healthy sensor reads unhealthy.
At an ELRS telemetry rate of ~200Hz that window is sampled often enough to
report "Bad Gyro Health" continuously on a vehicle whose gyro never missed a
sample. It is invisible in a log: IMU.GH stays 1 even logged at loop rate,
because logging also runs from the main loop and so cannot observe the
window.
Drop the central clear and have update_gyro()/update_accel() set the flag
false only when there is no fresh sample, so a healthy sensor never sees it
transiently cleared. The error-count preference later in update() can still
demote a sensor in the same cycle; that path is unchanged.
A backend whose start() failed to register stays in _backends[] and still
has update() and update_filters() called every cycle, with
gyro_instance/accel_instance left at their default. Default those to
INS_MAX_INSTANCES and bounds-check the frontend helpers that index by them,
so the new clear is not applied to instance 0 and nothing indexes one past
the end. notify_*_fifo_reset() gets the same check because LSM9DS1 calls it
from probe(), before registration. ADIS16607 and NONE redeclared
gyro_instance/accel_instance, shadowing the base members; the duplicates
are removed so the default applies there too.
ADIS16607 also tested enable_fast_sampling(accel_instance) from probe(),
before the instance is known. That was only right for instance 0 while the
driver had its own zero-initialised copy, and with the new default it
disabled fast sampling altogether. Pre-fetch the instance numbers in start()
as the Invensense drivers do and move the rate decision and the DEC_RATE
write there, after registration, so a failed write leaves an instance that
reads unhealthy rather than pre-fetched numbers with nothing registered
behind them.
Define HAL_SUPPORT_RCOUT_SERIAL for SITL so AP_BLHeli compiles and the
SERVO_BLH_* parameters (RVMASK, MASK, 3DMASK, ...) are registered in the
simulator. Serial passthrough is unsupported under SITL (there is no
serial_setup_output implementation, so attempts fail with an error ack)
and DShot reversing has no rcout effect, but exposing the parameters
lets the motor-direction / ESC tooling that depends on them be
exercised in SITL instead of only on hardware.
The same define drives AP_NOTIFY_DSHOT_LED_ENABLED, so NTF_LED_TYPES
gains the DShot LED bit under SITL. It is off by default and the backend
is a no-op there. sitl_periph sets the define to 0 in its own hwdef and
that still wins, as hwdef.h is included first.
The MSP_UID handler read the MCU serial number by dereferencing
UDID_START, which only exists on ChibiOS, and the motor-mask debug line
used a %08lx specifier on a uint32_t. uint32_t is unsigned long on
arm-none-eabi, so the format was correct there and wrong everywhere
else. Neither is portable to SITL, so AP_BLHeli could only build for
ChibiOS targets.
Use hal.util->get_system_id_unformatted() so the reply works on any
HAL - on ChibiOS it does the same memcpy from UDID_START that this
replaces - and cast the mask to match the format. The reply stays a
fixed 12 bytes, zero padded, matching AP_MSP_Telem_Backend.
Co-authored-by: Peter Barker <pb-gh@barker.dropbear.id.au>
The shared module inc probed the ICM-45686 at 24MHz, the part's rated
maximum. Every other icm45686 in the tree probes at 2MHz and only steps
up afterwards. The high-speed clock is unchanged at 24MHz.
Pull module-fixed pins (MCU type, oscillator, CAN1, USB, SWD, RMII
Ethernet PHY, on-module SPI3 IMU pads, CAN sleep/shutdown) into
hwdef.inc and hwdef-bl.inc so additional carrier boards built on the
CubeNode H757 module can reuse them without duplicating the module
pinout. The existing CubeNode AP_Periph dat files become thin wrappers
over the shared inc plus their AP_Periph-specific config.
CubeNode-ETH continues to include CubeNode/hwdef.dat unchanged.
_init_gyro() zeroed _board_orientation for the duration of the calibration
so the gyro samples came out in board frame, but that also stripped the
rotation from the accel. The last accel published in that window stays in
_accel[0], and AP_AHRS_DCM::reset() reads it a few lines later during
init_ardupilot(), gating only on the vector magnitude - so a board-frame
9.81 passes and DCM aligns to it. On a board mounted inverted that is 180
degrees out, and drift correction then takes minutes to walk it back,
failing the DCM attitude pre-arm throughout.
Skip the rotation in the gyro backend while _calibrating_gyro is set,
alongside the offset subtraction it already gates, and leave
_board_orientation alone. The accel is then never published in board frame
and DCM aligns level regardless of whether the value it reads is stale.
The ICM-56686 shares the ICM-456xy programming model, so this is a variant of
that path rather than a new driver: same FIFO header bits and the same 20 byte
high resolution packet, so the existing parser and accumulator are untouched.
Two things differ, both from DS-000563 rev 1.0. The register block from
PWR_MGMT0 upwards sits 4 higher, which reg456() maps at runtime, with WHO_AM_I
and the IREG window passing through unshifted. And SREG_CTRL resets to 0x0A on
this part - 20 bit sensor registers and big endian - where the ICM-45686 needs
no such write at all. The endianness applies to FIFO data as well, so it has to
be cleared before any sample is read or every value comes back byte swapped.
FS_SEL 0 selects 4000dps and 32g on both parts, so the scaling is shared.
Device ID is 0x08 against 0xE9, at the same address, so probing needs no
heuristics.
The MSP VTX tests only drove config into the FC. Also read
MSP_VTX_CONFIG back: the FC must report not-ready before the air unit's
boot handshake and, once it has uploaded its config, hand back the live
band, channel, power, pitmode and frequency with deviceIsReady set.
minimize_fpv_osd.inc force-enabled AP_MSP_VIDEOTX_ENABLED on the F405
FPV boards, costing ~1.5K of flash for a feature those boards rarely
use. Leave it to the default (off); 2MB boards that want it opt in via
their own hwdef.
Gate the AP_VideoTX include and the extra MSP_TIME_SLOT_MAX slot on
AP_MSP_VIDEOTX_ENABLED, whose default now lives here, and label the
matching #endifs.
sbuf_read_u8/u16 flag an exhausted buffer as an internal error rather
than quietly returning 0: callers guard every read, so an underflow is
a bug worth surfacing.
msp_vtx_set_pitmode uses the new AP_VideoTX::set_option_enabled.
set_option_enabled sets or clears a single configured option bit,
replacing the open-coded read-modify-write the MSP VTX pitmode path
used. Use ARRAY_SIZE(_power_levels) for the new power-level loops and
call the levels "active" to match the state they test.
It is non-essential and only useful with a digital VTX, so do not build it
into every >1MB board. Boards with the hardware opt in (FPV/OSD boards via
minimize_fpv_osd.inc, others by defining AP_MSP_VIDEOTX_ENABLED).
These boards default a serial port to MSP DisplayPort or DJI FPV, so they
have the digital VTX hardware that MSP VTX control targets. Enable it
explicitly now that it no longer defaults on for >1MB boards.
The msp_process_*_vtx_config and vtx_should_push_config declarations were
unconditional while their definitions are under AP_MSP_VIDEOTX_ENABLED, so
the vtable referenced undefined symbols on any build with the feature off.
Guard the declarations to match.
Add Copter coverage for the MSP VTX path: frequency changes over both the
direct and DisplayPort routes, power table learning with the one-based
power index, pitmode reporting with resend on warmup, and sending the
power table as dBm.
Implement betaflight-style VTX control over MSP so an MSP VTX (or an OSD
acting as one) can be configured from ArduPilot:
- reply to MSP_VTX_CONFIG and push config as MSP v2 native
- apply frequency changes from MSP_SET_VTX_CONFIG
- learn the power table from MSP_SET_VTXTABLE_POWERLEVEL and decode it
as dBm
- report the configured pitmode in MSP_VTX_CONFIG
- report the FC variant matching the active OSD symbol set
- option to hold the VTX at high power while disarmed
Process outgoing packets so config can be pushed unsolicited, and guard
the DisplayPort scheduler when VideoTX is disabled. The whole path is
gated on AP_MSP_VIDEOTX_ENABLED.
Add MSP as a VTX control transport alongside the existing providers.
VTX_TYPES selects which transport is allowed to drive the VTX so MSP and
SmartAudio/Tramp/CRSF do not fight over it.
The MSP provider is built behind AP_MSP_VIDEOTX_ENABLED, which requires
HAL_MSP_ENABLED and defaults on for boards with more than 1MB of flash.
Power levels from MSP arrive as a one-based index; map it onto the
supported levels so it lines up with the rest of the VTX power handling.
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
test scripting / test-scripting (push) Canceled after 0s
AP_Periph does not build AP_OSD, but OSD_ENABLED defaults to 1 so the
generated bindings failed to link with undefined references to
AP_OSD::_singleton
The scripting bindings took get_semaphore() around every OSD call, but the
OSD thread updated the display without it, so a scripting draw could run
concurrently with the OSD thread and the lock protected nothing.
Hold the semaphore in the OSD thread around the override check and
update_osd(), and set scripting_override under it, so the OSD thread and
scripting draws are mutually exclusive.
add semaphore protection for scripting bindings
Add get_semaphore() to AP_OSD_Backend that delegates to the parent
AP_OSD semaphore. Add semaphore keyword to scripting bindings so that
all OSD method calls from Lua are thread-safe with respect to the
OSD update thread.
Co-Authored-By: Iampete1 <iampete@hotmail.co.uk>
The ChibiOS 21.11.x merge dropped the rev X/Y conditionals upstream, which
left our STM32_ENFORCE_H7_REV_XY define a no-op on every H7 board that does
not set MCU_CLOCKRATE_MHZ 480. That silently disabled the errata 2.2.15 AXI
SRAM read corruption workaround and applied rev V only ODEN, CSICFGR and
ADC boost settings to rev X/Y parts.
stm32_clock_init() sets the ODEN bit in SYSCFG_PWRCR to put the core
into overdrive, which is required above STM32_SYSCLK_MAX_NOBOOST.
hal_lld_init() then reset every APB4 peripheral, and SYSCFG is on APB4,
so ODEN was cleared while the PLL kept running at the higher rate. The
core was left above its VOS1 rating with no indication.
The exclusion was already intended: the AHB4 reset above masks off
RCC_APB4RSTR_SYSCFGRST, but SYSCFG is not on AHB4 so it had no effect
there. On AHB4 that bit is GPIOBRST, which STM32_GPIO_EN_MASK already
covers, so that line is left alone.
Measured on an STM32H743 rev V at 480 MHz: SYSCFG_PWRCR reads 0x00
after boot without this change and 0x81 with it.
Flies a deterministic forward jab and release in optical-flow Loiter at low
height, where the EKF flow speed limit makes the AC_Loiter drag/feed-forward
mismatch visible, for before/after comparison of the fix.
FCAPv3 shares the TBS LUCID H7 electrical design but has no MAX7456: analog
OSD comes from an on-board STM32G431 co-processor fed MSP DisplayPort over
UART5. RC input is on UART4 (SBUS), leaving USART6 as a spare. Motor pads are
numbered S1-S10 from PA0 in silk order.
ChibiOS now reports the MSIPLL-locked 4MHz MSI range at its real
3.998MHz, giving a 79.96MHz SYSCLK rather than the nominal 80MHz. That
tripped the HAL_EXPECTED_SYSCLOCK static_assert on LSE-clocked L4 boards.
Also define HAL_CAN_ALLOW_INEXACT_CLOCK for CAN timing.
computeTimings required PCLK to be an exact integer multiple of the
target bitrate. On MSI-PLL/LSE clocked L4 boards PCLK is 79.96MHz, so the
1Mbit search truncated 79.96 to 79 (prime), found no solution, and left
the CAN interface uninitialised. Round the prescaler search to nearest
and accept the closest achievable bitrate within 1%. This is a no-op
where PCLK is an exact multiple, so other boards are unaffected.
Cover arming and Loiter when the compass is enabled but not an EK3 yaw
source (EK3_SRC1_YAW=0):
- LoiterNoCompassYaw: optical flow, no GPS. The EKF runs in relative
aiding with a free-running yaw, so arming directly in Loiter works.
- LoiterNoCompassYawGPS: GPS, no optical flow. The GSF yaw estimator
only aligns once moving, so Loiter cannot be entered on the ground;
the test arms in AltHold, flies forward to align yaw, then Loiters.
colcon build/test / build-test (push) Has been cancelled
Macos Build / build (CubeOrange) (push) Has been cancelled
Macos Build / build (sitl) (push) Has been cancelled
pre-commit / ci (push) Has been cancelled
test ccache / build (10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-EKF2, 10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-ODID, 10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-PPP, 10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (CubeRedPrimary-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (MatekF405-Wing, 10, chibios) (push) Has been cancelled
test chibios / build (Pixhawk6X-PPPGW, 10, chibios) (push) Has been cancelled
test chibios / build (SOHW, 10, chibios) (push) Has been cancelled
test chibios / build (build-options-defaults-test, 10, chibios) (push) Has been cancelled
test chibios / build (configure-all, 10, chibios) (push) Has been cancelled
test chibios / build (fmuv2-plane, 10, chibios) (push) Has been cancelled
test chibios / build (fmuv3, 10, chibios) (push) Has been cancelled
test chibios / build (fmuv3-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (iofirmware, 10, chibios) (push) Has been cancelled
test chibios / build (new-check, 10, chibios) (push) Has been cancelled
test chibios / build (periph-build, 10, chibios) (push) Has been cancelled
test chibios / build (revo-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (revo-mini, 10, chibios) (push) Has been cancelled
test chibios / build (signing, 10, chibios) (push) Has been cancelled
test chibios / build (stm32f7, 10, chibios) (push) Has been cancelled
test chibios / build (stm32h7, 10, chibios) (push) Has been cancelled
test chibios / build (stm32h7-debug, 10, chibios) (push) Has been cancelled
test dds / build (sitl) (push) Has been cancelled
test dds / build (stm32h7) (push) Has been cancelled
test scripts / build (astyle-cleanliness) (push) Has been cancelled
test scripts / build (check_autotest_options) (push) Has been cancelled
test scripts / build (logger_metadata) (push) Has been cancelled
test scripts / build (param-file-validation) (push) Has been cancelled
test scripts / build (param_parse) (push) Has been cancelled
test scripts / build (python-cleanliness) (push) Has been cancelled
test scripts / build (shellcheck) (push) Has been cancelled
test scripts / build (validate_board_list) (push) Has been cancelled
Cygwin Build / build (push) Has been cancelled
ESP32 Build / build (esp32buzz, 10) (push) Has been cancelled
ESP32 Build / build (esp32s3empty, 10) (push) Has been cancelled
QURT Build / build (push) Has been cancelled
test Linux SBC / build (bbbmini, armhf) (push) Has been cancelled
test Linux SBC / build (bebop, armhf) (push) Has been cancelled
test Linux SBC / build (bhat, armhf) (push) Has been cancelled
test Linux SBC / build (canzero, armhf) (push) Has been cancelled
test Linux SBC / build (erlebrain2, armhf) (push) Has been cancelled
test Linux SBC / build (navigator, armhf-musl) (push) Has been cancelled
test Linux SBC / build (navigator64, aarch64) (push) Has been cancelled
test Linux SBC / build (navio, armhf) (push) Has been cancelled
test Linux SBC / build (navio2, armhf) (push) Has been cancelled
test Linux SBC / build (pxf, armhf) (push) Has been cancelled
test Linux SBC / build (pxfmini, armhf) (push) Has been cancelled
test Linux SBC / build (t3-gem-o1, aarch64) (push) Has been cancelled
test replay / build (replay, base) (push) Has been cancelled
test replay / build (replay, clang) (push) Has been cancelled
test blimp / build (base) (push) Has been cancelled
test blimp / build (clang) (push) Has been cancelled
test copter / build (base) (push) Has been cancelled
test copter / build (clang) (push) Has been cancelled
test copter / build-gcc-heli (push) Has been cancelled
test ap_periph / build-gcc-ap_periph (push) Has been cancelled
test plane / build (base) (push) Has been cancelled
test plane / build (clang) (push) Has been cancelled
test rover / build (base) (push) Has been cancelled
test rover / build (clang) (push) Has been cancelled
test sub / build (base) (push) Has been cancelled
test sub / build (clang) (push) Has been cancelled
test tracker / build (base) (push) Has been cancelled
test tracker / build (clang) (push) Has been cancelled
test unit tests and sitl building / build (examples, base) (push) Has been cancelled
test unit tests and sitl building / build (examples, clang) (push) Has been cancelled
test unit tests and sitl building / build (sitl, base) (push) Has been cancelled
test unit tests and sitl building / build (sitl, clang) (push) Has been cancelled
test unit tests and sitl building / build (unit-tests, base) (push) Has been cancelled
test unit tests and sitl building / build (unit-tests, clang) (push) Has been cancelled
test blimp / autotest (sitltest-blimp) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1a) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1b) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1c) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1d) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1e) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests2a) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests2b) (push) Has been cancelled
test copter / autotest-heli (sitltest-heli) (push) Has been cancelled
test ap_periph / autotest-can (sitltest-can) (push) Has been cancelled
test plane / autotest (sitltest-plane-tests1a) (push) Has been cancelled
test plane / autotest (sitltest-plane-tests1b) (push) Has been cancelled
test plane / autotest (sitltest-plane-tests1c) (push) Has been cancelled
test plane / autotest (sitltest-quadplane) (push) Has been cancelled
test rover / autotest (sitltest-balancebot) (push) Has been cancelled
test rover / autotest (sitltest-rover) (push) Has been cancelled
test rover / autotest (sitltest-sailboat) (push) Has been cancelled
test sub / autotest (sitltest-sub) (push) Has been cancelled
test tracker / autotest (sitltest-tracker) (push) Has been cancelled
test Linux SBC / build (linux, base) (push) Has been cancelled
draw_vtx_power() previously displayed the configured (requested) power.
Tramp VTXes with a hardware power floor report a different actual value
that never reached the OSD. Prefer the self-reported actual when
available, falling back to configured for providers that don't report it
(e.g. SmartAudio).
The Tramp 'v' reply reports both configured and actual power, but only
the configured value reached AP_VideoTX, hiding VTXes that ignore the
request or have a hardware power floor. Expose the actual value via
set/get_actual_power_mw() (-1 = not reported) and warn once when it
exceeds VTX_MAX_POWER or the request by more than 50%.
update_power() also rejected any mW not in the SmartAudio power table,
silently dropping valid Tramp values like 2500mW. Accept off-table
values when a Tramp provider is active, stashing them in the custom
power slot so later equality checks still work.
A VTX that silently rejects a value drove an infinite retry loop because
update() re-armed retry_count on every mismatch. Re-arm only when the
configured value actually changes, and warn once when retries exhaust on
the same value. Also defines get_current_actual_power() and
get_current_temp(), which were declared but never implemented.
colcon build/test / build-test (push) Has been cancelled
Cygwin Build / build (push) Has been cancelled
ESP32 Build / build (esp32buzz, 10) (push) Has been cancelled
ESP32 Build / build (esp32s3empty, 10) (push) Has been cancelled
Macos Build / build (CubeOrange) (push) Has been cancelled
Macos Build / build (sitl) (push) Has been cancelled
pre-commit / ci (push) Has been cancelled
QURT Build / build (push) Has been cancelled
test ccache / build (10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-EKF2, 10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-ODID, 10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-PPP, 10, chibios) (push) Has been cancelled
test chibios / build (CubeOrange-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (CubeRedPrimary-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (MatekF405-Wing, 10, chibios) (push) Has been cancelled
test chibios / build (Pixhawk6X-PPPGW, 10, chibios) (push) Has been cancelled
test chibios / build (SOHW, 10, chibios) (push) Has been cancelled
test chibios / build (build-options-defaults-test, 10, chibios) (push) Has been cancelled
test chibios / build (configure-all, 10, chibios) (push) Has been cancelled
test chibios / build (fmuv2-plane, 10, chibios) (push) Has been cancelled
test chibios / build (fmuv3, 10, chibios) (push) Has been cancelled
test chibios / build (fmuv3-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (iofirmware, 10, chibios) (push) Has been cancelled
test chibios / build (new-check, 10, chibios) (push) Has been cancelled
test chibios / build (periph-build, 10, chibios) (push) Has been cancelled
test chibios / build (revo-bootloader, 10, chibios) (push) Has been cancelled
test chibios / build (revo-mini, 10, chibios) (push) Has been cancelled
test chibios / build (signing, 10, chibios) (push) Has been cancelled
test chibios / build (stm32f7, 10, chibios) (push) Has been cancelled
test chibios / build (stm32h7, 10, chibios) (push) Has been cancelled
test chibios / build (stm32h7-debug, 10, chibios) (push) Has been cancelled
test dds / build (sitl) (push) Has been cancelled
test dds / build (stm32h7) (push) Has been cancelled
test Linux SBC / build (bbbmini, armhf) (push) Has been cancelled
test Linux SBC / build (bebop, armhf) (push) Has been cancelled
test Linux SBC / build (bhat, armhf) (push) Has been cancelled
test Linux SBC / build (canzero, armhf) (push) Has been cancelled
test Linux SBC / build (erlebrain2, armhf) (push) Has been cancelled
test Linux SBC / build (navigator, armhf-musl) (push) Has been cancelled
test Linux SBC / build (navigator64, aarch64) (push) Has been cancelled
test Linux SBC / build (navio, armhf) (push) Has been cancelled
test Linux SBC / build (navio2, armhf) (push) Has been cancelled
test Linux SBC / build (pxf, armhf) (push) Has been cancelled
test Linux SBC / build (pxfmini, armhf) (push) Has been cancelled
test Linux SBC / build (t3-gem-o1, aarch64) (push) Has been cancelled
test replay / build (replay, base) (push) Has been cancelled
test replay / build (replay, clang) (push) Has been cancelled
test scripts / build (astyle-cleanliness) (push) Has been cancelled
test scripts / build (check_autotest_options) (push) Has been cancelled
test scripts / build (logger_metadata) (push) Has been cancelled
test scripts / build (param-file-validation) (push) Has been cancelled
test scripts / build (param_parse) (push) Has been cancelled
test scripts / build (python-cleanliness) (push) Has been cancelled
test scripts / build (shellcheck) (push) Has been cancelled
test scripts / build (validate_board_list) (push) Has been cancelled
test blimp / build (base) (push) Has been cancelled
test blimp / build (clang) (push) Has been cancelled
test copter / build (base) (push) Has been cancelled
test copter / build (clang) (push) Has been cancelled
test copter / build-gcc-heli (push) Has been cancelled
test ap_periph / build-gcc-ap_periph (push) Has been cancelled
test plane / build (base) (push) Has been cancelled
test plane / build (clang) (push) Has been cancelled
test rover / build (base) (push) Has been cancelled
test rover / build (clang) (push) Has been cancelled
test sub / build (base) (push) Has been cancelled
test sub / build (clang) (push) Has been cancelled
test tracker / build (base) (push) Has been cancelled
test tracker / build (clang) (push) Has been cancelled
test unit tests and sitl building / build (examples, base) (push) Has been cancelled
test unit tests and sitl building / build (examples, clang) (push) Has been cancelled
test unit tests and sitl building / build (sitl, base) (push) Has been cancelled
test unit tests and sitl building / build (sitl, clang) (push) Has been cancelled
test unit tests and sitl building / build (unit-tests, base) (push) Has been cancelled
test unit tests and sitl building / build (unit-tests, clang) (push) Has been cancelled
test blimp / autotest (sitltest-blimp) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1a) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1b) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1c) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1d) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests1e) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests2a) (push) Has been cancelled
test copter / autotest (sitltest-copter-tests2b) (push) Has been cancelled
test copter / autotest-heli (sitltest-heli) (push) Has been cancelled
test ap_periph / autotest-can (sitltest-can) (push) Has been cancelled
test plane / autotest (sitltest-plane-tests1a) (push) Has been cancelled
test plane / autotest (sitltest-plane-tests1b) (push) Has been cancelled
test plane / autotest (sitltest-plane-tests1c) (push) Has been cancelled
test plane / autotest (sitltest-quadplane) (push) Has been cancelled
test rover / autotest (sitltest-balancebot) (push) Has been cancelled
test rover / autotest (sitltest-rover) (push) Has been cancelled
test rover / autotest (sitltest-sailboat) (push) Has been cancelled
test sub / autotest (sitltest-sub) (push) Has been cancelled
test tracker / autotest (sitltest-tracker) (push) Has been cancelled
test Linux SBC / build (linux, base) (push) Has been cancelled
Rename STM32_I2C_I2Cn_IRQ_PRIORITY to STM32_IRQ_I2Cn_PRIORITY to
match the naming used by the kernel v9 I2Cv4 driver, mirroring
the same rename already applied to stm32g4_mcuconf.h.
The ChibiOS I2Cv4 LLD (used on STM32G0/G4/C0/U0/U3/H5/L4+) uses a
single DMA channel per I2C peripheral, shared between TX and RX,
configured via STM32_I2C_I2Cx_DMA_CHANNEL. The previous code
emitted the separate STM32_I2C_I2Cx_RX/TX_DMA_STREAM defines used
by I2Cv2/I2Cv3, which no longer satisfy the I2Cv4 driver.
Detect I2Cv4 MCUs from CHIBIOS_PLATFORM_MK, allocate a single DMA
channel per I2C peripheral in dma_resolver.py (no _RX/_TX split),
and generate HAL_I2Cn_CONFIG entries that feed the single channel
into the shared DMA slot with SHARED_DMA_NONE as the partner.
Also replace the unconditional STM32_I2C_USE_I2Cn TRUE lines in
stm32g4_mcuconf.h with #ifndef-guarded defaults to FALSE, so
boards only enable the I2C peripherals their hwdef actually uses.
Without this, the I2Cv4 driver demanded DMA channels for every
I2C peripheral on every G4 board regardless of pin usage.
EKF3 is a static member of the AP_AHRS_NavEKF3 backend wrapper, not a
direct member of AP_AHRS. Route the bootstrap reset call through ekf3.EKF3
and gate on AP_AHRS_NAVEKF3_ENABLED to match the surrounding code.
The aux switch now only resets the EKF when disarmed. Exercise both halves
of that rule: the disarmed reset succeeds and the origin survives across a
subsequent GUIDED takeoff (position hold proves the EKF origin did not
move), and an armed reset is refused with a STATUSTEXT.
Uses self.takeoff(), wait_statustext, and wait_location(minimum_duration=)
in place of the open-coded change_mode/arm/user_takeoff + delay_sim_time +
recv_match sequence.
Resetting the EKF while armed would discard the in-flight state estimate.
Check the armed flag first so reset_configured_backend() is not called when
armed, and emit a distinct STATUSTEXT for the refused-while-armed case.
Capture vehicle position before triggering the bootstrap reset and
assert horizontal drift stays under 5m after a 10s GUIDED hover. If
the EKF origin shifts during the reset, the position controller would
command a correction and the vehicle would fly away from the takeoff
point.
Save validOrigin and EKF_origin before InitialiseVariables() in
InitialiseFilterBootstrap() and restore them after, so an externally
commanded reset does not shift the local NED frame. Without this the
per-core EKF_origin gets re-set from the next GPS fix, diverging from
the shared frontend common_EKF_origin. On first boot validOrigin is
false and the restore is a no-op.
Add AP_AHRS_EKF_RESET_ENABLED to the custom build server so the
EKF bootstrap reset aux function can be compiled out on
flash-constrained boards. Enabled by default, depends on EKF3.
Add RCx_OPTION=187 (EKF_RESET) aux function that triggers a full EKF
bootstrap reset on HIGH, gated to fire only on state transition.
Sends GCS status message indicating whether the reset succeeded or
failed. Available for all vehicle types.
Gated by AP_AHRS_EKF_RESET_ENABLED compile-time option.