QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
NTRIPVehicleGgaSource.cc
Go to the documentation of this file.
2
3#include <QtCore/QDateTime>
4#include <QtCore/QPointer>
5
6#include "GPSProtocolMath.h"
7#include "GPSSourceHealth.h"
8#include "MAVLinkLib.h"
9#include "MonotonicClock.h"
10#include "MultiVehicleManager.h"
11#include "NTRIPGgaReporter.h"
12#include "NTRIPManager.h"
13#include "RuntimeScheduler.h"
14#include "Vehicle.h"
15#include "VehicleGPSFactGroup.h"
16#include "VehicleLinkManager.h"
17
18namespace {
19
20bool activeVehicleConnected()
21{
22 auto* manager = MultiVehicleManager::instance();
23 Vehicle* const vehicle = manager ? manager->activeVehicle() : nullptr;
24 return vehicle && !vehicle->isOfflineEditingVehicle() && vehicle->vehicleLinkManager() &&
26}
27
29{
30 using Quality = GPSObservation::FixQuality;
31 switch (fixType) {
32 case GPS_FIX_TYPE_2D_FIX:
33 return Quality::Fix2D;
34 case GPS_FIX_TYPE_3D_FIX:
35 case GPS_FIX_TYPE_STATIC:
36 return Quality::Fix3D;
37 case GPS_FIX_TYPE_DGPS:
38 case GPS_FIX_TYPE_PPP:
39 return Quality::Differential;
40 case GPS_FIX_TYPE_RTK_FLOAT:
41 return Quality::RTKFloat;
42 case GPS_FIX_TYPE_RTK_FIXED:
43 return Quality::RTKFixed;
44 default:
45 return Quality::NoFix;
46 }
47}
48
49GPSObservation vehicleObservation(const QGeoPositionInfo& position, GPSObservation::FixQuality quality,
50 quint64 receivedAtUs)
51{
52 GPSObservation observation;
53 observation.position = position;
54 observation.monotonicTimestampUs = receivedAtUs;
56 observation.fixQuality = quality;
57 return observation;
58}
59
60} // namespace
61
63 : QObject(parent)
64 , _scheduler(scheduler)
65{}
66
68{
70 using Observation = std::optional<GPSObservation>;
71 // The tracked reports are the active vehicle's; the gate still requires its link.
72 const auto gated = [source = QPointer(this)](Observation (NTRIPVehicleGgaSource::*observe)() const) {
73 return [source, observe]() -> Observation {
74 if (!source || !activeVehicleConnected()) {
75 return std::nullopt;
76 }
77 return (source->*observe)();
78 };
79 };
80 ntrip->setGgaPositionProvider(Source::VehicleGPS, gated(&NTRIPVehicleGgaSource::gpsObservation));
82
83 if (auto* vehicles = MultiVehicleManager::instance()) {
85 setVehicle(vehicles->activeVehicle());
86 }
87}
88
90{
91 QObject::disconnect(_gpsConnection);
92 QObject::disconnect(_messageConnection);
93 _gps.reset();
94 _estimate.reset();
95 if (!vehicle) {
96 return;
97 }
98 if (auto* gps = vehicle->gpsFactGroup()) {
99 _gpsConnection = connect(gps, &VehicleGPSFactGroup::positionReported, this,
100 [this, gps](const QGeoPositionInfo& position, int fixType) {
101 _gps = GpsReport{.position = position,
102 .fixType = fixType,
103 .horizontalDop = gps->hdop()->rawValue().toDouble(),
104 .receivedAtUs = _scheduler->nowUs()};
105 });
106 }
107 _messageConnection =
108 connect(vehicle, &Vehicle::mavlinkMessageReceived, this, [this](const mavlink_message_t& message) {
109 if (message.msgid != MAVLINK_MSG_ID_GLOBAL_POSITION_INT) {
110 return;
111 }
112 mavlink_global_position_int_t position;
113 mavlink_msg_global_position_int_decode(&message, &position);
114 // ArduPilot reports 0/0 without a position, to carry the relative altitude.
115 if (position.lat == 0 && position.lon == 0) {
116 _estimate.reset();
117 return;
118 }
119 _estimate =
120 EstimateReport{.coordinate = QGeoCoordinate(GPSProtocolMath::degreesFromE7(position.lat),
121 GPSProtocolMath::degreesFromE7(position.lon),
123 .receivedAtUs = _scheduler->nowUs()};
124 });
125}
126
127bool NTRIPVehicleGgaSource::_fresh(quint64 receivedAtUs) const
128{
129 return MonotonicClock::fresh(receivedAtUs, _scheduler->nowUs(), GPSSourceHealth::FRESHNESS_TIMEOUT);
130}
131
132std::optional<GPSObservation> NTRIPVehicleGgaSource::gpsObservation() const
133{
134 if (!_gps || !_fresh(_gps->receivedAtUs)) {
135 return std::nullopt;
136 }
137 GPSObservation observation = vehicleObservation(_gps->position, fixQuality(_gps->fixType), _gps->receivedAtUs);
138 observation.receiverFixValid = observation.fixQuality != GPSObservation::FixQuality::NoFix;
139 if (qIsFinite(_gps->horizontalDop)) {
140 observation.horizontalDop = _gps->horizontalDop;
141 }
143}
144
145std::optional<GPSObservation> NTRIPVehicleGgaSource::estimateObservation() const
146{
147 if (!_estimate || !_fresh(_estimate->receivedAtUs)) {
148 return std::nullopt;
149 }
150 // GLOBAL_POSITION_INT carries no fix time, so the observation is stamped when it is built.
151 return vehicleObservation(QGeoPositionInfo(_estimate->coordinate, QDateTime::currentDateTimeUtc()),
152 GPSObservation::FixQuality::Extrapolated, _estimate->receivedAtUs)
154}
struct __mavlink_message mavlink_message_t
static constexpr std::chrono::milliseconds FRESHNESS_TIMEOUT
Default position age at which health becomes Stale and the position stops being usable.
static MultiVehicleManager * instance()
void activeVehicleChanged(Vehicle *activeVehicle)
void setGgaPositionProvider(NTRIPGgaReporter::PositionSource source, NTRIPGgaReporter::PositionProvider provider)
std::optional< GPSObservation > estimateObservation() const
The fresh observation from the vehicle's GLOBAL_POSITION_INT estimate.
std::optional< GPSObservation > gpsObservation() const
The fresh observation from the vehicle's GPS with a fix.
NTRIPVehicleGgaSource(RuntimeScheduler *scheduler, QObject *parent=nullptr)
scheduler stamps receipt times and must outlive this source.
void setVehicle(Vehicle *vehicle)
Tracks vehicle's reports; reports from before this call are not used.
void attach(NTRIPManager *ntrip)
virtual quint64 nowUs() const =0
void positionReported(const QGeoPositionInfo &position, int fixType)
bool communicationLost() const
VehicleLinkManager * vehicleLinkManager()
Definition Vehicle.h:597
VehicleGPSFactGroup * gpsFactGroup()
Definition Vehicle.cc:410
bool isOfflineEditingVehicle() const
Definition Vehicle.h:532
void mavlinkMessageReceived(const mavlink_message_t &message)
GPSPositionReport position(const GPSDecodedPosition &source, const GPSIntegrityReport &diagnostic, uint64_t nowUs)
constexpr double metersFromMillimeters(int32_t value)
constexpr double degreesFromE7(int32_t value)
Degrees of a coordinate in 1e-7 degree units, as u-blox and MAVLink send them.
constexpr bool fresh(uint64_t timestampUs, uint64_t nowUs, std::chrono::microseconds lifetime)
Whether a receipt is younger than lifetime.
GPSFixQuality fixQuality(unsigned quality, GPSFixQuality autonomous)
Autonomous GGA does not distinguish 2D/3D; the caller supplies its independently resolved quality.
Receiver-independent data. Unknown metadata remains absent, never a manufactured zero.
GPSFixQuality FixQuality
FixQuality fixQuality
QGeoPositionInfo position
std::optional< GPSObservation > projected(PositionUse use) const
The owner separately enforces freshness and session authorization.
quint64 monotonicTimestampUs
GPSAltitudeDatum altitudeDatum
std::optional< bool > receiverFixValid
std::optional< double > horizontalDop