From 9ec0186ab74bc55d7bb6e219bdf8da98398bb3f1 Mon Sep 17 00:00:00 2001 From: Julian Oes Date: Fri, 3 Jul 2026 14:11:36 +1200 Subject: [PATCH 1/2] RemoteIDManager: Stamp GCS GPS freshness from local arrival time The freshness check in _sendSystem() compared update.timestamp() (the position source's own clock) against the local wall clock. On Android that timestamp is offset from the system clock, and when the offset sat near the 5s ALLOWED_GPS_DELAY threshold the computed age swept across it every send cycle, flapping gcsGPSGood green/red at 1 Hz despite a healthy 1 Hz fix. Record the local arrival time instead, so the check measures the true time since the last valid fix and is immune to GPS-vs-system clock skew. --- src/Vehicle/RemoteIDManager.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Vehicle/RemoteIDManager.cc b/src/Vehicle/RemoteIDManager.cc index 54a4086ee5bc..7fce98135bc3 100644 --- a/src/Vehicle/RemoteIDManager.cc +++ b/src/Vehicle/RemoteIDManager.cc @@ -488,6 +488,10 @@ void RemoteIDManager::setEmergency(bool declare) void RemoteIDManager::_updateLastGCSPositionInfo(QGeoPositionInfo update) { if (update.isValid()) { - _lastGeoPositionTimeStamp = update.timestamp().toUTC(); + // Stamp the local arrival time rather than update.timestamp(). The freshness + // check in _sendSystem() compares this against the local wall clock, and on some + // platforms (e.g. Android) the position source's own timestamp is offset from the + // system clock, which made gcsGPSGood flap green/red even with a healthy fix. + _lastGeoPositionTimeStamp = QDateTime::currentDateTimeUtc(); } } From fced979de7490f4655db822d0b63510b85d351ea Mon Sep 17 00:00:00 2001 From: Julian Oes Date: Mon, 6 Jul 2026 11:30:18 +1200 Subject: [PATCH 2/2] PositionManager: Keep GPS altitude for poor vertical accuracy Altitude was dropped whenever the fix's vertical accuracy exceeded a strict 10m gate (or wasn't reported), which the Android position source almost never meets, leaving gcsPosition.altitude() as NaN. Remote ID in FAA regions mandates an operator altitude, so this made Live GNSS unusable there. Accept the altitude on any 3D fix when the vertical accuracy is within threshold or not reported at all, and raise the vertical threshold to 100m to match the horizontal one. --- src/PositionManager/PositionManager.cpp | 13 ++++++++++--- src/PositionManager/PositionManager.h | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/PositionManager/PositionManager.cpp b/src/PositionManager/PositionManager.cpp index 17ee71614375..596f00a43ea5 100644 --- a/src/PositionManager/PositionManager.cpp +++ b/src/PositionManager/PositionManager.cpp @@ -119,11 +119,18 @@ void QGCPositionManager::_positionUpdated(const QGeoPositionInfo &update) } } + // Accept the altitude when the fix carries one and the vertical accuracy is either + // acceptable or not reported at all. The Android position source typically reports a + // vertical accuracy well above the old 10m gate (or none), which used to drop the + // altitude entirely and leave consumers such as Remote ID (which mandates an operator + // altitude in FAA regions) with a NaN. + bool verticalAccuracyOk = true; if (update.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) { _gcsPositionVerticalAccuracy = update.attribute(QGeoPositionInfo::VerticalAccuracy); - if (_gcsPositionVerticalAccuracy <= kMinVerticalAccuracyMeters) { - newGCSPosition.setAltitude(update.coordinate().altitude()); - } + verticalAccuracyOk = (_gcsPositionVerticalAccuracy <= kMinVerticalAccuracyMeters); + } + if ((update.coordinate().type() == QGeoCoordinate::Coordinate3D) && verticalAccuracyOk) { + newGCSPosition.setAltitude(update.coordinate().altitude()); } _gcsPositionAccuracy = sqrt(pow(_gcsPositionHorizontalAccuracy, 2) + pow(_gcsPositionVerticalAccuracy, 2)); diff --git a/src/PositionManager/PositionManager.h b/src/PositionManager/PositionManager.h index 13c75b90c62d..53a92ce161d8 100644 --- a/src/PositionManager/PositionManager.h +++ b/src/PositionManager/PositionManager.h @@ -85,6 +85,6 @@ private slots: QGCCompass *_compass = nullptr; static constexpr qreal kMinHorizonalAccuracyMeters = 100.; - static constexpr qreal kMinVerticalAccuracyMeters = 10.; + static constexpr qreal kMinVerticalAccuracyMeters = 100.; static constexpr qreal kMinDirectionAccuracyDegrees = 30.; };