QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
PositionManager.cpp
Go to the documentation of this file.
1#include "PositionManager.h"
2#include "AppMessages.h"
3#include "QGCCorePlugin.h"
4#include "SimulatedPosition.h"
5// #include "QGCSensors.h"
7
8#include <QtCore/QApplicationStatic>
9#include <QtCore/QPermissions>
10#include <QtPositioning/QNmeaPositionInfoSource>
11
12QGC_LOGGING_CATEGORY(QGCPositionManagerLog, "PositionManager.QGCPositionManager")
13
15
17 : QObject(parent)
18{
19 qCDebug(QGCPositionManagerLog) << this;
20}
21
23{
24 qCDebug(QGCPositionManagerLog) << this;
25}
26
28{
29 return _positionManager();
30}
31
33{
35 _simulatedSource = new SimulatedPosition(this);
36 _setPositionSource(QGCPositionSource::Simulated);
37 } else {
38 _checkPermission();
39 }
40}
41
42void QGCPositionManager::_setupPositionSources()
43{
44 _defaultSource = QGCCorePlugin::instance()->createPositionSource(this);
45 if (_defaultSource) {
46 _usingPluginSource = true;
47 } else {
48 qCDebug(QGCPositionManagerLog) << Q_FUNC_INFO << QGeoPositionInfoSource::availableSources();
49
50 _defaultSource = QGeoPositionInfoSource::createDefaultSource(this);
51 if (!_defaultSource) {
52 qCWarning(QGCPositionManagerLog) << Q_FUNC_INFO << "No default source available";
53 return;
54 }
55 }
56
57 _setPositionSource(QGCPositionSource::InternalGPS);
58}
59
60void QGCPositionManager::_handlePermissionStatus(Qt::PermissionStatus permissionStatus)
61{
62 if (permissionStatus == Qt::PermissionStatus::Granted) {
63 _setupPositionSources();
64 } else {
65 qCWarning(QGCPositionManagerLog) << Q_FUNC_INFO << "Location Permission Denied";
66 }
67}
68
69void QGCPositionManager::_checkPermission()
70{
71 QLocationPermission locationPermission;
72 locationPermission.setAccuracy(QLocationPermission::Precise);
73
74 const Qt::PermissionStatus permissionStatus = QCoreApplication::instance()->checkPermission(locationPermission);
75 if (permissionStatus == Qt::PermissionStatus::Undetermined) {
76 QCoreApplication::instance()->requestPermission(locationPermission, this, [this](const QPermission &permission) {
77 _handlePermissionStatus(permission.status());
78 });
79 } else {
80 _handlePermissionStatus(permissionStatus);
81 }
82}
83
85{
86 if (_nmeaSource) {
87 _nmeaSource->stopUpdates();
88 (void) disconnect(_nmeaSource);
89
90 if (_currentSource == _nmeaSource) {
91 _currentSource = nullptr;
92 }
93
94 delete _nmeaSource;
95 _nmeaSource = nullptr;
96 }
97
98 _nmeaSource = new QNmeaPositionInfoSource(QNmeaPositionInfoSource::RealTimeMode, this);
99 _nmeaSource->setDevice(device);
100 _nmeaSource->setUserEquivalentRangeError(5.1);
101 _setPositionSource(QGCPositionManager::NmeaGPS);
102}
103
104void QGCPositionManager::_positionUpdated(const QGeoPositionInfo &update)
105{
106 _geoPositionInfo = update;
107 _gcsPositioningError = QGeoPositionInfoSource::NoError;
108
109 QGeoCoordinate newGCSPosition(_gcsPosition);
110
111 if (update.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) {
112 if ((qAbs(update.coordinate().latitude()) > 0.001) && (qAbs(update.coordinate().longitude()) > 0.001)) {
113 _gcsPositionHorizontalAccuracy = update.attribute(QGeoPositionInfo::HorizontalAccuracy);
114 if (_gcsPositionHorizontalAccuracy <= kMinHorizonalAccuracyMeters) {
115 newGCSPosition.setLatitude(update.coordinate().latitude());
116 newGCSPosition.setLongitude(update.coordinate().longitude());
117 }
118 emit gcsPositionHorizontalAccuracyChanged(_gcsPositionHorizontalAccuracy);
119 }
120 }
121
122 if (update.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) {
123 _gcsPositionVerticalAccuracy = update.attribute(QGeoPositionInfo::VerticalAccuracy);
124 if (_gcsPositionVerticalAccuracy <= kMinVerticalAccuracyMeters) {
125 newGCSPosition.setAltitude(update.coordinate().altitude());
126 }
127 }
128
129 _gcsPositionAccuracy = sqrt(pow(_gcsPositionHorizontalAccuracy, 2) + pow(_gcsPositionVerticalAccuracy, 2));
130
131 _setGCSPosition(newGCSPosition);
132
133 if (update.hasAttribute(QGeoPositionInfo::DirectionAccuracy)) {
134 _gcsDirectionAccuracy = update.attribute(QGeoPositionInfo::DirectionAccuracy);
135 if (_gcsDirectionAccuracy <= kMinDirectionAccuracyDegrees) {
136 _setGCSHeading(update.attribute(QGeoPositionInfo::Direction));
137 }
138 } else if (_usingPluginSource) {
139 _setGCSHeading(update.attribute(QGeoPositionInfo::Direction));
140 }
141
142 emit positionInfoUpdated(update);
143}
144
145void QGCPositionManager::_positionError(QGeoPositionInfoSource::Error gcsPositioningError)
146{
147 qCWarning(QGCPositionManagerLog) << Q_FUNC_INFO << "Positioning error:" << gcsPositioningError;
148 _gcsPositioningError = gcsPositioningError;
149}
150
151void QGCPositionManager::_setGCSHeading(qreal newGCSHeading)
152{
153 if (newGCSHeading != _gcsHeading) {
154 _gcsHeading = newGCSHeading;
155 emit gcsHeadingChanged(_gcsHeading);
156 }
157}
158
159void QGCPositionManager::_setGCSPosition(const QGeoCoordinate& newGCSPosition)
160{
161 if (newGCSPosition != _gcsPosition) {
162 _gcsPosition = newGCSPosition;
163 emit gcsPositionChanged(_gcsPosition);
164 }
165}
166
167void QGCPositionManager::_setPositionSource(QGCPositionSource source)
168{
169 if (_currentSource != nullptr) {
170 _currentSource->stopUpdates();
171 (void) disconnect(_currentSource);
172
173 _geoPositionInfo = QGeoPositionInfo();
174 emit positionInfoUpdated(_geoPositionInfo);
175
176 _setGCSPosition(QGeoCoordinate());
177
178 _setGCSHeading(qQNaN());
179
180 _gcsPositionHorizontalAccuracy = std::numeric_limits<qreal>::infinity();
181 emit gcsPositionHorizontalAccuracyChanged(_gcsPositionHorizontalAccuracy);
182 }
183
184 switch (source) {
185 case QGCPositionManager::Log:
186 break;
187 case QGCPositionManager::Simulated:
188 _currentSource = _simulatedSource;
189 break;
190 case QGCPositionManager::NmeaGPS:
191 _currentSource = _nmeaSource;
192 break;
193 case QGCPositionManager::InternalGPS:
194 _currentSource = _defaultSource;
195 break;
196 case QGCPositionManager::ExternalGPS:
197 break;
198 default:
199 _currentSource = _defaultSource;
200 break;
201 }
202
203 if (_currentSource != nullptr) {
204 _currentSource->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
205 _updateInterval = _currentSource->minimumUpdateInterval();
206 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_IOS)
207 _currentSource->setUpdateInterval(_updateInterval);
208 #endif
209
210 (void) connect(_currentSource, &QGeoPositionInfoSource::positionUpdated, this, &QGCPositionManager::_positionUpdated);
211 (void) connect(_currentSource, &QGeoPositionInfoSource::errorOccurred, this, &QGCPositionManager::_positionError);
212
213 // (void) connect(QGCCompass::instance(), &QGCCompass::positionUpdated, this, &QGCPositionManager::_positionUpdated);
214
215 _currentSource->startUpdates();
216 }
217}
Q_APPLICATION_STATIC(QGCPositionManager, _positionManager)
#define QGC_LOGGING_CATEGORY(name, categoryStr)
virtual QGeoPositionInfoSource * createPositionSource(QObject *parent)
static QGCCorePlugin * instance()
static QGCPositionManager * instance()
void gcsPositionChanged(QGeoCoordinate gcsPosition)
QGeoPositionInfoSource::Error gcsPositioningError() const
void setNmeaSourceDevice(QIODevice *device)
void gcsPositionHorizontalAccuracyChanged(qreal gcsPositionHorizontalAccuracy)
void positionInfoUpdated(QGeoPositionInfo update)
void gcsHeadingChanged(qreal gcsHeading)
bool runningUnitTests()