wait_until_altitude() returns on the first touch of the target band while
the vehicle is still climbing, so start_checking_altitude() latched the hold
reference mid-climb. The normal takeoff overshoot (~0.24 m) and slow VTOL
settle then exceeded the 0.15 m tolerance and the standard_vtol job failed
intermittently.
Wait for the overshoot to damp before capturing the reference, and restore
the 0.2 m tolerance established in #26106 (a later SIH rewrite had tightened
it back to 0.15 m). Steady-state hover holds to ~0.05 m, so the check stays
sensitive to real altitude-hold failures.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Since #27918 a blind descend reports the distinct Descend flight mode
instead of masquerading as Land. MAVSDK v3.17.1 has no Descend mode, so
wait_for_flight_mode(Land) timed out and SITL failed on main.
Losing GPS in SIH removes all horizontal position aiding, so the vehicle
always blind-descends after the mission GPS loss; a controlled Land is
never entered. The test already waits for the automatic disarm after
landing, which is the meaningful check.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Give NAVIGATION_STATE_DESCEND its own MAVLink custom_mode and advertise it so ground stations stop displaying it as Land.
---------
Signed-off-by: Elisa Ferrara <elisa.ferrara@auterion.com>
Shifting the remaining bytes with memmove and zeroing the tail is
functionally equivalent to the copy-out/zero/copy-back sequence and
removes the dynamic allocation entirely, along with the unchecked
malloc return.
Suggested-by: Beat Küng <beat@auterion.com>
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The swap buffer in VnSearcher_discardData was malloc'd but never freed,
leaking on every call. Reported by Martin Strunz.
No VnSearcher_* symbol is referenced by the driver today, so the linker
drops searcher.c entirely and no shipped firmware is affected. Fixed
anyway so the leak cannot go live if the port autodetect API is ever
used. Upstream vnproglib is frozen with no public repository, so the
fix is carried in the vendored copy.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Since b11e615810 src/modules/zenoh/Kconfig sources the generated topic
catalog through ZENOH_KCONFIG_TOPICS, which only cmake exports, so every
standalone Kconfig parse crashed and build_all_targets produced an empty
build matrix on every run while the scan job still reported success.
Add Tools/kconfig/loadconfig.py as the single entry point for parsing
the Kconfig tree outside cmake: it generates the topic catalog exactly
like cmake/kconfig.cmake and provides shared board/target enumeration
and config loading. Port generate_board_targets_json.py (CI matrix) and
updateconfig.py (make updateconfig) to it; both were independently
broken and each reimplemented board scanning on its own.
Harden the workflow so the next failure of this class is loud: run the
generator as a standalone assignment, so bash -e fails the step (the
previous echo "matrix=$(...)" form masked the exit code), and write
the JSON outputs through the heredoc GITHUB_OUTPUT form.
Matrix output verified byte-identical to the pre-b11e6158101 baseline
in all three modes; updateconfig output verified identical against the
same baseline.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
sensor_gps uORB instance numbering is boot-order dependent for CAN
receivers, so GPS_RAW_INT/GPS2_RAW showed a random receiver in dual-GPS
setups (e.g. moving base + rover RTK). Resolve the primary from
SENS_GPS_PRIME instead, matching the vehicle_gps_position selection
including DroneCAN node IDs (2-127). The node ID matching lives in
lib/gnss/SensorGpsSelector.hpp and is shared with vehicle_gps_position.
Each stream only reports its selected receiver and falls back to NO_GPS
keepalives if it has no data.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(crsf): correct GPS telemetry ground speed, course, and altitude offset
Ground speed was sent from the NED down-velocity component with the km/h conversion inverted, course over ground wraps negative values through the uint16 field, and the rc_input frame applied a +1 m offset where the protocol expects +1000 m.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(crsf): send local altitude and vertical speed telemetry
Add the CRSF barometric altitude frame (0x09), fed from vehicle_local_position, to both the crsf_rc driver and the legacy rc_input telemetry. Shows up as Alt and VSpd sensors on EdgeTX/OpenTX radios, complementing the MSL altitude already sent in the GPS frame.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(crsf): clarify local-altitude telemetry semantics and units
Note that the Alt/VSpd sensors reuse the CRSF baro-altitude frame to carry PX4's fused local altitude (above the estimator origin), not a raw barometer reading, and document the EdgeTX version requirements. Add terse unit comments on the GPS-frame fields.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
The rangefinder bridge published TOO_CLOSE, TOO_FAR and UNDEFINED
readings with signal_quality -1 (unknown) and the raw wire range, so
consumers treated them as usable measurements. DroneCAN rangefinder
nodes commonly report an out-of-range sentinel value in the range field
for these reading types (e.g. max_distance + 1 for TOO_FAR); flight
logs show the EKF fusing a node's 101 m TOO_FAR sentinel as terrain
distance at 45-113 m AGL.
Per the distance_sensor uORB convention (0 = invalid signal), mark all
non-VALID_RANGE readings as quality 0 so downstream consumers reject
them.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ekf2): correct Minimum spelling in range validity param short
User-facing EKF2 range finder parameter description for QGC metadata.
* ci: retrigger SITL after flaky standard_vtol failure
---------
Co-authored-by: Daniel Pike <daniel@team-of-light.com>
Give PRs generated via the skill a fixed, skimmable structure instead of an ad-hoc leading paragraph. Keeps the existing no-attribution, no-test-plan, and terse rules.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
wait_until_ready() polls MAVSDK's is_armable, but a known hysteresis gap
(and estimator heading-reference flicker at startup) means the flag can
read armable while PX4 then denies the arm command with 'no heading
reference'. This made arm() fail intermittently. Retry the arm command
until the autopilot accepts it, so the transient is absorbed while real
failures still time out.
Signed-off-by: Julian Oes <julian@oes.ch>
The four older VTOL RTL tests waited only 120s for disarm while running
the same climb-to-550m-and-land missions as the other RTL tests, which
already use 150s. 'RTL direct Mission Land' occasionally tipped just
over 120s of sim time (observed 123.76s), failing wait_until_disarmed.
Align all of them to 150s for margin.
Signed-off-by: Julian Oes <julian@oes.ch>
Switching the SITL tests to the SIH simulator exercises sih.cpp, whose
gcov data contains a spurious negative counter (line 510) that newer
lcov treats as a fatal error, failing the coverage step. Pass
--ignore-errors negative so lcov zeroes the bad count and continues, as
the tool itself suggests.
Signed-off-by: Julian Oes <julian@oes.ch>
The 0.01m (1cm) tolerance was not reachable within the 15s sim-time
window for the standard_vtol, causing the takeoff-and-hold test to time
out. Use 0.1m, which still verifies altitude hold but is physically
achievable, and stays below the 0.15m hold-monitoring tolerance.
Signed-off-by: Julian Oes <julian@oes.ch>
MAVSDK's OffboardImpl::process_heartbeat() resets the setpoint state to
NotActive when a heartbeat without offboard mode arrives more than 3 s
after _last_started. _last_started is only ever written by start(), so
before the first start() it is epoch zero and the guard is always true:
any heartbeat that slips in between set_*() and start() makes start()
fail with NoSetpointSet.
At speed factor 30 PX4's 1 Hz (sim time) heartbeat arrives every ~33 ms
of wall time, which made 'Offboard attitude control' fail roughly one
run in three. Re-send the setpoint and retry start() in a small loop at
both offboard start sites. Failed 1/3 before, 16/16 after.
This is arguably a MAVSDK bug (_last_started should be initialized when
setpoint streaming begins); a retry keeps the tests robust either way.
Signed-off-by: Julian Oes <julian@oes.ch>
Two related thread-safety fixes for the cond_timedwait + set_absolute_time
dance, both surfaced under TSan with multi-instance Mavlink and a fast
sim clock advance:
1. Signal loss between releasing _timed_waits_mutex and entering
pthread_cond_wait. set_absolute_time could have already broadcast
to a waiter that hadn't actually started waiting yet, and the
broadcast would be missed -> wait blocks forever.
Fix: cond_timedwait uses pthread_cond_timedwait with a short
wall-clock timeout (10 ms) and re-checks the timeout flag. Lost
signals turn into a maximum of one loop iteration of latency.
2. ABBA between (passed_lock -> _timed_waits_mutex) used by
cond_timedwait to mark `done`, and (passed_lock under
_timed_waits_mutex) used by set_absolute_time to broadcast. TSan
flagged the inversion immediately.
Fix: split set_absolute_time into three phases. Phase 1 marks
timed_outs and stages waiters onto a per-call signal_next list,
under _timed_waits_mutex only. Phase 2 broadcasts to each waiter,
outside _timed_waits_mutex but under a new _signaling_mutex held
for the duration. Phase 3 clears _setting_time under the
_timed_waits_mutex again.
The waiter's "dance" (when it sees _setting_time still true on
exit) acquires _signaling_mutex first, then _timed_waits_mutex,
guaranteeing it cannot return — and let its stack-local
passed_lock/passed_cond go out of scope — until set_absolute_time
has finished signaling.
The TimedWait::timeout flag also becomes std::atomic<bool> since it
is now read by cond_timedwait without holding _timed_waits_mutex.
poll_condition_with_timeout polls the autopilot's monotonic time, which is
already simulation time. The previous code divided a sim-time budget by the
speed factor to compute a wall-clock timeout, but this is unnecessary and
adds a dependency on the speed-factor query.
Symmetric with the existing COM_DL_LOSS_T / COM_RC_LOSS_T /
COM_OF_LOSS_T / COM_OBC_LOSS_T scalings just above. At high simulation
speed the default 10s preflight disarm is reached much sooner in
real wall time than tests expect, so scale it the same way.
Replace 5 functions that used std::future::wait_for() (wall-clock time)
with poll_condition_with_timeout() (simulation time). This prevents
timeouts from expiring prematurely when running at high speed factors
under lockstep.
Affected functions:
- wait_until_altitude()
- wait_for_landed_state()
- wait_for_flight_mode()
- start_and_wait_for_mission_sequence()
- wait_until_speed_lower_than()
Also remove debug printf statements from start_checking_altitude().
The DO_LAND_START item carried loiter params (heading required, radius,
and a stray 1 in param3) hand-copied from the adjacent LOITER_TO_ALT
item, and LOITER_TO_ALT itself had param3 set, which the spec defines
as empty. PX4's mission item param validation now rejects such items.
Signed-off-by: Julian Oes <julian@oes.ch>
The param validation table rejected mission items that QGC-generated
plans legitimately contain:
- NAV_VTOL_LAND param3 is the approach altitude per the MAVLink spec.
QGC writes it in every VTOL landing pattern; PX4's mission logic
ignores it, but that is no reason to reject the upload.
- DO_LAND_START param5-7 are the optional lat/lon/alt marker position
per the spec, which QGC also writes.
Both made any QGC VTOL landing plan fail to upload with
MAV_MISSION_INVALID_PARAMx, surfaced by the SIH SITL VTOL tests.
Signed-off-by: Julian Oes <julian@oes.ch>
The ExternalProject_Add(mavsdk_tests ...) lived at the bottom of
sitl_targets_gazebo-classic.cmake, outside the if(gazebo_FOUND) gate
and with a comment noting it doesn't depend on sitl_gazebo. Historical
artifact: mavsdk_tests is a black-box MAVLink test driver that talks
to a running PX4 over UDP, and works against any simulator backend
(sitl_gazebo-classic, gz, sih, jmavsim, ...).
With CI moving from classic Gazebo to SIH, the misplacement becomes
actively misleading. Pull the block into a new top-level
cmake/mavsdk_tests.cmake and include it from CMakeLists.txt under the
existing posix-only block, so the dependency graph reflects what is
actually true.
Behavior is unchanged: target is EXCLUDE_FROM_ALL, only built on
demand via `make mavsdk_tests` or `make tests_integration`.
Reverts the hotfix from #27487. The navigator now guarantees the course
field is NaN unless Course mode explicitly commands it, so
PX4_ISFINITE(course) is again a sufficient trigger for course guidance.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The reposition triplet was zero-initialized at boot and memset after
consumption, and mission_item_to_position_setpoint() never wrote the
course field, so a finite course (0.0, or stale after leaving Course
mode) could leak into published position setpoints. Reset the
reposition triplet with reset_position_setpoint() and clear course when
converting mission items, so the field is only finite while Course mode
commands it.
Replaces the consumer-side clear from #27537 with a fix at the source.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>