QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
TerrainQueryCoordinator.cc
Go to the documentation of this file.
2
3#include <cmath>
4
5#include "AppMessages.h"
6#include "MAVLinkEnums.h"
8#include "TerrainQuery.h"
9#include "Vehicle.h"
10
11QGC_LOGGING_CATEGORY(TerrainQueryCoordinatorLog, "Vehicle.TerrainQueryCoordinator")
12
13namespace {
14// DO_SET_HOME sanity bounds for resolved terrain altitude (AMSL, meters).
15constexpr double kSetHomeTerrainAltMax = 10000.0;
16constexpr double kSetHomeTerrainAltMin = -500.0;
17
18// Altitude-above-terrain polling throttle.
19constexpr int kAltQueryMinIntervalMs = 500;
20constexpr qreal kAltMinDistanceTraveled = 2.0; // meters
21constexpr float kAltMinAltitudeChanged = 0.5f; // meters
22} // namespace
23
25 : QObject(vehicle)
26 , _vehicle(vehicle)
27{
28 _altQueryTimer.restart();
29}
30
31void TerrainQueryCoordinator::doSetHomeWithTerrain(const QGeoCoordinate& coord)
32{
33 if (!coord.isValid()) {
34 return;
35 }
36
37 // If a prior query is still in-flight, disconnect it and start a new one. TerrainQuery
38 // auto-deletes the old query; we just let it go. This matters when two doSetHome
39 // commands arrive back-to-back: only the most recent should drive the outbound command.
40 if (_doSetHomeQuery) {
41 disconnect(_doSetHomeQuery, &TerrainAtCoordinateQuery::terrainDataReceived,
42 this, &TerrainQueryCoordinator::_doSetHomeTerrainReceived);
43 _doSetHomeQuery = nullptr;
44 }
45
46 _doSetHomeCoordinate = coord;
47
48 _doSetHomeQuery = new TerrainAtCoordinateQuery(true /* autoDelete */);
49 connect(_doSetHomeQuery, &TerrainAtCoordinateQuery::terrainDataReceived,
50 this, &TerrainQueryCoordinator::_doSetHomeTerrainReceived);
51
52 QList<QGeoCoordinate> rgCoord;
53 rgCoord.append(coord);
54 _doSetHomeQuery->requestData(rgCoord);
55}
56
57void TerrainQueryCoordinator::_doSetHomeTerrainReceived(bool success, QList<double> heights)
58{
59 if (success) {
60 const double terrainAltitude = heights[0];
61 if (_doSetHomeCoordinate.isValid()
62 && terrainAltitude <= kSetHomeTerrainAltMax
63 && terrainAltitude >= kSetHomeTerrainAltMin) {
64 _vehicle->sendMavCommand(
65 _vehicle->defaultComponentId(),
66 MAV_CMD_DO_SET_HOME,
67 true, // show error if fails
68 0,
69 0,
70 0,
71 static_cast<float>(qQNaN()),
72 _doSetHomeCoordinate.latitude(),
73 _doSetHomeCoordinate.longitude(),
74 terrainAltitude);
75 } else if (_doSetHomeCoordinate.isValid()) {
76 qCDebug(TerrainQueryCoordinatorLog) << "_doSetHomeTerrainReceived: elevation data out of limits";
77 } else {
78 qCDebug(TerrainQueryCoordinatorLog) << "_doSetHomeTerrainReceived: cached home coordinate not valid";
79 }
80 } else {
81 QGC::showAppMessage(tr("Set Home failed, terrain data not available for selected coordinate"));
82 }
83
84 _doSetHomeQuery = nullptr;
85 _doSetHomeCoordinate = QGeoCoordinate(); // Invalidate for extra safety
86}
87
89{
90 // Throttle: no query sooner than 500 ms after the last one. Any requests that miss
91 // this window are fine — the next coordinateChanged will re-trigger us.
92 if (_altQueryTimer.elapsed() < kAltQueryMinIntervalMs) {
93 return;
94 }
95
96 const QGeoCoordinate currentCoord = _vehicle->coordinate();
97 if (!currentCoord.isValid()) {
98 return;
99 }
100
101 // Throttle: require minimum distance/altitude deltas to avoid pounding the
102 // terrain service with near-identical queries.
103 const float currentRelAlt = _vehicle->altitudeRelative()->rawValue().toFloat();
104 if (_altLastCoord.isValid() && !qIsNaN(_altLastRelAlt)) {
105 if (_altLastCoord.distanceTo(currentCoord) < kAltMinDistanceTraveled
106 && std::fabs(currentRelAlt - _altLastRelAlt) < kAltMinAltitudeChanged) {
107 return;
108 }
109 }
110
111 _altLastCoord = currentCoord;
112 _altLastRelAlt = currentRelAlt;
113
114 if (_altQuery) {
116 this, &TerrainQueryCoordinator::_altitudeAboveTerrainReceived);
117 _altQuery = nullptr;
118 }
119
120 _altQuery = new TerrainAtCoordinateQuery(true /* autoDelete */);
122 this, &TerrainQueryCoordinator::_altitudeAboveTerrainReceived);
123
124 QList<QGeoCoordinate> rgCoord;
125 rgCoord.append(currentCoord);
126 _altQuery->requestData(rgCoord);
127 _altQueryTimer.restart();
128}
129
130void TerrainQueryCoordinator::_altitudeAboveTerrainReceived(bool success, QList<double> heights)
131{
132 if (!success) {
133 qCDebug(TerrainQueryCoordinatorLog) << "_altitudeAboveTerrainReceived: terrain data not available";
134 } else {
135 const double terrainAltitude = heights[0];
136 const double altitudeAboveTerrain = _vehicle->altitudeAMSL()->rawValue().toDouble() - terrainAltitude;
137 _vehicle->altitudeAboveTerr()->setRawValue(altitudeAboveTerrain);
138 }
139
140 _altQuery = nullptr;
141}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void setRawValue(const QVariant &value)
Definition Fact.cc:135
QVariant rawValue() const
Definition Fact.h:87
NOTE: TerrainAtCoordinateQuery is not thread safe. All instances/calls to ElevationProvider must be o...
void terrainDataReceived(bool success, const QList< double > &heights)
void doSetHomeWithTerrain(const QGeoCoordinate &coord)
TerrainQueryCoordinator(Vehicle *vehicle)
void sendMavCommand(int compId, MAV_CMD command, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
Definition Vehicle.cc:2173
int defaultComponentId() const
Definition Vehicle.h:700
QGeoCoordinate coordinate()
Definition Vehicle.h:427
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Definition AppMessages.cc:9