QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
FollowMe.cc
Go to the documentation of this file.
1#include "FollowMe.h"
2
3#include <QtPositioning/QGeoPositionInfo>
4
5#include "AppSettings.h"
6#include "FirmwarePlugin.h"
7#include "GPSManager.h"
9#include "PositionManager.h"
10#include "QGCLoggingCategory.h"
11#include "QmlObjectListModel.h"
12#include "SettingsManager.h"
13#include "Vehicle.h"
14
15QGC_LOGGING_CATEGORY(FollowMeLog, "API.FollowMe")
16
17Q_APPLICATION_STATIC(FollowMe, _followMeInstance);
18
19FollowMe::FollowMe(QObject *parent)
20 : QObject(parent)
21 , _gcsMotionReportTimer(new QTimer(this))
22{
23 // qCDebug(FollowMeLog) << Q_FUNC_INFO << this;
24
25 _gcsMotionReportTimer->setSingleShot(false);
26 // We set the update interval to a fixed amount of time.
27 // Even if the device can't update this quickly we'll pick up a new value on the next time around.
28 // We can't trust the value for update interval which comes from the actual device.
29 _gcsMotionReportTimer->setInterval(kMotionUpdateInterval);
30}
31
33{
34 // qCDebug(FollowMeLog) << Q_FUNC_INFO << this;
35}
36
38{
39 return _followMeInstance();
40}
41
43{
44 static bool once = false;
45 if (!once) {
46 (void) connect(_gcsMotionReportTimer, &QTimer::timeout, this, &FollowMe::_sendGCSMotionReport);
47 (void) connect(SettingsManager::instance()->appSettings()->followTarget(), &Fact::rawValueChanged, this, &FollowMe::_settingsChanged);
48
49 _settingsChanged(SettingsManager::instance()->appSettings()->followTarget()->rawValue());
50 }
51 once = true;
52}
53
54void FollowMe::_settingsChanged(QVariant value)
55{
56 _currentMode = static_cast<FollowMode>(value.toUInt());
57
58 switch (_currentMode) {
59 case MODE_NEVER:
60 (void) disconnect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleAdded, this, &FollowMe::_vehicleAdded);
61 (void) disconnect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleRemoved, this, &FollowMe::_vehicleRemoved);
62 _disableFollowSend();
63 break;
64 case MODE_ALWAYS:
65 (void) connect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleAdded, this, &FollowMe::_vehicleAdded);
66 (void) connect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleRemoved, this, &FollowMe::_vehicleRemoved);
67 _enableFollowSend();
68 break;
69 case MODE_FOLLOWME:
70 (void) connect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleAdded, this, &FollowMe::_vehicleAdded);
71 (void) connect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleRemoved, this, &FollowMe::_vehicleRemoved);
72 _enableIfVehicleInFollow();
73 break;
74 }
75}
76
77void FollowMe::_enableFollowSend()
78{
79 if (!_gcsMotionReportTimer->isActive()) {
80 _gcsMotionReportTimer->start();
81 }
82}
83
84void FollowMe::_disableFollowSend()
85{
86 if (_gcsMotionReportTimer->isActive()) {
87 _gcsMotionReportTimer->stop();
88 }
89}
90
91void FollowMe::_sendGCSMotionReport()
92{
93 const auto observation =
95 if (!observation) {
96 return;
97 }
98 const auto& geoPositionInfo = observation->position;
99 const QGeoCoordinate gcsCoordinate = geoPositionInfo.coordinate();
100
101 // First check to see if any vehicles need follow me updates
102 bool needFollowMe = false;
103 if (_currentMode == MODE_ALWAYS) {
104 needFollowMe = true;
105 } else if (_currentMode == MODE_FOLLOWME) {
107 for (int i = 0; i < vehicles->count(); i++) {
108 const Vehicle* const vehicle = vehicles->value<const Vehicle*>(i);
109 if (vehicle && _isFollowFlightMode(vehicle, vehicle->flightMode())) {
110 needFollowMe = true;
111 }
112 }
113 }
114 if (!needFollowMe) {
115 return;
116 }
117
118 GCSMotionReport motionReport{};
119 uint8_t estimationCapabilities = 0;
120
121 motionReport.lat_int = static_cast<int>(gcsCoordinate.latitude() * 1e7);
122 motionReport.lon_int = static_cast<int>(gcsCoordinate.longitude() * 1e7);
123 motionReport.altMetersAMSL = gcsCoordinate.altitude();
124 estimationCapabilities |= (1 << POS);
125
126 if (geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction)) {
127 estimationCapabilities |= (1 << HEADING);
128 motionReport.headingDegrees = geoPositionInfo.attribute(QGeoPositionInfo::Direction);
129 }
130
131 if (geoPositionInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) {
132 motionReport.pos_std_dev[0] = motionReport.pos_std_dev[1] = geoPositionInfo.attribute(QGeoPositionInfo::HorizontalAccuracy);
133 }
134
135 if (geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) {
136 motionReport.pos_std_dev[2] = geoPositionInfo.attribute(QGeoPositionInfo::VerticalAccuracy);
137 }
138
139 if (geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalSpeed)) {
140 motionReport.vzMetersPerSec = geoPositionInfo.attribute(QGeoPositionInfo::VerticalSpeed);
141 }
142
143 if (geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction) && geoPositionInfo.hasAttribute(QGeoPositionInfo::GroundSpeed)) {
144 estimationCapabilities |= (1 << VEL);
145
146 const qreal direction = qDegreesToRadians(geoPositionInfo.attribute(QGeoPositionInfo::Direction));
147 const qreal velocity = geoPositionInfo.attribute(QGeoPositionInfo::GroundSpeed);
148
149 motionReport.vxMetersPerSec = cos(direction) * velocity;
150 motionReport.vyMetersPerSec = sin(direction) * velocity;
151 } else {
152 motionReport.vxMetersPerSec = 0;
153 motionReport.vyMetersPerSec = 0;
154 }
155
157
158 for (int i = 0; i < vehicles->count(); i++) {
159 Vehicle* const vehicle = vehicles->value<Vehicle*>(i);
160 if (vehicle && ((_currentMode == MODE_ALWAYS) || (_isFollowFlightMode(vehicle, vehicle->flightMode())))) {
161 qCDebug(FollowMeLog) << "sendGCSMotionReport latInt:lonInt:altMetersAMSL" << motionReport.lat_int << motionReport.lon_int << motionReport.altMetersAMSL;
162 vehicle->firmwarePlugin()->sendGCSMotionReport(vehicle, motionReport, estimationCapabilities);
163 }
164 }
165}
166
167void FollowMe::_vehicleAdded(Vehicle *vehicle)
168{
169 (void) connect(vehicle, &Vehicle::flightModeChanged, this, &FollowMe::_enableIfVehicleInFollow);
170 _enableIfVehicleInFollow();
171}
172
173void FollowMe::_vehicleRemoved(Vehicle *vehicle)
174{
175 (void) disconnect(vehicle, &Vehicle::flightModeChanged, this, &FollowMe::_enableIfVehicleInFollow);
176 _enableIfVehicleInFollow();
177}
178
179void FollowMe::_enableIfVehicleInFollow()
180{
181 if (_currentMode == MODE_ALWAYS) {
182 return;
183 }
184
185 // Any vehicle in follow mode will enable the system
187
188 for (int i = 0; i < vehicles->count(); i++) {
189 const Vehicle* const vehicle = vehicles->value<const Vehicle*>(i);
190 if (_isFollowFlightMode(vehicle, vehicle->flightMode())) {
191 _enableFollowSend();
192 return;
193 }
194 }
195
196 _disableFollowSend();
197}
198
199bool FollowMe::_isFollowFlightMode(const Vehicle *vehicle, const QString &flightMode)
200{
201 return (flightMode.compare(vehicle->followFlightMode()) == 0);
202}
Q_APPLICATION_STATIC(FollowMe, _followMeInstance)
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void rawValueChanged(const QVariant &value)
virtual void sendGCSMotionReport(Vehicle *vehicle, const FollowMe::GCSMotionReport &motionReport, uint8_t estimationCapabilities) const
Sends the appropriate mavlink message for follow me support.
static FollowMe * instance()
Definition FollowMe.cc:37
~FollowMe()
Definition FollowMe.cc:32
void init()
Definition FollowMe.cc:42
@ HEADING
Definition FollowMe.h:38
static GPSManager * instance()
Definition GPSManager.cc:67
PositionManager * positionManager() const
Definition GPSManager.h:56
static MultiVehicleManager * instance()
void vehicleAdded(Vehicle *vehicle)
QmlObjectListModel * vehicles() const
void vehicleRemoved(Vehicle *vehicle)
std::optional< GPSObservation > acceptedObservation(GPSObservation::PositionUse use=GPSObservation::PositionUse::GroundStation, std::optional< std::chrono::milliseconds > maximumAge=std::nullopt) const
T value(int index) const
int count() const override final
static SettingsManager * instance()
AppSettings * appSettings() const
QString flightMode() const
Definition Vehicle.cc:1485
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
Definition Vehicle.h:462
QString followFlightMode() const
Definition Vehicle.cc:2630
void flightModeChanged(const QString &flightMode)