QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
VehicleGPSFactGroup.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5
6#include <QtCore/QDateTime>
7#include <QtPositioning/QGeoCoordinate>
8
9#include "MAVLinkLib.h"
10#include "QGCGeo.h"
11#include "QGCLoggingCategory.h"
12#include "RuntimeScheduler.h"
13#include "Vehicle.h"
14#include "development/mavlink_msg_gnss_integrity.h"
15
17 : FactGroup(1000, QStringLiteral(":/json/Vehicle/GPSFact.json"), parent)
18 , _receiver(receiver)
19 , _scheduler(RuntimeScheduler::orDefault(scheduler, this))
20 , _rtkStatusExpiry(_scheduler, this)
21 , _integrityExpiry(_scheduler, this)
22{
23 _addFact(&_latFact);
24 _addFact(&_lonFact);
25 _addFact(&_mgrsFact);
26 _addFact(&_hdopFact);
27 _addFact(&_vdopFact);
28 _addFact(&_horizontalAccuracyFact);
29 _addFact(&_verticalAccuracyFact);
30 _addFact(&_courseOverGroundFact);
31 _addFact(&_yawFact);
32 _addFact(&_lockFact);
33 _addFact(&_countFact);
34 _addFact(&_systemErrorsFact);
35 _addFact(&_spoofingStateFact);
36 _addFact(&_jammingStateFact);
37 _addFact(&_authenticationStateFact);
38 _addFact(&_correctionsQualityFact);
39 _addFact(&_systemQualityFact);
40 _addFact(&_gnssSignalQualityFact);
41 _addFact(&_postProcessingQualityFact);
42 _addFact(&_rtkBaselineFact);
43 _addFact(&_rtkRateFact);
44 _addFact(&_rtkSatellitesFact);
45
46 (void) connect(&_systemErrorsFact, &Fact::rawValueChanged, this, &VehicleGPSFactGroup::systemErrorTextChanged);
47 for (Fact* fact : {&_spoofingStateFact, &_jammingStateFact, &_authenticationStateFact}) {
49 }
50
51 _latFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
52 _lonFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
53 _mgrsFact.setRawValue("");
54 _hdopFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
55 _vdopFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
56 _horizontalAccuracyFact.setRawValue(qQNaN());
57 _verticalAccuracyFact.setRawValue(qQNaN());
58 _courseOverGroundFact.setRawValue(std::numeric_limits<float>::quiet_NaN());
59 _yawFact.setRawValue(qQNaN());
60 _clearIntegrity();
61 _clearRtkStatus();
62}
63
65{
66 Q_UNUSED(vehicle);
67
68 switch (message.msgid) {
69 case MAVLINK_MSG_ID_GPS_RAW_INT:
70 if (_receiver == ReceiverIndex::Primary) {
71 _handleGpsRaw(message);
72 }
73 break;
74 case MAVLINK_MSG_ID_GPS2_RAW:
75 if (_receiver == ReceiverIndex::Secondary) {
76 _handleGpsRaw(message);
77 }
78 break;
79 case MAVLINK_MSG_ID_HIGH_LATENCY:
80 if (_receiver == ReceiverIndex::Primary) {
81 _handleHighLatency(message);
82 }
83 break;
84 case MAVLINK_MSG_ID_HIGH_LATENCY2:
85 if (_receiver == ReceiverIndex::Primary) {
86 _handleHighLatency2(message);
87 }
88 break;
89 case MAVLINK_MSG_ID_GNSS_INTEGRITY:
90 _handleGnssIntegrity(message);
91 break;
92 case MAVLINK_MSG_ID_GPS_RTK:
93 if (_receiver == ReceiverIndex::Primary) {
94 _handleGpsRtk(message);
95 }
96 break;
97 case MAVLINK_MSG_ID_GPS2_RTK:
98 if (_receiver == ReceiverIndex::Secondary) {
99 _handleGpsRtk(message);
100 }
101 break;
102 default:
103 break;
104 }
105}
106
107void VehicleGPSFactGroup::_updateFix(int fixType, int satellitesVisible, double hdopValue, double vdopValue,
108 double courseValue, double yawValue)
109{
110 count()->setRawValue(satellitesVisible == UINT8_MAX ? 0 : satellitesVisible);
111 hdop()->setRawValue(hdopValue);
112 vdop()->setRawValue(vdopValue);
113 courseOverGround()->setRawValue(courseValue);
114 yaw()->setRawValue(yawValue);
115 lock()->setRawValue(fixType);
116}
117
118void VehicleGPSFactGroup::_reportPosition(QGeoPositionInfo position, int fixType)
119{
120 position.setTimestamp(QDateTime::currentDateTimeUtc());
121 const auto coordinate = position.coordinate();
122 lat()->setRawValue(coordinate.latitude());
123 lon()->setRawValue(coordinate.longitude());
124 mgrs()->setRawValue(coordinate.isValid() ? QGCGeo::convertGeoToMGRS(coordinate) : QString());
125 horizontalAccuracy()->setRawValue(position.attribute(QGeoPositionInfo::HorizontalAccuracy));
126 verticalAccuracy()->setRawValue(position.attribute(QGeoPositionInfo::VerticalAccuracy));
128 emit positionReported(position, fixType);
129}
130
131void VehicleGPSFactGroup::_handleGpsRaw(const mavlink_message_t& message)
132{
133 const auto update = [this](const auto& raw) {
134 QGeoPositionInfo position;
135 position.setCoordinate(QGeoCoordinate(raw.lat * 1e-7, raw.lon * 1e-7, raw.alt / 1000.0));
136 if (raw.h_acc != 0) {
137 position.setAttribute(QGeoPositionInfo::HorizontalAccuracy, raw.h_acc / 1000.0);
138 }
139 if (raw.v_acc != 0) {
140 position.setAttribute(QGeoPositionInfo::VerticalAccuracy, raw.v_acc / 1000.0);
141 }
142 if (raw.cog < 36000) {
143 position.setAttribute(QGeoPositionInfo::Direction, raw.cog / 100.0);
144 }
145 const double hdopValue = raw.eph == UINT16_MAX ? qQNaN() : raw.eph / 100.0;
146 const double vdopValue = raw.epv == UINT16_MAX ? qQNaN() : raw.epv / 100.0;
147 const double yawValue = raw.yaw > 0 && raw.yaw <= 36000 ? (raw.yaw % 36000) / 100.0 : qQNaN();
148 _updateFix(raw.fix_type, raw.satellites_visible, hdopValue, vdopValue,
149 position.attribute(QGeoPositionInfo::Direction), yawValue);
150 _reportPosition(position, raw.fix_type);
151 };
152 if (message.msgid == MAVLINK_MSG_ID_GPS_RAW_INT) {
153 mavlink_gps_raw_int_t raw{};
154 mavlink_msg_gps_raw_int_decode(&message, &raw);
155 update(raw);
156 } else {
157 mavlink_gps2_raw_t raw{};
158 mavlink_msg_gps2_raw_decode(&message, &raw);
159 update(raw);
160 }
161}
162
163void VehicleGPSFactGroup::_handleHighLatency(const mavlink_message_t& message)
164{
165 mavlink_high_latency_t highLatency{};
166 mavlink_msg_high_latency_decode(&message, &highLatency);
167
168 QGeoPositionInfo position;
169 position.setCoordinate(
170 QGeoCoordinate(highLatency.latitude * 1e-7, highLatency.longitude * 1e-7, highLatency.altitude_amsl));
171 _updateFix(highLatency.gps_fix_type, highLatency.gps_nsat, qQNaN(), qQNaN(), qQNaN(), qQNaN());
172 _reportPosition(position, highLatency.gps_fix_type);
173}
174
175void VehicleGPSFactGroup::_handleHighLatency2(const mavlink_message_t& message)
176{
177 mavlink_high_latency2_t highLatency2{};
178 mavlink_msg_high_latency2_decode(&message, &highLatency2);
179
180 QGeoPositionInfo position;
181 position.setCoordinate(
182 QGeoCoordinate(highLatency2.latitude * 1e-7, highLatency2.longitude * 1e-7, highLatency2.altitude));
183 if (highLatency2.eph != UINT8_MAX) {
184 position.setAttribute(QGeoPositionInfo::HorizontalAccuracy, highLatency2.eph / 10.0);
185 }
186 if (highLatency2.epv != UINT8_MAX) {
187 position.setAttribute(QGeoPositionInfo::VerticalAccuracy, highLatency2.epv / 10.0);
188 }
189 // HIGH_LATENCY2 reports an estimated global position and no receiver state, so the fix facts keep their values
190 // and the report does not count as a GPS fix.
191 _reportPosition(position, GPS_FIX_TYPE_NO_GPS);
192}
193
194void VehicleGPSFactGroup::_handleGnssIntegrity(const mavlink_message_t& message)
195{
196 mavlink_gnss_integrity_t gnssIntegrity;
197 mavlink_msg_gnss_integrity_decode(&message, &gnssIntegrity);
198
199 if (gnssIntegrity.id != static_cast<uint8_t>(_receiver)) {
200 return;
201 }
202
203 systemErrors()->setRawValue (gnssIntegrity.system_errors);
204 spoofingState()->setRawValue (gnssIntegrity.spoofing_state);
205 jammingState()->setRawValue (gnssIntegrity.jamming_state);
206 authenticationState()->setRawValue (gnssIntegrity.authentication_state);
207 correctionsQuality()->setRawValue (gnssIntegrity.corrections_quality);
208 systemQuality()->setRawValue (gnssIntegrity.system_status_summary);
209 gnssSignalQuality()->setRawValue (gnssIntegrity.gnss_signal_quality);
210 postProcessingQuality()->setRawValue(gnssIntegrity.post_processing_quality);
211 (void) _integrityExpiry.schedule(GNSS_INTEGRITY_TIMEOUT, [this]() { _clearIntegrity(); });
212}
213
214void VehicleGPSFactGroup::_clearIntegrity()
215{
216 _systemErrorsFact.setRawValue(0);
217 for (Fact* fact : {&_spoofingStateFact, &_jammingStateFact, &_authenticationStateFact, &_correctionsQualityFact,
218 &_systemQualityFact, &_gnssSignalQualityFact, &_postProcessingQualityFact}) {
219 fact->setRawValue(NOT_REPORTED);
220 }
221}
222
223void VehicleGPSFactGroup::_handleGpsRtk(const mavlink_message_t& message)
224{
225 const auto apply = [this](const auto& rtk) {
226 // Baseline length is independent of whether the components are ECEF or NED.
227 const double a = rtk.baseline_a_mm;
228 const double b = rtk.baseline_b_mm;
229 const double c = rtk.baseline_c_mm;
230 rtkBaseline()->setRawValue(std::sqrt(a * a + b * b + c * c) / 1000.0);
231 rtkRate()->setRawValue(rtk.rtk_rate);
232 rtkSatellites()->setRawValue(rtk.nsats);
233 };
234 if (message.msgid == MAVLINK_MSG_ID_GPS2_RTK) {
235 mavlink_gps2_rtk_t rtk;
236 mavlink_msg_gps2_rtk_decode(&message, &rtk);
237 apply(rtk);
238 } else {
239 mavlink_gps_rtk_t rtk;
240 mavlink_msg_gps_rtk_decode(&message, &rtk);
241 apply(rtk);
242 }
243 (void) _rtkStatusExpiry.schedule(RTK_STATUS_TIMEOUT, [this]() { _clearRtkStatus(); });
244}
245
246void VehicleGPSFactGroup::_clearRtkStatus()
247{
248 _rtkBaselineFact.setRawValue(qQNaN());
249 _rtkRateFact.setRawValue(qQNaN());
250 _rtkSatellitesFact.setRawValue(-1);
251}
252
254{
255 // MAVLink GPS_SYSTEM_ERROR_FLAGS.
256 static constexpr const char* ERROR_NAMES[] = {
257 QT_TR_NOOP("Incoming correction"),
258 QT_TR_NOOP("Configuration"),
259 QT_TR_NOOP("Software"),
260 QT_TR_NOOP("Antenna"),
261 QT_TR_NOOP("Event congestion"),
262 QT_TR_NOOP("CPU overload"),
263 QT_TR_NOOP("Output congestion"),
264 };
265 const quint32 errors = _systemErrorsFact.rawValue().toUInt();
266 QStringList names;
267 quint32 known = 0;
268 for (quint32 bit = 0; bit < std::size(ERROR_NAMES); ++bit) {
269 known |= 1u << bit;
270 if (errors & (1u << bit)) {
271 names.append(tr(ERROR_NAMES[bit]));
272 }
273 }
274 if (errors & ~known) {
275 names.append(tr("Other (0x%1)").arg(errors & ~known, 0, 16));
276 }
277 return names.join(QStringLiteral(", "));
278}
279
281{
282 return reported(_jammingStateFact.rawValue().toInt());
283}
284
286{
287 return reported(_spoofingStateFact.rawValue().toInt());
288}
289
291{
292 return reported(_authenticationStateFact.rawValue().toInt());
293}
294
296{
297 const int spoofing = _spoofingStateFact.rawValue().toInt();
298 const int jamming = _jammingStateFact.rawValue().toInt();
299 return (std::max) (reported(spoofing) ? spoofing : 0, reported(jamming) ? jamming : 0);
300}
301
303{
304 switch (static_cast<AuthenticationState>(_authenticationStateFact.rawValue().toInt())) {
306 return 1;
308 return 2;
310 return 3;
312 return 4;
313 default:
314 return 0;
315 }
316}
struct __mavlink_message mavlink_message_t
Geographic coordinate conversion utilities using GeographicLib.
struct __mavlink_high_latency2_t mavlink_high_latency2_t
Used to group Facts together into an object hierarachy.
Definition FactGroup.h:16
void _setTelemetryAvailable(bool telemetryAvailable)
Definition FactGroup.cc:175
void _addFact(Fact *fact, const QString &name)
Definition FactGroup.cc:116
A Fact is used to hold a single value within the system.
Definition Fact.h:15
void rawValueChanged(const QVariant &value)
void setRawValue(const QVariant &value)
Definition Fact.cc:135
QVariant rawValue() const
Definition Fact.h:87
bool schedule(std::chrono::microseconds delay, RuntimeScheduler::Callback callback)
bool authenticationReported() const
Fact * rtkBaseline()
GPS_RTK (primary) or GPS2_RTK (secondary); cleared when the vehicle stops reporting them.
static constexpr std::chrono::seconds GNSS_INTEGRITY_TIMEOUT
The GNSS_INTEGRITY facts return to unreported when the vehicle stops sending it for this long.
void handleMessage(Vehicle *vehicle, const mavlink_message_t &message) override
Allows a FactGroup to parse incoming messages and fill in values.
static constexpr int NOT_REPORTED
The value of a state the vehicle has not reported.
QString systemErrorText() const
The receiver's reported system errors, comma separated; empty when there are none.
ReceiverIndex
The worse of the reported spoofing and jamming states, or 0 when neither is reported.
static constexpr bool reported(int state)
A state other than Unknown or NOT_REPORTED.
AuthenticationState
MAVLink GPS_AUTHENTICATION_STATE.
void systemErrorTextChanged()
void positionReported(const QGeoPositionInfo &position, int fixType)
static constexpr std::chrono::seconds RTK_STATUS_TIMEOUT
VehicleGPSFactGroup(QObject *parent=nullptr, RuntimeScheduler *scheduler=nullptr, ReceiverIndex receiver=ReceiverIndex::Primary)
GPSPositionReport position(const GPSDecodedPosition &source, const GPSIntegrityReport &diagnostic, uint64_t nowUs)
std::optional< double > coordinate(std::string_view field, std::string_view hemisphere, bool latitude)
QString convertGeoToMGRS(const QGeoCoordinate &coord)
Definition QGCGeo.cc:179