You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
QGC carries two different notions of the vehicle's AMSL altitude, and on PX4 they diverge with a persistent offset:
vehicle.coordinate.altitude — always GPS frame, from GLOBAL_POSITION_INT (Vehicle::_handleGlobalPositionInt).
vehicle.altitudeAMSL fact — starts out GPS frame (GLOBAL_POSITION_INT / GPS_RAW_INT), but as soon as an ALTITUDE message is received, VehicleFactGroup::_handleAltitude sets _altitudeMessageAvailable and the fact switches to altitude_amsl from that message, which on PX4 is the barometric/local estimator frame. The GPS-frame writers in Vehicle::_handleGpsRawInt / _handleGlobalPositionInt are gated off from then on.
On PX4 the baro and GPS frames carry a persistent offset (baro drift, QNH error), so the two values disagree for the whole flight. ArduPilot doesn't send ALTITUDE, so it is unaffected.
Consequences
Any code that mixes the two frames (or mixes the fact with DEM/terrain data) inherits the offset:
TerrainQueryCoordinator::_altitudeAboveTerrainReceived computes altitudeAboveTerr = altitudeAMSL fact − DEM terrain height. DEM heights are geodetic; on PX4 the fact is baro frame, so the reported altitude-above-terrain is off by the frame offset.
Anything else comparing the fact against HOME_POSITION, mission item altitudes, or DEM data has the same latent problem.
Possible directions
Decide which frame the altitudeAMSL fact is supposed to represent and make it consistent regardless of message availability (e.g. keep it GPS frame and expose the baro/estimator altitude as a separate fact).
Audit consumers of vehicle->altitudeAMSL() (TerrainQueryCoordinator, PX4/APM firmware plugins, guided-mode paths) and pin each to the frame it actually needs.
Document the frame semantics on the fact so future consumers don't mix frames unknowingly.
QGC carries two different notions of the vehicle's AMSL altitude, and on PX4 they diverge with a persistent offset:
vehicle.coordinate.altitude— always GPS frame, fromGLOBAL_POSITION_INT(Vehicle::_handleGlobalPositionInt).vehicle.altitudeAMSLfact — starts out GPS frame (GLOBAL_POSITION_INT/GPS_RAW_INT), but as soon as anALTITUDEmessage is received,VehicleFactGroup::_handleAltitudesets_altitudeMessageAvailableand the fact switches toaltitude_amslfrom that message, which on PX4 is the barometric/local estimator frame. The GPS-frame writers inVehicle::_handleGpsRawInt/_handleGlobalPositionIntare gated off from then on.On PX4 the baro and GPS frames carry a persistent offset (baro drift, QNH error), so the two values disagree for the whole flight. ArduPilot doesn't send
ALTITUDE, so it is unaffected.Consequences
Any code that mixes the two frames (or mixes the fact with DEM/terrain data) inherits the offset:
TerrainQueryCoordinator::_altitudeAboveTerrainReceivedcomputesaltitudeAboveTerr = altitudeAMSL fact − DEM terrain height. DEM heights are geodetic; on PX4 the fact is baro frame, so the reported altitude-above-terrain is off by the frame offset.altitudeAMSLfact and rendered offset from the trajectory/HOME_POSITION (both GPS frame). Worked around in feat(GeoMap): map item overlays with 3D vehicle marker and flight path ribbon #14876 by switching tocoordinate.altitude, with a comment explaining the trap.HOME_POSITION, mission item altitudes, or DEM data has the same latent problem.Possible directions
altitudeAMSLfact is supposed to represent and make it consistent regardless of message availability (e.g. keep it GPS frame and expose the baro/estimator altitude as a separate fact).vehicle->altitudeAMSL()(TerrainQueryCoordinator, PX4/APM firmware plugins, guided-mode paths) and pin each to the frame it actually needs.Refs:
VehicleFactGroup::_handleAltitude(frame switch),Vehicle::_handleGpsRawInt/_handleGlobalPositionInt(gated GPS writers),TerrainQueryCoordinator.cc(frame mixing), #14876 (marker workaround).