QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
Vehicle.cc
Go to the documentation of this file.
1#include "Vehicle.h"
2
4#include "APM.h"
5#include "Actuators.h"
6#include "AppMessages.h"
7#include "AppSettings.h"
8#include "AudioOutput.h"
9#include "AutoPilotPlugin.h"
13#include "FTPManager.h"
14#include "FirmwarePlugin.h"
16#include "FlyViewSettings.h"
17#include "GPSManager.h"
18#include "GeoFenceManager.h"
19#include "GimbalController.h"
22#include "Joystick.h"
23#include "JoystickManager.h"
24#include "LinkManager.h"
25#include "MAVLinkEventManager.h"
26#include "MAVLinkLogManager.h"
27#include "MAVLinkProtocol.h"
28#include "MAVLinkStreamConfig.h"
29#include "MavCommandQueue.h"
30#include "MavlinkSettings.h"
32#include "MissionCommandTree.h"
33#include "MissionManager.h"
34#include "MultiVehicleManager.h"
35#include "ParameterManager.h"
37#include "PositionManager.h"
38#include "QGCApplication.h"
39#include "QGCCameraManager.h"
40#include "QGCCorePlugin.h"
41#include "QGCImageProvider.h"
42#include "QGCLoggingCategory.h"
43#include "QGCMapCircle.h"
44#include "QGCMath.h"
45#include "QGCQGeoCoordinate.h"
46#include "QGCSensors.h"
47#include "QmlObjectListModel.h"
49#include "RallyPointManager.h"
50#include "RemoteIDManager.h"
52#include "SettingsManager.h"
53#include "StandardModes.h"
54#include "StatusTextHandler.h"
55#include "SysStatusSensorInfo.h"
56#include "TerrainFactGroup.h"
58#include "TerrainQuery.h"
60#include "TrajectoryPoints.h"
63#include "VehicleEFIFactGroup.h"
65#include "VehicleGPSFactGroup.h"
68#include "VehicleLinkManager.h"
72#include "VehicleRPMFactGroup.h"
75#include "VehicleSupports.h"
79#include "VideoManager.h"
80#include "VideoSettings.h"
81
82#ifdef QT_DEBUG
83#include "MockLink.h"
84#endif
85
86#include <QtCore/QDateTime>
87#include <QtCore/QSettings>
88
89QGC_LOGGING_CATEGORY(VehicleLog, "Vehicle.Vehicle")
90
91#define UPDATE_TIMER 50
92#define DEFAULT_LAT 38.965767f
93#define DEFAULT_LON -120.083923f
94
95// After a second GCS has requested control and we have given it permission to takeover, we will remove takeover permission automatically after this timeout
96// If the second GCS didn't get control
97#define REQUEST_OPERATOR_CONTROL_ALLOW_TAKEOVER_TIMEOUT_MSECS 10000
98
99const QString guided_mode_not_supported_by_vehicle = QObject::tr("Guided mode not supported by Vehicle.");
100
101// Standard connected vehicle
103 int vehicleId,
104 int defaultComponentId,
105 MAV_AUTOPILOT firmwareType,
106 MAV_TYPE vehicleType,
107 QObject* parent)
108 : VehicleFactGroup (parent)
109 , _systemID (vehicleId)
110 , _defaultComponentId (defaultComponentId)
111 , _firmwareType (firmwareType)
112 , _vehicleType (vehicleType)
113 , _defaultCruiseSpeed (SettingsManager::instance()->appSettings()->offlineEditingCruiseSpeed()->rawValue().toDouble())
114 , _defaultHoverSpeed (SettingsManager::instance()->appSettings()->offlineEditingHoverSpeed()->rawValue().toDouble())
115 , _sysStatusSensorInfo (std::make_unique<SysStatusSensorInfo>(this))
116 , _trajectoryPoints (new TrajectoryPoints(this, this))
117 , _cameraTriggerPoints (std::make_unique<QmlObjectListModel>(this))
118 , _orbitMapCircle (std::make_unique<QGCMapCircle>(this))
119 , _mavlinkStreamConfig (std::make_unique<MAVLinkStreamConfig>(std::bind(&Vehicle::_setMessageInterval, this, std::placeholders::_1, std::placeholders::_2)))
120 , _vehicleFactGroup (this)
121{
122 connect(MultiVehicleManager::instance(), &MultiVehicleManager::activeVehicleChanged, this, &Vehicle::_activeVehicleChanged);
123
124 connect(MAVLinkProtocol::instance(), &MAVLinkProtocol::messageReceived, this, &Vehicle::_mavlinkMessageReceived);
125 connect(MAVLinkProtocol::instance(), &MAVLinkProtocol::mavlinkMessageStatus, this, &Vehicle::_mavlinkMessageStatus);
126
127 connect(this, &Vehicle::flightModeChanged, this, &Vehicle::_handleFlightModeChanged);
128 connect(this, &Vehicle::armedChanged, this, &Vehicle::_announceArmedChanged);
129 connect(this, &Vehicle::airborneChanged, this, [this](bool airborne) {
130 if (airborne) {
133 }
134 });
135
137
138 _commonInit(link);
139
140 // Set video stream to udp if running ArduSub and Video is disabled
141 if (sub() && SettingsManager::instance()->videoSettings()->videoSource()->rawValue() == VideoSettings::videoDisabled) {
143 SettingsManager::instance()->videoSettings()->lowLatencyMode()->setRawValue(true);
144 }
145
146 _autopilotPlugin = _firmwarePlugin->autopilotPlugin(this);
147 _autopilotPlugin->setParent(this);
148
149 // PreArm Error self-destruct timer
150 connect(&_prearmErrorTimer, &QTimer::timeout, this, &Vehicle::_prearmErrorTimeout);
151 _prearmErrorTimer.setInterval(_prearmErrorTimeoutMSecs);
152 _prearmErrorTimer.setSingleShot(true);
153
154 // Command queue timer is managed by MavCommandQueue itself.
155
156 // MAV_TYPE_GENERIC is used by unit test for creating a vehicle which doesn't do the connect sequence. This
157 // way we can test the methods that are used within the connect sequence.
158 if (!QGC::runningUnitTests() || _vehicleType != MAV_TYPE_GENERIC) {
160 }
161
162 _firmwarePlugin->initializeVehicle(this);
163 for(auto& factName: factNames()) {
164 _firmwarePlugin->adjustMetaData(vehicleType, getFact(factName)->metaData());
165 }
166
167 _sendMultipleTimer.start(_sendMessageMultipleIntraMessageDelay);
168 connect(&_sendMultipleTimer, &QTimer::timeout, this, &Vehicle::_sendMessageMultipleNext);
169
170 connect(&_orbitTelemetryTimer, &QTimer::timeout, this, &Vehicle::_orbitTelemetryTimeout);
171
172 // Start csv logger
173 connect(&_csvLogTimer, &QTimer::timeout, this, &Vehicle::_writeCsvLine);
174 _csvLogTimer.start(1000);
175
176}
177
178// Disconnected Vehicle for offline editing
179Vehicle::Vehicle(MAV_AUTOPILOT firmwareType,
180 MAV_TYPE vehicleType,
181 QObject* parent)
182 : VehicleFactGroup (parent)
183 , _systemID (0)
184 , _defaultComponentId (MAV_COMP_ID_ALL)
185 , _offlineEditingVehicle (true)
186 , _firmwareType (firmwareType)
187 , _vehicleType (vehicleType)
188 , _defaultCruiseSpeed (SettingsManager::instance()->appSettings()->offlineEditingCruiseSpeed()->rawValue().toDouble())
189 , _defaultHoverSpeed (SettingsManager::instance()->appSettings()->offlineEditingHoverSpeed()->rawValue().toDouble())
190 , _capabilityBitsKnown (true)
191 , _capabilityBits (MAV_PROTOCOL_CAPABILITY_MISSION_FENCE | MAV_PROTOCOL_CAPABILITY_MISSION_RALLY)
192 , _sysStatusSensorInfo (std::make_unique<SysStatusSensorInfo>(this))
193 , _trajectoryPoints (new TrajectoryPoints(this, this))
194 , _cameraTriggerPoints (std::make_unique<QmlObjectListModel>(this))
195 , _orbitMapCircle (std::make_unique<QGCMapCircle>(this))
196 , _mavlinkStreamConfig (std::make_unique<MAVLinkStreamConfig>(std::bind(&Vehicle::_setMessageInterval, this, std::placeholders::_1, std::placeholders::_2)))
197 , _vehicleFactGroup (this)
198{
199 // This will also set the settings based firmware/vehicle types. So it needs to happen first.
200 if (_firmwareType == MAV_AUTOPILOT_TRACK) {
202 }
203
204 _commonInit(nullptr /* link */);
205
206 connect(SettingsManager::instance()->appSettings()->offlineEditingCruiseSpeed(), &Fact::rawValueChanged, this, &Vehicle::_offlineCruiseSpeedSettingChanged);
207 connect(SettingsManager::instance()->appSettings()->offlineEditingHoverSpeed(), &Fact::rawValueChanged, this, &Vehicle::_offlineHoverSpeedSettingChanged);
208
209 _offlineFirmwareTypeSettingChanged(_firmwareType); // This adds correct terrain capability bit
210 _firmwarePlugin->initializeVehicle(this);
211}
212
214{
215 connect(SettingsManager::instance()->appSettings()->offlineEditingFirmwareClass(), &Fact::rawValueChanged, this, &Vehicle::_offlineFirmwareTypeSettingChanged);
216 connect(SettingsManager::instance()->appSettings()->offlineEditingVehicleClass(), &Fact::rawValueChanged, this, &Vehicle::_offlineVehicleTypeSettingChanged);
217
218 _offlineFirmwareTypeSettingChanged(SettingsManager::instance()->appSettings()->offlineEditingFirmwareClass()->rawValue());
219 _offlineVehicleTypeSettingChanged(SettingsManager::instance()->appSettings()->offlineEditingVehicleClass()->rawValue());
220}
221
223{
224 disconnect(SettingsManager::instance()->appSettings()->offlineEditingFirmwareClass(), &Fact::rawValueChanged, this, &Vehicle::_offlineFirmwareTypeSettingChanged);
225 disconnect(SettingsManager::instance()->appSettings()->offlineEditingVehicleClass(), &Fact::rawValueChanged, this, &Vehicle::_offlineVehicleTypeSettingChanged);
226}
227
228void Vehicle::_commonInit(LinkInterface* link)
229{
230 _firmwarePlugin = FirmwarePluginManager::instance()->firmwarePluginForAutopilot(_firmwareType, _vehicleType);
231
233
234 connect(this, &Vehicle::coordinateChanged, this, &Vehicle::_updateDistanceHeadingHome);
235 connect(this, &Vehicle::coordinateChanged, this, &Vehicle::_updateDistanceHeadingGCS);
236 connect(this, &Vehicle::homePositionChanged, this, &Vehicle::_updateDistanceHeadingHome);
237 connect(this, &Vehicle::hobbsMeterChanged, this, &Vehicle::_updateHobbsMeter);
239 connect(this, &Vehicle::vehicleTypeChanged, this, &Vehicle::_updateAirborne);
241
242 PositionManager* const positionManager = GPSManager::instance()->positionManager();
243 connect(positionManager, &PositionManager::gcsPositionChanged, this, &Vehicle::_updateDistanceHeadingGCS);
244 connect(positionManager, &PositionManager::gcsPositionChanged, this, &Vehicle::_updateHomepoint);
245
247 connect(_missionManager, &MissionManager::error, this, &Vehicle::_missionManagerError);
248 connect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_firstMissionLoadComplete);
249 connect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_clearCameraTriggerPoints);
250 connect(_missionManager, &MissionManager::sendComplete, this, &Vehicle::_clearCameraTriggerPoints);
251 connect(_missionManager, &MissionManager::currentIndexChanged, this, &Vehicle::_updateHeadingToNextWP);
252 connect(_missionManager, &MissionManager::currentIndexChanged, this, &Vehicle::_updateMissionItemIndex);
253
256
257 _standardModes = new StandardModes (this, this);
258 _componentInformationManager = new ComponentInformationManager (this, this);
260 _ftpManager = new FTPManager (this);
261
262 // Command send/ack queue and request-message coordinator must exist before any
263 // manager that may call Vehicle::sendMavCommand / requestMessage during construction
264 // (e.g. VehicleLinkManager::_addLink() → _updatePrimaryLink → sendMavCommand).
265 _mavCmdQueue = new MavCommandQueue(this);
266 connect(_mavCmdQueue, &MavCommandQueue::commandResult, this, &Vehicle::mavCommandResult);
267 _reqMsgCoord = new RequestMessageCoordinator(this, _mavCmdQueue);
268 _messageIntervalManager = new MessageIntervalManager(this, _mavCmdQueue, _reqMsgCoord);
269 connect(_messageIntervalManager, &MessageIntervalManager::mavlinkMsgIntervalsChanged,
273
275 if (link) {
276 _vehicleLinkManager->_addLink(link);
277 }
278
280 // Re-emit flightModeChanged after available modes mapping updates so UI refreshes
281 // the human-readable mode name even if HEARTBEAT arrived earlier.
282 connect(_standardModes, &StandardModes::modesUpdated, this, [this]() {
284 });
285
286 _parameterManager = new ParameterManager(this);
287 connect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady);
288 connect(_parameterManager, &ParameterManager::parametersReadyChanged, this, [this](bool) {
289 emit hasGripperChanged();
290 });
292 this, &Vehicle::_gotProgressUpdate);
293 connect(_parameterManager, &ParameterManager::loadProgressChanged, this, &Vehicle::_gotProgressUpdate);
294
295 _objectAvoidance = new VehicleObjectAvoidance(this, this);
296
297 _autotune = _firmwarePlugin->createAutotune(this);
298
299 // GeoFenceManager needs to access ParameterManager so make sure to create after
301 connect(_geoFenceManager, &GeoFenceManager::error, this, &Vehicle::_geoFenceManagerError);
302 connect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &Vehicle::_firstGeoFenceLoadComplete);
303
305 connect(_rallyPointManager, &RallyPointManager::error, this, &Vehicle::_rallyPointManagerError);
306 connect(_rallyPointManager, &RallyPointManager::loadComplete, this, &Vehicle::_firstRallyPointLoadComplete);
307
308 // Remote ID manager might want to acces parameters so make sure to create it after
310
311 // Flight modes can differ based on advanced mode
313
333
334 if (!_offlineEditingVehicle) {
336 }
337
338 _createImageProtocolManager();
339 _createStatusTextHandler();
340 _createMAVLinkLogManager();
341 _createSigningController();
342 _createMAVLinkEventManager();
343
344 // _addFactGroup(_vehicleFactGroup, _vehicleFactGroupName);
362
363 // Add firmware-specific fact groups, if provided
364 QMap<QString, FactGroup*>* fwFactGroups = _firmwarePlugin->factGroups();
365 if (fwFactGroups) {
366 for (auto it = fwFactGroups->keyValueBegin(); it != fwFactGroups->keyValueEnd(); ++it) {
367 _addFactGroup(it->second, it->first);
368 }
369 }
370
371 _flightTimeUpdater.setInterval(1000);
372 _flightTimeUpdater.setSingleShot(false);
373 connect(&_flightTimeUpdater, &QTimer::timeout, this, &Vehicle::_updateFlightTime);
374
375 // Set video stream to udp if running ArduSub and Video is disabled
376 if (sub() && SettingsManager::instance()->videoSettings()->videoSource()->rawValue() == VideoSettings::videoDisabled) {
378 SettingsManager::instance()->videoSettings()->lowLatencyMode()->setRawValue(true);
379 }
380
381 _gimbalController = new GimbalController(this);
382 _vehicleSupports = new VehicleSupports(this);
383
384 _createCameraManager();
385}
386
388{
389 qCDebug(VehicleLog) << "~Vehicle" << this;
390
391 // Stop all timers and disconnect their signals to prevent any callbacks during destruction.
392 // Even though _stopCommandProcessing() should have been called earlier via VehicleLinkManager,
393 // we do it again here defensively in case the vehicle is destroyed without going through
394 // the normal link removal path (e.g., in unit tests).
395 if (_mavCmdQueue) {
396 _mavCmdQueue->stop();
397 }
398 _sendMultipleTimer.stop();
399 _sendMultipleTimer.disconnect();
400 _prearmErrorTimer.stop();
401 _prearmErrorTimer.disconnect();
402
403 delete _missionManager;
404 _missionManager = nullptr;
405
406 delete _autopilotPlugin;
407 _autopilotPlugin = nullptr;
408}
409
414
434
437
438QObject* Vehicle::sysStatusSensorInfo() { return _sysStatusSensorInfo.get(); }
439QmlObjectListModel* Vehicle::cameraTriggerPoints() { return _cameraTriggerPoints.get(); }
441
442void Vehicle::_deleteCameraManager()
443{
444 if(_cameraManager) {
445 // Disconnect all signals to prevent any callbacks during or after deletion
446 _cameraManager->disconnect();
447 delete _cameraManager;
448 _cameraManager = nullptr;
449 }
450}
451
452void Vehicle::_deleteGimbalController()
453{
454 if (_gimbalController) {
455 // Disconnect all signals to prevent any callbacks during or after deletion
456 _gimbalController->disconnect();
457 // The gimbal controller registers itself as the callback context for its GIMBAL_MANAGER_INFORMATION
458 // requestMessage calls. Cancel any still-outstanding request so the coordinator never calls back
459 // into the freed controller.
460 if (_reqMsgCoord) {
461 _reqMsgCoord->cancelRequests(_gimbalController);
462 }
463 delete _gimbalController;
464 _gimbalController = nullptr;
465 }
466}
467
468void Vehicle::_stopCommandProcessing()
469{
470 qCDebug(VehicleLog) << "_stopCommandProcessing - stopping timers and clearing pending commands";
471
472 // Stop timers AND disconnect their signals to prevent any pending callbacks
473 // from being delivered after this point. This is critical during vehicle destruction
474 // where a queued callback could access a partially-destroyed vehicle.
475 if (_mavCmdQueue) {
476 _mavCmdQueue->stop();
477 }
478 if (_reqMsgCoord) {
479 _reqMsgCoord->stop();
480 }
481 _sendMultipleTimer.stop();
482 _sendMultipleTimer.disconnect();
483}
484
486{
487 _firmwareType = static_cast<MAV_AUTOPILOT>(varFirmwareType.toInt());
488 _firmwarePlugin = FirmwarePluginManager::instance()->firmwarePluginForAutopilot(_firmwareType, _vehicleType);
489 if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
490 _capabilityBits |= MAV_PROTOCOL_CAPABILITY_TERRAIN;
491 } else {
492 _capabilityBits &= ~MAV_PROTOCOL_CAPABILITY_TERRAIN;
493 }
494 emit firmwareTypeChanged();
495 emit capabilityBitsChanged(_capabilityBits);
496}
497
499{
500 _vehicleType = static_cast<MAV_TYPE>(varVehicleType.toInt());
501 emit vehicleTypeChanged();
502}
503
504void Vehicle::_offlineCruiseSpeedSettingChanged(QVariant value)
505{
506 _defaultCruiseSpeed = value.toDouble();
507 emit defaultCruiseSpeedChanged(_defaultCruiseSpeed);
508}
509
510void Vehicle::_offlineHoverSpeedSettingChanged(QVariant value)
511{
512 _defaultHoverSpeed = value.toDouble();
513 emit defaultHoverSpeedChanged(_defaultHoverSpeed);
514}
515
517{
518 return QGCMAVLink::firmwareClassToString(_firmwareType);
519}
520
522{
523 _messagesReceived = 0;
524 _messagesSent = 0;
525 _messagesLost = 0;
526 _messageSeq = 0;
527 _heardFrom = false;
528}
529
530void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
531{
532 if (message.sysid != _systemID && message.sysid != 0) {
533 // We allow RADIO_STATUS messages which come from a link the vehicle is using to pass through and be handled
534 if (!(message.msgid == MAVLINK_MSG_ID_RADIO_STATUS && _vehicleLinkManager->containsLink(link))) {
535 return;
536 }
537 }
538
539 // We give the link manager first whack since it it reponsible for adding new links
541
542 //-- Check link status
543 _messagesReceived++;
545 if(!_heardFrom) {
546 if(message.msgid == MAVLINK_MSG_ID_HEARTBEAT) {
547 _heardFrom = true;
548 _compID = message.compid;
549 _messageSeq = message.seq + 1;
550 }
551 } else {
552 if(_compID == message.compid) {
553 uint16_t seq_received = static_cast<uint16_t>(message.seq);
554 uint16_t packet_lost_count = 0;
555 //-- Account for overflow during packet loss
556 if(seq_received < _messageSeq) {
557 packet_lost_count = (seq_received + 255) - _messageSeq;
558 } else {
559 packet_lost_count = seq_received - _messageSeq;
560 }
561 _messageSeq = message.seq + 1;
562 _messagesLost += packet_lost_count;
563 if(packet_lost_count)
564 emit messagesLostChanged();
565 }
566 }
567
568 // Give the plugin a change to adjust the message contents
569 if (!_firmwarePlugin->adjustIncomingMavlinkMessage(this, &message)) {
570 return;
571 }
572
573 // Give the Core Plugin access to all mavlink traffic
574 if (!QGCCorePlugin::instance()->mavlinkMessage(this, link, message)) {
575 return;
576 }
577
579 return;
580 }
581 _ftpManager->_mavlinkMessageReceived(message);
582 _parameterManager->mavlinkMessageReceived(message);
583 (void) QMetaObject::invokeMethod(_imageProtocolManager, "mavlinkMessageReceived", Qt::AutoConnection, message);
585
586 _reqMsgCoord->handleReceivedMessage(message);
587
588 // Handle creation of dynamic fact group lists
591
592 // Let the fact groups take a whack at the mavlink traffic
593 for (FactGroup* factGroup : factGroups()) {
594 factGroup->handleMessage(this, message);
595 }
596
597 this->handleMessage(this, message);
598
599 switch (message.msgid) {
600 case MAVLINK_MSG_ID_HOME_POSITION:
601 _handleHomePosition(message);
602 break;
603 case MAVLINK_MSG_ID_HEARTBEAT:
604 _handleHeartbeat(message);
605 break;
606 case MAVLINK_MSG_ID_RC_CHANNELS:
607 _handleRCChannels(message);
608 break;
609 case MAVLINK_MSG_ID_SERVO_OUTPUT_RAW:
610 {
611 mavlink_servo_output_raw_t servoOutputRaw;
612 mavlink_msg_servo_output_raw_decode(&message, &servoOutputRaw);
613
614 // ArduPilot commonly publishes servo1_raw..servo16_raw in a single packet (port may remain 0).
615 const uint16_t rawValues[16] = {
616 servoOutputRaw.servo1_raw,
617 servoOutputRaw.servo2_raw,
618 servoOutputRaw.servo3_raw,
619 servoOutputRaw.servo4_raw,
620 servoOutputRaw.servo5_raw,
621 servoOutputRaw.servo6_raw,
622 servoOutputRaw.servo7_raw,
623 servoOutputRaw.servo8_raw,
624 servoOutputRaw.servo9_raw,
625 servoOutputRaw.servo10_raw,
626 servoOutputRaw.servo11_raw,
627 servoOutputRaw.servo12_raw,
628 servoOutputRaw.servo13_raw,
629 servoOutputRaw.servo14_raw,
630 servoOutputRaw.servo15_raw,
631 servoOutputRaw.servo16_raw
632 };
633
634 for (int servoIndex = 0; servoIndex < _servoOutputRawValues.size() && servoIndex < 16; servoIndex++) {
635 _servoOutputRawValues[servoIndex] = (rawValues[servoIndex] == UINT16_MAX) ? -1 : static_cast<int>(rawValues[servoIndex]);
636 }
637
639 }
640 break;
641 case MAVLINK_MSG_ID_BATTERY_STATUS:
642 _handleBatteryStatus(message);
643 break;
644 case MAVLINK_MSG_ID_SYS_STATUS:
645 _handleSysStatus(message);
646 break;
647 case MAVLINK_MSG_ID_EXTENDED_SYS_STATE:
648 _handleExtendedSysState(message);
649 break;
650 case MAVLINK_MSG_ID_COMMAND_ACK:
651 _handleCommandAck(message);
652 break;
653 case MAVLINK_MSG_ID_LOGGING_DATA:
654 _handleMavlinkLoggingData(message);
655 break;
656 case MAVLINK_MSG_ID_LOGGING_DATA_ACKED:
657 _handleMavlinkLoggingDataAcked(message);
658 break;
659 case MAVLINK_MSG_ID_GPS_RAW_INT:
660 _handleGpsRawInt(message);
661 break;
662 case MAVLINK_MSG_ID_GLOBAL_POSITION_INT:
663 _handleGlobalPositionInt(message);
664 break;
665 case MAVLINK_MSG_ID_CAMERA_IMAGE_CAPTURED:
666 _handleCameraImageCaptured(message);
667 break;
668 case MAVLINK_MSG_ID_ADSB_VEHICLE:
670 break;
671 case MAVLINK_MSG_ID_HIGH_LATENCY:
672 _handleHighLatency(message);
673 break;
674 case MAVLINK_MSG_ID_HIGH_LATENCY2:
675 _handleHighLatency2(message);
676 break;
677 case MAVLINK_MSG_ID_STATUSTEXT:
678 m_statusTextHandler->mavlinkMessageReceived(message);
679 break;
680 case MAVLINK_MSG_ID_ORBIT_EXECUTION_STATUS:
681 _handleOrbitExecutionStatus(message);
682 break;
683 case MAVLINK_MSG_ID_PING:
684 _handlePing(link, message);
685 break;
686 case MAVLINK_MSG_ID_OBSTACLE_DISTANCE:
687 _handleObstacleDistance(message);
688 break;
689 case MAVLINK_MSG_ID_FENCE_STATUS:
690 _handleFenceStatus(message);
691 break;
692
693 case MAVLINK_MSG_ID_EVENT:
694 case MAVLINK_MSG_ID_CURRENT_EVENT_SEQUENCE:
695 case MAVLINK_MSG_ID_RESPONSE_EVENT_ERROR:
696 _handleEventMessage(message);
697 break;
698
699 case MAVLINK_MSG_ID_SERIAL_CONTROL:
700 {
701 mavlink_serial_control_t ser;
702 mavlink_msg_serial_control_decode(&message, &ser);
703 if (static_cast<size_t>(ser.count) > sizeof(ser.data)) {
704 qCWarning(VehicleLog) << "Invalid count for SERIAL_CONTROL, discarding." << ser.count;
705 } else {
706 emit mavlinkSerialControl(ser.device, ser.flags, ser.timeout, ser.baudrate,
707 QByteArray(reinterpret_cast<const char*>(ser.data), ser.count));
708 }
709 }
710 break;
711 case MAVLINK_MSG_ID_AVAILABLE_MODES_MONITOR:
712 {
713 // Avoid duplicate requests during initial connection setup
715 mavlink_available_modes_monitor_t availableModesMonitor;
716 mavlink_msg_available_modes_monitor_decode(&message, &availableModesMonitor);
717 _standardModes->availableModesMonitorReceived(availableModesMonitor.seq);
718 }
719 break;
720 }
721 case MAVLINK_MSG_ID_CURRENT_MODE:
722 _handleCurrentMode(message);
723 break;
724
725 // Following are ArduPilot dialect messages
726 case MAVLINK_MSG_ID_CAMERA_FEEDBACK:
727 _handleCameraFeedback(message);
728 break;
729 case MAVLINK_MSG_ID_LOG_ENTRY:
730 {
731 mavlink_log_entry_t log{};
732 mavlink_msg_log_entry_decode(&message, &log);
733 emit logEntry(log.time_utc, log.size, log.id, log.num_logs, log.last_log_num);
734 break;
735 }
736 case MAVLINK_MSG_ID_LOG_DATA:
737 {
738 mavlink_log_data_t log{};
739 mavlink_msg_log_data_decode(&message, &log);
740 if (static_cast<size_t>(log.count) > sizeof(log.data)) {
741 qCWarning(VehicleLog) << "Invalid count for LOG_DATA, discarding." << log.count;
742 } else {
743 emit logData(log.ofs, log.id, log.count, log.data);
744 }
745 break;
746 }
747 case MAVLINK_MSG_ID_MESSAGE_INTERVAL:
748 {
749 _messageIntervalManager->handleMessageInterval(message);
750 break;
751 }
752 case MAVLINK_MSG_ID_CONTROL_STATUS:
753 _handleControlStatus(message);
754 break;
755 case MAVLINK_MSG_ID_COMMAND_LONG:
756 _handleCommandLong(message);
757 break;
758 }
759
760 // This must be emitted after the vehicle processes the message. This way the vehicle state is up to date when anyone else
761 // does processing.
762 emit mavlinkMessageReceived(message);
763}
764
765void Vehicle::_handleCameraFeedback(const mavlink_message_t& message)
766{
767 // If CAMERA_IMAGE_CAPTURED is supported, then CAMERA_FEEDBACK is redundant and should be ignored
768 // to avoid duplicate points.
769 if (_cameraImageCapturedMessageAvailable) {
770 return;
771 }
772
773 mavlink_camera_feedback_t feedback;
774
775 mavlink_msg_camera_feedback_decode(&message, &feedback);
776
777 QGeoCoordinate imageCoordinate((double)feedback.lat / qPow(10.0, 7.0), (double)feedback.lng / qPow(10.0, 7.0), feedback.alt_msl);
778 qCDebug(VehicleLog) << "_handleCameraFeedback coord:index" << imageCoordinate << feedback.img_idx;
779 _cameraTriggerPoints->append(new QGCQGeoCoordinate(imageCoordinate, this));
780}
781
782void Vehicle::_handleOrbitExecutionStatus(const mavlink_message_t& message)
783{
784 mavlink_orbit_execution_status_t orbitStatus;
785
786 mavlink_msg_orbit_execution_status_decode(&message, &orbitStatus);
787
788 double newRadius = qAbs(static_cast<double>(orbitStatus.radius));
789 if (!QGC::fuzzyCompare(_orbitMapCircle->radius()->rawValue().toDouble(), newRadius)) {
790 _orbitMapCircle->radius()->setRawValue(newRadius);
791 }
792
793 bool newOrbitClockwise = orbitStatus.radius > 0 ? true : false;
794 if (_orbitMapCircle->clockwiseRotation() != newOrbitClockwise) {
795 _orbitMapCircle->setClockwiseRotation(newOrbitClockwise);
796 }
797
798 QGeoCoordinate newCenter(static_cast<double>(orbitStatus.x) / qPow(10.0, 7.0), static_cast<double>(orbitStatus.y) / qPow(10.0, 7.0));
799 if (_orbitMapCircle->center() != newCenter) {
800 _orbitMapCircle->setCenter(newCenter);
801 }
802
803 if (!_orbitActive) {
804 _orbitActive = true;
805 _orbitMapCircle->setShowRotation(true);
806 emit orbitActiveChanged(true);
807 }
808
809 _orbitTelemetryTimer.start(_orbitTelemetryTimeoutMsecs);
810}
811
812void Vehicle::_orbitTelemetryTimeout()
813{
814 _orbitActive = false;
815 emit orbitActiveChanged(false);
816}
817
818void Vehicle::_handleCameraImageCaptured(const mavlink_message_t& message)
819{
820 mavlink_camera_image_captured_t feedback;
821
822 mavlink_msg_camera_image_captured_decode(&message, &feedback);
823
824 if (!_cameraImageCapturedMessageAvailable) {
825 _cameraImageCapturedMessageAvailable = true;
826 // Avoid initial duplicatation in case where first photo has CAMERA_FEEDBACK processed first.
827 if (_cameraTriggerPoints->count() > 0) {
828 return;
829 }
830 }
831
832 QGeoCoordinate imageCoordinate((double)feedback.lat / qPow(10.0, 7.0), (double)feedback.lon / qPow(10.0, 7.0), feedback.alt);
833 qCDebug(VehicleLog) << "_handleCameraFeedback coord:index" << imageCoordinate << feedback.image_index << feedback.capture_result;
834 if (feedback.capture_result == 1) {
835 _cameraTriggerPoints->append(new QGCQGeoCoordinate(imageCoordinate, this));
836 }
837}
838
839// TODO: VehicleFactGroup
840void Vehicle::_handleGpsRawInt(mavlink_message_t& message)
841{
842 if (message.compid != _defaultComponentId) {
843 return;
844 }
845
846 mavlink_gps_raw_int_t gpsRawInt;
847 mavlink_msg_gps_raw_int_decode(&message, &gpsRawInt);
848
849 _gpsRawIntMessageAvailable = true;
850
851 if (gpsRawInt.fix_type >= GPS_FIX_TYPE_3D_FIX) {
852 if (!_globalPositionIntMessageAvailable) {
853 QGeoCoordinate newPosition(gpsRawInt.lat / (double)1E7, gpsRawInt.lon / (double)1E7, gpsRawInt.alt / 1000.0);
854 if (newPosition != _coordinate) {
855 _coordinate = newPosition;
856 emit coordinateChanged(_coordinate);
857 }
859 _altitudeAMSLFact.setRawValue(gpsRawInt.alt / 1000.0);
860 }
861 }
862 }
863}
864
865// TODO: VehicleFactGroup
866void Vehicle::_handleGlobalPositionInt(mavlink_message_t& message)
867{
868 if (message.compid != _defaultComponentId) {
869 return;
870 }
871
872 mavlink_global_position_int_t globalPositionInt;
873 mavlink_msg_global_position_int_decode(&message, &globalPositionInt);
874
876 _altitudeRelativeFact.setRawValue(globalPositionInt.relative_alt / 1000.0);
877 _altitudeAMSLFact.setRawValue(globalPositionInt.alt / 1000.0);
878 }
879
880 // ArduPilot sends bogus GLOBAL_POSITION_INT messages with lat/lat 0/0 even when it has no gps signal
881 // Apparently, this is in order to transport relative altitude information.
882 if (globalPositionInt.lat == 0 && globalPositionInt.lon == 0) {
883 return;
884 }
885
886 _globalPositionIntMessageAvailable = true;
887 QGeoCoordinate newPosition(globalPositionInt.lat / (double)1E7, globalPositionInt.lon / (double)1E7, globalPositionInt.alt / 1000.0);
888 if (newPosition != _coordinate) {
889 _coordinate = newPosition;
890 emit coordinateChanged(_coordinate);
891 }
892}
893
894// TODO: VehicleFactGroup
895void Vehicle::_handleHighLatency(mavlink_message_t& message)
896{
897 mavlink_high_latency_t highLatency;
898 mavlink_msg_high_latency_decode(&message, &highLatency);
899
900 QString previousFlightMode;
901 if (_base_mode != 0 || _custom_mode != 0){
902 // Vehicle is initialized with _base_mode=0 and _custom_mode=0. Don't pass this to flightMode() since it will complain about
903 // bad modes while unit testing.
904 previousFlightMode = flightMode();
905 }
906 _base_mode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
907 _custom_mode = _firmwarePlugin->highLatencyCustomModeTo32Bits(highLatency.custom_mode);
908 if (previousFlightMode != flightMode()) {
910 }
911
912 // Assume armed since we don't know
913 if (_armed != true) {
914 _armed = true;
915 emit armedChanged(_armed);
916 }
917
918 struct {
919 const double latitude;
920 const double longitude;
921 const double altitude;
922 } coordinate {
923 highLatency.latitude / (double)1E7,
924 highLatency.longitude / (double)1E7,
925 static_cast<double>(highLatency.altitude_amsl)
926 };
927
928 _coordinate.setLatitude(coordinate.latitude);
929 _coordinate.setLongitude(coordinate.longitude);
930 _coordinate.setAltitude(coordinate.altitude);
931 emit coordinateChanged(_coordinate);
932
933 _airSpeedFact.setRawValue((double)highLatency.airspeed / 5.0);
934 _groundSpeedFact.setRawValue((double)highLatency.groundspeed / 5.0);
935 _climbRateFact.setRawValue((double)highLatency.climb_rate / 10.0);
936 _headingFact.setRawValue((double)highLatency.heading * 2.0);
939}
940
941// TODO: VehicleFactGroup
942void Vehicle::_handleHighLatency2(mavlink_message_t& message)
943{
944 mavlink_high_latency2_t highLatency2;
945 mavlink_msg_high_latency2_decode(&message, &highLatency2);
946
947 QString previousFlightMode;
948 if (_base_mode != 0 || _custom_mode != 0){
949 // Vehicle is initialized with _base_mode=0 and _custom_mode=0. Don't pass this to flightMode() since it will complain about
950 // bad modes while unit testing.
951 previousFlightMode = flightMode();
952 }
953 // ArduPilot has the basemode in the custom0 field of the high latency message.
954 if (highLatency2.autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA) {
955 _base_mode = (uint8_t)highLatency2.custom0;
956 } else {
957 _base_mode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
958 }
959 _custom_mode = _firmwarePlugin->highLatencyCustomModeTo32Bits(highLatency2.custom_mode);
960 if (previousFlightMode != flightMode()) {
962 }
963 // ArduPilot has the arming status (basemode) in the custom0 field of the high latency message.
964 if (highLatency2.autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA) {
965 if ((uint8_t)highLatency2.custom0 & MAV_MODE_FLAG_SAFETY_ARMED && _armed != true) {
966 _armed = true;
967 emit armedChanged(_armed);
968 } else if (!((uint8_t)highLatency2.custom0 & MAV_MODE_FLAG_SAFETY_ARMED) && _armed != false) {
969 _armed = false;
970 emit armedChanged(_armed);
971 }
972 } else {
973 // Assume armed since we don't know
974 if (_armed != true) {
975 _armed = true;
976 emit armedChanged(_armed);
977 }
978 }
979
980 _coordinate.setLatitude(highLatency2.latitude / (double)1E7);
981 _coordinate.setLongitude(highLatency2.longitude / (double)1E7);
982 _coordinate.setAltitude(highLatency2.altitude);
983 emit coordinateChanged(_coordinate);
984
985 _airSpeedFact.setRawValue((double)highLatency2.airspeed / 5.0);
986 _groundSpeedFact.setRawValue((double)highLatency2.groundspeed / 5.0);
987 _climbRateFact.setRawValue((double)highLatency2.climb_rate / 10.0);
988 _headingFact.setRawValue((double)highLatency2.heading * 2.0);
990 _altitudeAMSLFact.setRawValue(highLatency2.altitude);
991
992 // Map from MAV_FAILURE bits to standard SYS_STATUS message handling
993 const uint32_t newOnboardControlSensorsEnabled = QGCMAVLink::highLatencyFailuresToMavSysStatus(highLatency2);
994 if (newOnboardControlSensorsEnabled != _onboardControlSensorsEnabled) {
995 _onboardControlSensorsEnabled = newOnboardControlSensorsEnabled;
996 _onboardControlSensorsPresent = newOnboardControlSensorsEnabled;
997 _onboardControlSensorsUnhealthy = 0;
998 }
999}
1000
1001void Vehicle::_setCapabilities(uint64_t capabilityBits)
1002{
1003 _capabilityBits = capabilityBits;
1004 _capabilityBitsKnown = true;
1005 emit capabilitiesKnownChanged(true);
1006 emit capabilityBitsChanged(_capabilityBits);
1007
1008 QString supports("supports");
1009 QString doesNotSupport("does not support");
1010
1011 qCDebug(VehicleLog) << QString("Vehicle %1 Mavlink 2.0").arg(_capabilityBits & MAV_PROTOCOL_CAPABILITY_MAVLINK2 ? supports : doesNotSupport);
1012 qCDebug(VehicleLog) << QString("Vehicle %1 MISSION_ITEM_INT").arg(_capabilityBits & MAV_PROTOCOL_CAPABILITY_MISSION_INT ? supports : doesNotSupport);
1013 qCDebug(VehicleLog) << QString("Vehicle %1 MISSION_COMMAND_INT").arg(_capabilityBits & MAV_PROTOCOL_CAPABILITY_COMMAND_INT ? supports : doesNotSupport);
1014 qCDebug(VehicleLog) << QString("Vehicle %1 GeoFence").arg(_capabilityBits & MAV_PROTOCOL_CAPABILITY_MISSION_FENCE ? supports : doesNotSupport);
1015 qCDebug(VehicleLog) << QString("Vehicle %1 RallyPoints").arg(_capabilityBits & MAV_PROTOCOL_CAPABILITY_MISSION_RALLY ? supports : doesNotSupport);
1016 qCDebug(VehicleLog) << QString("Vehicle %1 Terrain").arg(_capabilityBits & MAV_PROTOCOL_CAPABILITY_TERRAIN ? supports : doesNotSupport);
1017}
1018
1020{
1021 QString uid;
1022 uint8_t* pUid = (uint8_t*)(void*)&_uid;
1023 uid = uid.asprintf("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
1024 pUid[0] & 0xff,
1025 pUid[1] & 0xff,
1026 pUid[2] & 0xff,
1027 pUid[3] & 0xff,
1028 pUid[4] & 0xff,
1029 pUid[5] & 0xff,
1030 pUid[6] & 0xff,
1031 pUid[7] & 0xff);
1032 return uid;
1033}
1034
1035void Vehicle::_handleExtendedSysState(mavlink_message_t& message)
1036{
1037 if (message.compid != _defaultComponentId) {
1038 return;
1039 }
1040
1041 mavlink_extended_sys_state_t extendedState;
1042 mavlink_msg_extended_sys_state_decode(&message, &extendedState);
1043
1044 switch (extendedState.landed_state) {
1045 case MAV_LANDED_STATE_ON_GROUND:
1046 _setUnderway(false);
1047 _setLanding(false);
1048 break;
1049 case MAV_LANDED_STATE_TAKEOFF:
1050 case MAV_LANDED_STATE_IN_AIR:
1051 _setUnderway(true);
1052 _setLanding(false);
1053 break;
1054 case MAV_LANDED_STATE_LANDING:
1055 _setUnderway(true);
1056 _setLanding(true);
1057 break;
1058 default:
1059 break;
1060 }
1061
1062 if (vtol()) {
1063 bool vtolInFwdFlight = extendedState.vtol_state == MAV_VTOL_STATE_FW;
1064 if (vtolInFwdFlight != _vtolInFwdFlight) {
1065 _vtolInFwdFlight = vtolInFwdFlight;
1067 }
1068 }
1069}
1070
1071bool Vehicle::_apmArmingNotRequired()
1072{
1073 const QString armingRequireParam("ARMING_REQUIRE");
1074 if (!_parameterManager->parameterExists(ParameterManager::defaultComponentId, armingRequireParam)) {
1075 return false;
1076 }
1077 const Fact* const armingRequire =
1078 _parameterManager->getParameter(ParameterManager::defaultComponentId, armingRequireParam);
1079 return armingRequire && (armingRequire->rawValue().toInt() == 0);
1080}
1081
1082void Vehicle::_handleSysStatus(mavlink_message_t& message)
1083{
1084 if (message.compid != _defaultComponentId) {
1085 return;
1086 }
1087
1088 mavlink_sys_status_t sysStatus;
1089 mavlink_msg_sys_status_decode(&message, &sysStatus);
1090
1091 _sysStatusSensorInfo->update(sysStatus);
1092
1093 if (sysStatus.onboard_control_sensors_enabled & MAV_SYS_STATUS_PREARM_CHECK) {
1094 if (!_readyToFlyAvailable) {
1095 _readyToFlyAvailable = true;
1096 emit readyToFlyAvailableChanged(true);
1097 }
1098
1099 bool newReadyToFly = sysStatus.onboard_control_sensors_health & MAV_SYS_STATUS_PREARM_CHECK;
1100 if (newReadyToFly != _readyToFly) {
1101 _readyToFly = newReadyToFly;
1102 emit readyToFlyChanged(_readyToFly);
1103 }
1104 }
1105
1106 bool newAllSensorsHealthy = (sysStatus.onboard_control_sensors_enabled & sysStatus.onboard_control_sensors_health) == sysStatus.onboard_control_sensors_enabled;
1107 if (newAllSensorsHealthy != _allSensorsHealthy) {
1108 _allSensorsHealthy = newAllSensorsHealthy;
1109 emit allSensorsHealthyChanged(_allSensorsHealthy);
1110 }
1111
1112 if (_onboardControlSensorsPresent != sysStatus.onboard_control_sensors_present) {
1113 _onboardControlSensorsPresent = sysStatus.onboard_control_sensors_present;
1114 emit sensorsPresentBitsChanged(_onboardControlSensorsPresent);
1115 emit requiresGpsFixChanged();
1116 }
1117 if (_onboardControlSensorsEnabled != sysStatus.onboard_control_sensors_enabled) {
1118 _onboardControlSensorsEnabled = sysStatus.onboard_control_sensors_enabled;
1119 emit sensorsEnabledBitsChanged(_onboardControlSensorsEnabled);
1120 }
1121 if (_onboardControlSensorsHealth != sysStatus.onboard_control_sensors_health) {
1122 _onboardControlSensorsHealth = sysStatus.onboard_control_sensors_health;
1123 emit sensorsHealthBitsChanged(_onboardControlSensorsHealth);
1124 }
1125
1126 // ArduPilot firmare has a strange case when ARMING_REQUIRE=0. This means the vehicle is always armed but the motors are not
1127 // really powered up until the safety button is pressed. Because of this we can't depend on the heartbeat to tell us the true
1128 // armed (and dangerous) state. We must instead rely on SYS_STATUS telling us that the motors are enabled.
1129 if (apmFirmware() && _apmArmingNotRequired()) {
1130 _updateArmed(_onboardControlSensorsEnabled & MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS);
1131 }
1132
1133 uint32_t newSensorsUnhealthy = _onboardControlSensorsEnabled & ~_onboardControlSensorsHealth;
1134 if (newSensorsUnhealthy != _onboardControlSensorsUnhealthy) {
1135 _onboardControlSensorsUnhealthy = newSensorsUnhealthy;
1136 emit sensorsUnhealthyBitsChanged(_onboardControlSensorsUnhealthy);
1137 }
1138}
1139
1140void Vehicle::_handleBatteryStatus(mavlink_message_t& message)
1141{
1142 mavlink_battery_status_t batteryStatus;
1143 mavlink_msg_battery_status_decode(&message, &batteryStatus);
1144
1145 if (!_lowestBatteryChargeStateAnnouncedMap.contains(batteryStatus.id)) {
1146 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1147 }
1148
1149 QString batteryMessage;
1150
1151 switch (batteryStatus.charge_state) {
1152 case MAV_BATTERY_CHARGE_STATE_OK:
1153 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1154 break;
1155 case MAV_BATTERY_CHARGE_STATE_LOW:
1156 if (batteryStatus.charge_state > _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id]) {
1157 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1158 batteryMessage = tr("battery %1 level low");
1159 }
1160 break;
1161 case MAV_BATTERY_CHARGE_STATE_CRITICAL:
1162 if (batteryStatus.charge_state > _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id]) {
1163 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1164 batteryMessage = tr("battery %1 level is critical");
1165 }
1166 break;
1167 case MAV_BATTERY_CHARGE_STATE_EMERGENCY:
1168 if (batteryStatus.charge_state > _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id]) {
1169 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1170 batteryMessage = tr("battery %1 level emergency");
1171 }
1172 break;
1173 case MAV_BATTERY_CHARGE_STATE_FAILED:
1174 if (batteryStatus.charge_state > _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id]) {
1175 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1176 batteryMessage = tr("battery %1 failed");
1177 }
1178 break;
1179 case MAV_BATTERY_CHARGE_STATE_UNHEALTHY:
1180 if (batteryStatus.charge_state > _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id]) {
1181 _lowestBatteryChargeStateAnnouncedMap[batteryStatus.id] = batteryStatus.charge_state;
1182 batteryMessage = tr("battery %1 unhealthy");
1183 }
1184 break;
1185 }
1186
1187 if (!batteryMessage.isEmpty()) {
1188 QString batteryIdStr("%1");
1189 if (_batteryFactGroupListModel->count() > 1) {
1190 batteryIdStr = batteryIdStr.arg(batteryStatus.id);
1191 } else {
1192 batteryIdStr = batteryIdStr.arg("");
1193 }
1194 _say(tr("warning"));
1195 _say(QStringLiteral("%1 %2 ").arg(_vehicleIdSpeech()).arg(batteryMessage.arg(batteryIdStr)));
1196 }
1197}
1198
1199void Vehicle::_setHomePosition(QGeoCoordinate& homeCoord)
1200{
1201 if (homeCoord != _homePosition) {
1202 _homePosition = homeCoord;
1203 qCDebug(VehicleLog) << "new home location set at coordinate: " << homeCoord;
1204 emit homePositionChanged(_homePosition);
1205 }
1206}
1207
1208void Vehicle::_handleHomePosition(mavlink_message_t& message)
1209{
1210 if (message.compid != _defaultComponentId) {
1211 return;
1212 }
1213
1214 mavlink_home_position_t homePos;
1215
1216 mavlink_msg_home_position_decode(&message, &homePos);
1217
1218 QGeoCoordinate newHomePosition (homePos.latitude / 10000000.0,
1219 homePos.longitude / 10000000.0,
1220 homePos.altitude / 1000.0);
1221 _setHomePosition(newHomePosition);
1222}
1223
1224void Vehicle::_updateArmed(bool armed)
1225{
1226 if (_armed != armed) {
1227 _armed = armed;
1228 emit armedChanged(_armed);
1229 // We are transitioning to the armed state, begin tracking trajectory points for the map
1230 if (_armed) {
1231 _trajectoryPoints->start();
1232 _flightTimerStart();
1233 _clearCameraTriggerPoints();
1234 // Reset battery warning
1236 } else {
1237 _trajectoryPoints->stop();
1238 _flightTimerStop();
1239 // Also handle Video Streaming
1240 if(SettingsManager::instance()->videoSettings()->disableWhenDisarmed()->rawValue().toBool()) {
1241 SettingsManager::instance()->videoSettings()->streamEnabled()->setRawValue(false);
1243 }
1244 }
1245 }
1246}
1247
1248void Vehicle::_handlePing(LinkInterface* link, mavlink_message_t& message)
1249{
1250 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
1251 if (!sharedLink) {
1252 qCDebug(VehicleLog) << "_handlePing: primary link gone!";
1253 return;
1254 }
1255
1256 mavlink_ping_t ping;
1258
1259 mavlink_msg_ping_decode(&message, &ping);
1260
1261 if ((ping.target_system == 0) && (ping.target_component == 0)) {
1262 // Mavlink defines a ping request as a MSG_ID_PING which contains target_system = 0 and target_component = 0
1263 // So only send a ping response when you receive a valid ping request
1264 mavlink_msg_ping_pack_chan(static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
1265 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
1266 sharedLink->mavlinkChannel(),
1267 &msg,
1268 ping.time_usec,
1269 ping.seq,
1270 message.sysid,
1271 message.compid);
1272 sendMessageOnLinkThreadSafe(link, msg);
1273 }
1274}
1275
1276void Vehicle::setActuatorsMetadata([[maybe_unused]] uint8_t compid,
1277 const QString &metadataJsonFileName,
1278 const QJsonDocument &metadataJson)
1279{
1280 if (!_actuators) {
1281 _actuators = new Actuators(this, this);
1282 }
1283 _actuators->load(metadataJsonFileName, metadataJson);
1284}
1285
1286void Vehicle::_handleHeartbeat(mavlink_message_t& message)
1287{
1288 if (message.compid != _defaultComponentId) {
1289 return;
1290 }
1291
1292 mavlink_heartbeat_t heartbeat;
1293
1294 mavlink_msg_heartbeat_decode(&message, &heartbeat);
1295
1296 bool newArmed = heartbeat.base_mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY;
1297
1298 // ArduPilot firmare has a strange case when ARMING_REQUIRE=0. This means the vehicle is always armed but the motors are not
1299 // really powered up until the safety button is pressed. Because of this we can't depend on the heartbeat to tell us the true
1300 // armed (and dangerous) state. We must instead rely on SYS_STATUS telling us that the motors are enabled.
1301 if (apmFirmware()) {
1302 if (!_apmArmingNotRequired() || !(_onboardControlSensorsPresent & MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS)) {
1303 // If ARMING_REQUIRE!=0 or we haven't seen motor output status yet we use the hearbeat info for armed
1304 _updateArmed(newArmed);
1305 }
1306 } else {
1307 // Non-ArduPilot always updates from armed state in heartbeat
1308 _updateArmed(newArmed);
1309 }
1310
1311 if (heartbeat.base_mode != _base_mode || heartbeat.custom_mode != _custom_mode) {
1312 QString previousFlightMode;
1313 if (_base_mode != 0 || _custom_mode != 0){
1314 // Vehicle is initialized with _base_mode=0 and _custom_mode=0. Don't pass this to flightMode() since it will complain about
1315 // bad modes while unit testing.
1316 previousFlightMode = flightMode();
1317 }
1318 _base_mode = heartbeat.base_mode;
1319 _custom_mode = heartbeat.custom_mode;
1320 if (previousFlightMode != flightMode()) {
1322 }
1323 }
1324}
1325
1326void Vehicle::_handleCurrentMode(mavlink_message_t& message)
1327{
1328 if (message.compid != _defaultComponentId) {
1329 return;
1330 }
1331
1332 mavlink_current_mode_t currentMode;
1333 mavlink_msg_current_mode_decode(&message, &currentMode);
1334 if (currentMode.intended_custom_mode != 0) { // 0 == unknown/not supplied
1335 _has_custom_mode_user_intention = true;
1336 QString previousFlightMode = flightMode();
1337 bool changed = _custom_mode_user_intention != currentMode.intended_custom_mode;
1338 _custom_mode_user_intention = currentMode.intended_custom_mode;
1339 if (changed && previousFlightMode != flightMode()) {
1341 }
1342 }
1343}
1344
1345void Vehicle::_handleRCChannels(mavlink_message_t& message)
1346{
1347 mavlink_rc_channels_t channels;
1348
1349 mavlink_msg_rc_channels_decode(&message, &channels);
1350
1351 QVector<uint16_t> rawChannelValues({
1352 channels.chan1_raw,
1353 channels.chan2_raw,
1354 channels.chan3_raw,
1355 channels.chan4_raw,
1356 channels.chan5_raw,
1357 channels.chan6_raw,
1358 channels.chan7_raw,
1359 channels.chan8_raw,
1360 channels.chan9_raw,
1361 channels.chan10_raw,
1362 channels.chan11_raw,
1363 channels.chan12_raw,
1364 channels.chan13_raw,
1365 channels.chan14_raw,
1366 channels.chan15_raw,
1367 channels.chan16_raw,
1368 channels.chan17_raw,
1369 channels.chan18_raw,
1370 });
1371
1372 // The internals of radio calibration can ony deal with contiguous channels (other stuff as well!)
1373 int validChannelCount = 0;
1374 int firstUnusedChannelIndex = -1;
1375 for (int i=0; i<rawChannelValues.size(); i++) {
1376 if (rawChannelValues[i] != UINT16_MAX) {
1377 validChannelCount++;
1378 } else if (firstUnusedChannelIndex == -1) {
1379 firstUnusedChannelIndex = i;
1380 }
1381 }
1382 if (firstUnusedChannelIndex != -1 && firstUnusedChannelIndex != validChannelCount) {
1383 qCWarning(VehicleLog) << "Non-contiguous RC channels detected. Not publishing data from RC_CHANNELS.";
1384 return;
1385 }
1386
1387 QVector<int> channelValues(validChannelCount);
1388 QVector<int> clampedValues(validChannelCount);
1389 for (int channelIndex = 0; channelIndex < validChannelCount; ++channelIndex) {
1390 channelValues[channelIndex] = rawChannelValues[channelIndex];
1391 clampedValues[channelIndex] = std::clamp(channelValues[channelIndex], 1000, 2000);
1392 }
1393
1394 // rcRSSI is now a Fact on VehicleFactGroup (this); VehicleFactGroup owns the low-pass
1395 // filter and sentinel handling for the 0-100 / 255-unknown semantics.
1396 updateRCRSSI(channels.rssi);
1397 emit rcChannelsRawChanged(channelValues);
1398 emit rcChannelsClampedChanged(clampedValues);
1399}
1400
1402{
1403 if (!link->isConnected()) {
1404 qCDebug(VehicleLog) << "sendMessageOnLinkThreadSafe" << link << "not connected!";
1405 return false;
1406 }
1407
1408 // Give the plugin a chance to adjust
1409 _firmwarePlugin->adjustOutgoingMavlinkMessageThreadSafe(this, link, &message);
1410
1411 // Single send chokepoint: LinkInterface re-signs, serializes, and writes.
1412 link->sendMessageThreadSafe(message);
1413 _messagesSent++;
1414 emit messagesSentChanged();
1415
1416 return true;
1417}
1418
1420{
1421 uint8_t frameType = 0;
1422 if (_vehicleType == MAV_TYPE_SUBMARINE) {
1423 const QString frameConfigParam = QStringLiteral("FRAME_CONFIG");
1424 const Fact* const frameConfig = _parameterManager->parameterExists(_compID, frameConfigParam)
1425 ? _parameterManager->getParameter(_compID, frameConfigParam)
1426 : nullptr;
1427 if (frameConfig) {
1428 frameType = frameConfig->rawValue().toInt();
1429 } else {
1430 qCDebug(VehicleLog) << frameConfigParam << "not available, using default frame";
1431 }
1432 }
1433 return QGCMAVLink::motorCount(_vehicleType, frameType);
1434}
1435
1437{
1438 return _firmwarePlugin->multiRotorCoaxialMotors(this);
1439}
1440
1442{
1443 return _firmwarePlugin->multiRotorXConfig(this);
1444}
1445
1446void Vehicle::_activeVehicleChanged(Vehicle *newActiveVehicle)
1447{
1448 _isActiveVehicle = newActiveVehicle == this;
1449}
1450
1452{
1453 return _homePosition;
1454}
1455
1456void Vehicle::setArmed(bool armed, bool showError)
1457{
1458 // We specifically use COMMAND_LONG:MAV_CMD_COMPONENT_ARM_DISARM since it is supported by more flight stacks.
1459 sendMavCommand(_defaultComponentId,
1460 MAV_CMD_COMPONENT_ARM_DISARM,
1461 showError,
1462 armed ? 1.0f : 0.0f);
1463}
1464
1466{
1467 sendMavCommand(_defaultComponentId,
1468 MAV_CMD_COMPONENT_ARM_DISARM,
1469 true, // show error if fails
1470 1.0f, // arm
1471 2989); // force arm
1472}
1473
1475{
1476 return _firmwarePlugin->isCapable(this, FirmwarePlugin::SetFlightModeCapability);
1477}
1478
1480{
1481 QStringList flightModes = _firmwarePlugin->flightModes(this);
1482 return flightModes;
1483}
1484
1485QString Vehicle::flightMode() const
1486{
1487 return _firmwarePlugin->flightMode(_base_mode, _custom_mode);
1488}
1489
1490bool Vehicle::setFlightModeCustom(const QString& flightMode, uint8_t* base_mode, uint32_t* custom_mode)
1491{
1492 return _firmwarePlugin->setFlightMode(flightMode, base_mode, custom_mode);
1493}
1494
1495void Vehicle::setFlightMode(const QString& flightMode)
1496{
1497 uint8_t base_mode;
1498 uint32_t custom_mode;
1499
1500 if (setFlightModeCustom(flightMode, &base_mode, &custom_mode)) {
1501 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
1502 if (!sharedLink) {
1503 qCDebug(VehicleLog) << "setFlightMode: primary link gone!";
1504 return;
1505 }
1506
1507 uint8_t newBaseMode = _base_mode & ~MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE;
1508
1509 // setFlightMode will only set MAV_MODE_FLAG_CUSTOM_MODE_ENABLED in base_mode, we need to move back in the existing
1510 // states.
1511 newBaseMode |= base_mode;
1512
1513 if (_firmwarePlugin->MAV_CMD_DO_SET_MODE_is_supported()) {
1515 MAV_CMD_DO_SET_MODE,
1516 true, // show error if fails
1517 MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
1518 custom_mode);
1519 } else {
1521 mavlink_msg_set_mode_pack_chan(MAVLinkProtocol::instance()->getSystemId(),
1523 sharedLink->mavlinkChannel(),
1524 &msg,
1525 id(),
1526 newBaseMode,
1527 custom_mode);
1528 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
1529 }
1530 } else {
1531 qCWarning(VehicleLog) << "FirmwarePlugin::setFlightMode failed, flightMode:" << flightMode;
1532 }
1533}
1534
1535#if 0
1536QVariantList Vehicle::links() const {
1537 QVariantList ret;
1538
1539 for( const auto &item: _links )
1540 ret << QVariant::fromValue(item);
1541
1542 return ret;
1543}
1544#endif
1545
1546void Vehicle::requestDataStream(MAV_DATA_STREAM stream, uint16_t rate, bool sendMultiple)
1547{
1548 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
1549 if (!sharedLink) {
1550 qCDebug(VehicleLog) << "requestDataStream: primary link gone!";
1551 return;
1552 }
1553
1555 mavlink_request_data_stream_t dataStream;
1556
1557 memset(&dataStream, 0, sizeof(dataStream));
1558
1559 dataStream.req_stream_id = stream;
1560 dataStream.req_message_rate = rate;
1561 dataStream.start_stop = 1; // start
1562 dataStream.target_system = id();
1563 dataStream.target_component = _defaultComponentId;
1564
1565 mavlink_msg_request_data_stream_encode_chan(MAVLinkProtocol::instance()->getSystemId(),
1567 sharedLink->mavlinkChannel(),
1568 &msg,
1569 &dataStream);
1570
1571 if (sendMultiple) {
1572 // We use sendMessageMultiple since we really want these to make it to the vehicle
1574 } else {
1575 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
1576 }
1577}
1578
1579void Vehicle::_sendMessageMultipleNext()
1580{
1581 if (_nextSendMessageMultipleIndex < _sendMessageMultipleList.count()) {
1582 uint32_t msgId = _sendMessageMultipleList[_nextSendMessageMultipleIndex].message.msgid;
1583 const mavlink_message_info_t* info = mavlink_get_message_info_by_id(msgId);
1584 QString msgName = info ? info->name : QString::number(msgId);
1585 qCDebug(VehicleLog) << "_sendMessageMultipleNext:" << msgName;
1586
1587 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
1588 if (sharedLink) {
1589 sendMessageOnLinkThreadSafe(sharedLink.get(), _sendMessageMultipleList[_nextSendMessageMultipleIndex].message);
1590 }
1591
1592 if (--_sendMessageMultipleList[_nextSendMessageMultipleIndex].retryCount <= 0) {
1593 _sendMessageMultipleList.removeAt(_nextSendMessageMultipleIndex);
1594 } else {
1595 _nextSendMessageMultipleIndex++;
1596 }
1597 }
1598
1599 if (_nextSendMessageMultipleIndex >= _sendMessageMultipleList.count()) {
1600 _nextSendMessageMultipleIndex = 0;
1601 }
1602}
1603
1605{
1606 SendMessageMultipleInfo_t info;
1607
1608 info.message = message;
1609 info.retryCount = _sendMessageMultipleRetries;
1610
1611 _sendMessageMultipleList.append(info);
1612}
1613
1614void Vehicle::_missionManagerError(int errorCode, const QString& errorMsg)
1615{
1616 Q_UNUSED(errorCode);
1617 QGC::showAppMessage(tr("Mission transfer failed. Error: %1").arg(errorMsg));
1618}
1619
1620void Vehicle::_geoFenceManagerError(int errorCode, const QString& errorMsg)
1621{
1622 Q_UNUSED(errorCode);
1623 QGC::showAppMessage(tr("GeoFence transfer failed. Error: %1").arg(errorMsg));
1624}
1625
1626void Vehicle::_rallyPointManagerError(int errorCode, const QString& errorMsg)
1627{
1628 Q_UNUSED(errorCode);
1629 QGC::showAppMessage(tr("Rally Point transfer failed. Error: %1").arg(errorMsg));
1630}
1631
1632void Vehicle::_clearCameraTriggerPoints()
1633{
1634 _cameraImageCapturedMessageAvailable = false;
1635 _cameraTriggerPoints->clearAndDeleteContents();
1636}
1637
1638void Vehicle::_flightTimerStart()
1639{
1640 _flightTimer.start();
1641 _flightTimeUpdater.start();
1644}
1645
1646void Vehicle::_flightTimerStop()
1647{
1648 _flightTimeUpdater.stop();
1649}
1650
1651void Vehicle::_updateFlightTime()
1652{
1653 _flightTimeFact.setRawValue((double)_flightTimer.elapsed() / 1000.0);
1654}
1655
1656void Vehicle::_gotProgressUpdate(float progressValue)
1657{
1659 return;
1660 }
1662 progressValue = 0.f;
1663 }
1664 _loadProgress = progressValue;
1665 emit loadProgressChanged(progressValue);
1666}
1667
1668void Vehicle::_firstMissionLoadComplete()
1669{
1670 disconnect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_firstMissionLoadComplete);
1671}
1672
1673void Vehicle::_firstGeoFenceLoadComplete()
1674{
1675 disconnect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &Vehicle::_firstGeoFenceLoadComplete);
1676}
1677
1678void Vehicle::_firstRallyPointLoadComplete()
1679{
1680 disconnect(_rallyPointManager, &RallyPointManager::loadComplete, this, &Vehicle::_firstRallyPointLoadComplete);
1681 _initialPlanRequestComplete = true;
1683}
1684
1685void Vehicle::_parametersReady(bool parametersReady)
1686{
1687 qCDebug(VehicleLog) << "_parametersReady" << parametersReady;
1688
1689 // Try to set current unix time to the vehicle
1690 _sendQGCTimeToVehicle();
1691 // Send time twice, more likely to get to the vehicle on a noisy link
1692 _sendQGCTimeToVehicle();
1693 if (parametersReady) {
1694 disconnect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady);
1695 _setupAutoDisarmSignalling();
1696 }
1697
1700
1701 emit haveMRSpeedLimChanged();
1702 emit haveFWSpeedLimChanged();
1703}
1704
1705void Vehicle::_sendQGCTimeToVehicle()
1706{
1707 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
1708 if (!sharedLink) {
1709 qCDebug(VehicleLog) << "_sendQGCTimeToVehicle: primary link gone!";
1710 return;
1711 }
1712
1714 mavlink_system_time_t cmd;
1715
1716 // Timestamp of the master clock in microseconds since UNIX epoch.
1717 cmd.time_unix_usec = QDateTime::currentDateTime().currentMSecsSinceEpoch()*1000;
1718 // Timestamp of the component clock since boot time in milliseconds (Not necessary).
1719 cmd.time_boot_ms = 0;
1720 mavlink_msg_system_time_encode_chan(MAVLinkProtocol::instance()->getSystemId(),
1722 sharedLink->mavlinkChannel(),
1723 &msg,
1724 &cmd);
1725
1726 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
1727}
1728
1729void Vehicle::virtualTabletJoystickValue(double roll, double pitch, double yaw, double thrust)
1730{
1731 // The following if statement prevents the virtualTabletJoystick from sending values if the standard joystick is enabled
1732 bool isActiveVehicle = (MultiVehicleManager::instance()->activeVehicle() == this);
1733 bool joystickEnabled = isActiveVehicle && JoystickManager::instance()->activeJoystickEnabledForActiveVehicle();
1734 if (!joystickEnabled) {
1736 static_cast<float>(roll),
1737 static_cast<float>(pitch),
1738 static_cast<float>(yaw),
1739 static_cast<float>(thrust),
1740 0, 0, // buttons
1741 NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN); // extension values
1742 }
1743}
1744
1745void Vehicle::_say(const QString& text)
1746{
1747 AudioOutput::instance()->say(text.toLower());
1748}
1749
1751{
1753}
1754
1756{
1758}
1759
1760bool Vehicle::rover() const
1761{
1763}
1764
1765bool Vehicle::sub() const
1766{
1768}
1769
1771{
1773}
1774
1776{
1778}
1779
1780bool Vehicle::vtol() const
1781{
1783}
1784
1786{
1787 return QGCMAVLink::mavTypeToString(_vehicleType);
1788}
1789
1794
1796QString Vehicle::_vehicleIdSpeech()
1797{
1798 if (MultiVehicleManager::instance()->vehicles()->count() > 1) {
1799 return tr("Vehicle %1 ").arg(id());
1800 } else {
1801 return QString();
1802 }
1803}
1804
1805void Vehicle::_handleFlightModeChanged(const QString& flightMode)
1806{
1807 if (flightMode != _lastAnnouncedFlightMode) {
1808 _lastAnnouncedFlightMode = flightMode;
1809 _say(tr("%1 %2 flight mode").arg(_vehicleIdSpeech()).arg(flightMode));
1810 }
1811 emit guidedModeChanged(_firmwarePlugin->isGuidedMode(this));
1812}
1813
1814void Vehicle::_announceArmedChanged(bool armed)
1815{
1816 _say(QString("%1 %2").arg(_vehicleIdSpeech()).arg(armed ? tr("armed") : tr("disarmed")));
1817 if(armed) {
1818 //-- Keep track of armed coordinates
1819 _armedPosition = _coordinate;
1820 emit armedPositionChanged();
1821 }
1822}
1823
1824void Vehicle::_setUnderway(bool underway)
1825{
1826 if (_underway != underway) {
1827 _underway = underway;
1829 _updateAirborne();
1830 }
1831}
1832
1833void Vehicle::_updateAirborne()
1834{
1835 const bool airborne = _underway && !rover() && !sub();
1836 if (_airborne != airborne) {
1837 _airborne = airborne;
1839 }
1840}
1841
1842void Vehicle::_setLanding(bool landing)
1843{
1844 if (armed() && _landing != landing) {
1845 _landing = landing;
1846 emit landingChanged(landing);
1847 }
1848}
1849
1851{
1852 return _firmwarePlugin->gotoFlightMode();
1853}
1854
1855void Vehicle::guidedModeRTL(bool smartRTL)
1856{
1857 if (!_vehicleSupports->guidedMode()) {
1859 return;
1860 }
1861 _firmwarePlugin->guidedModeRTL(this, smartRTL);
1862}
1863
1865{
1866 if (!_vehicleSupports->guidedMode()) {
1868 return;
1869 }
1870 _firmwarePlugin->guidedModeLand(this);
1871}
1872
1873void Vehicle::guidedModeTakeoff(double altitudeRelative)
1874{
1875 if (!_vehicleSupports->guidedMode()) {
1877 return;
1878 }
1879 _firmwarePlugin->guidedModeTakeoff(this, altitudeRelative);
1880}
1881
1883{
1884 return _firmwarePlugin->minimumTakeoffAltitudeMeters(this);
1885}
1886
1891
1892
1894{
1895 return _firmwarePlugin->maximumEquivalentAirspeed(this);
1896}
1897
1898
1900{
1901 return _firmwarePlugin->minimumEquivalentAirspeed(this);
1902}
1903
1905{
1906 return _firmwarePlugin->hasGripper(this);
1907}
1908
1910{
1911 _firmwarePlugin->startTakeoff(this);
1912}
1913
1914
1916{
1917 _firmwarePlugin->startMission(this);
1918}
1919
1920bool Vehicle::guidedModeGotoLocation(const QGeoCoordinate& gotoCoord, double forwardFlightLoiterRadius)
1921{
1922 if (!_vehicleSupports->guidedMode()) {
1924 return false;
1925 }
1926 if (!coordinate().isValid()) {
1927 return false;
1928 }
1929 if (!gotoCoord.isValid()) {
1930 return false;
1931 }
1932 double maxDistance = SettingsManager::instance()->flyViewSettings()->maxGoToLocationDistance()->rawValue().toDouble();
1933 if (coordinate().distanceTo(gotoCoord) > maxDistance) {
1934 QGC::showAppMessage(QString("New location is too far. Must be less than %1 %2.").arg(qRound(FactMetaData::metersToAppSettingsHorizontalDistanceUnits(maxDistance).toDouble())).arg(FactMetaData::appSettingsHorizontalDistanceUnitsString()));
1935 return false;
1936 }
1937
1938 return _firmwarePlugin->guidedModeGotoLocation(this, gotoCoord, forwardFlightLoiterRadius);
1939}
1940
1941void Vehicle::guidedModeChangeAltitude(double altitudeChange, bool pauseVehicle)
1942{
1943 if (!_vehicleSupports->guidedMode()) {
1945 return;
1946 }
1947 _firmwarePlugin->guidedModeChangeAltitude(this, altitudeChange, pauseVehicle);
1948}
1949
1950void
1952{
1953 if (!_vehicleSupports->guidedMode()) {
1955 return;
1956 }
1957 _firmwarePlugin->guidedModeChangeGroundSpeedMetersSecond(this, groundspeed);
1958}
1959
1960void
1962{
1963 if (!_vehicleSupports->guidedMode()) {
1965 return;
1966 }
1967 _firmwarePlugin->guidedModeChangeEquivalentAirspeedMetersSecond(this, airspeed);
1968}
1969
1970void Vehicle::guidedModeOrbit(const QGeoCoordinate& centerCoord, double radius, double amslAltitude)
1971{
1972 if (!_vehicleSupports->orbitMode()) {
1973 QGC::showAppMessage(tr("Orbit mode not supported by Vehicle."));
1974 return;
1975 }
1976 if (capabilityBits() & MAV_PROTOCOL_CAPABILITY_COMMAND_INT) {
1979 MAV_CMD_DO_ORBIT,
1980 MAV_FRAME_GLOBAL,
1981 true, // show error if fails
1982 static_cast<float>(radius),
1983 static_cast<float>(qQNaN()), // Use default velocity
1984 static_cast<float>(ORBIT_YAW_BEHAVIOUR_UNCHANGED), // Use current or vehicle default yaw behavior
1985 static_cast<float>(qQNaN()), // Use vehicle default num of orbits behavior
1986 centerCoord.latitude(), centerCoord.longitude(), static_cast<float>(amslAltitude));
1987 } else {
1990 MAV_CMD_DO_ORBIT,
1991 true, // show error if fails
1992 static_cast<float>(radius),
1993 static_cast<float>(qQNaN()), // Use default velocity
1994 static_cast<float>(ORBIT_YAW_BEHAVIOUR_UNCHANGED), // Use current or vehicle default yaw behavior
1995 static_cast<float>(qQNaN()), // Use vehicle default num of orbits behavior
1996 static_cast<float>(centerCoord.latitude()),
1997 static_cast<float>(centerCoord.longitude()),
1998 static_cast<float>(amslAltitude));
1999 }
2000}
2001
2002bool Vehicle::guidedModeROI(const QGeoCoordinate& centerCoord, double relativeAltitudeMeters)
2003{
2004 if (!centerCoord.isValid()) {
2005 return false;
2006 }
2007 if (!_vehicleSupports->roiMode()) {
2008 QGC::showAppMessage(tr("ROI mode not supported by Vehicle."));
2009 return false;
2010 }
2011
2012 if (!qIsFinite(relativeAltitudeMeters)) {
2013 relativeAltitudeMeters = 0;
2014 }
2015
2016 if (!_firmwarePlugin->guidedModeROI(this, centerCoord, relativeAltitudeMeters)) {
2017 return false;
2018 }
2019
2020 if (_roiRelativeAltitudeMeters != relativeAltitudeMeters) {
2021 _roiRelativeAltitudeMeters = relativeAltitudeMeters;
2023 }
2024
2025 // This is picked by qml to display coordinate over map
2026 emit roiCoordChanged(centerCoord);
2027 return true;
2028}
2029
2031{
2032 if (!_vehicleSupports->roiMode()) {
2033 QGC::showAppMessage(tr("ROI mode not supported by Vehicle."));
2034 return;
2035 }
2036 if (capabilityBits() & MAV_PROTOCOL_CAPABILITY_COMMAND_INT) {
2039 MAV_CMD_DO_SET_ROI_NONE,
2040 MAV_FRAME_GLOBAL,
2041 true, // show error if fails
2042 static_cast<float>(qQNaN()), // Empty
2043 static_cast<float>(qQNaN()), // Empty
2044 static_cast<float>(qQNaN()), // Empty
2045 static_cast<float>(qQNaN()), // Empty
2046 static_cast<double>(qQNaN()), // Empty
2047 static_cast<double>(qQNaN()), // Empty
2048 static_cast<float>(qQNaN())); // Empty
2049 } else {
2052 MAV_CMD_DO_SET_ROI_NONE,
2053 true, // show error if fails
2054 static_cast<float>(qQNaN()), // Empty
2055 static_cast<float>(qQNaN()), // Empty
2056 static_cast<float>(qQNaN()), // Empty
2057 static_cast<float>(qQNaN()), // Empty
2058 static_cast<float>(qQNaN()), // Empty
2059 static_cast<float>(qQNaN()), // Empty
2060 static_cast<float>(qQNaN())); // Empty
2061 }
2062}
2063
2064void Vehicle::guidedModeChangeHeading(const QGeoCoordinate &headingCoord)
2065{
2066 if (!_vehicleSupports->changeHeading()) {
2067 QGC::showAppMessage(tr("Change Heading not supported by Vehicle."));
2068 return;
2069 }
2070
2071 _firmwarePlugin->guidedModeChangeHeading(this, headingCoord);
2072}
2073
2075{
2076 if (!_vehicleSupports->pauseVehicle()) {
2077 QGC::showAppMessage(tr("Pause not supported by vehicle."));
2078 return;
2079 }
2080 _firmwarePlugin->pauseVehicle(this);
2081}
2082
2083void Vehicle::abortLanding(double climbOutAltitude)
2084{
2087 MAV_CMD_DO_GO_AROUND,
2088 true, // show error if fails
2089 static_cast<float>(climbOutAltitude));
2090}
2091
2093{
2094 return _firmwarePlugin->isGuidedMode(this);
2095}
2096
2097void Vehicle::setGuidedMode(bool guidedMode)
2098{
2099 return _firmwarePlugin->setGuidedMode(this, guidedMode);
2100}
2101
2103{
2104 return fixedWing() || _vtolInFwdFlight;
2105}
2106
2107
2109{
2111 _defaultComponentId,
2112 MAV_CMD_COMPONENT_ARM_DISARM,
2113 true, // show error if fails
2114 0.0f,
2115 21196.0f); // Magic number for emergency stop
2116}
2117
2119{
2122 MAV_CMD_AIRFRAME_CONFIGURATION,
2123 true, // show error if fails
2124 -1.0f, // all gears
2125 0.0f); // down
2126}
2127
2129{
2132 MAV_CMD_AIRFRAME_CONFIGURATION,
2133 true, // show error if fails
2134 -1.0f, // all gears
2135 1.0f); // up
2136}
2137
2139{
2140 if (!_firmwarePlugin->sendHomePositionToVehicle()) {
2141 seq--;
2142 }
2143
2144 // send the mavlink command (created in Jan 2019)
2146 [this,seq]() { // lambda function which uses the deprecated mission_set_current
2147 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
2148 if (!sharedLink) {
2149 qCDebug(VehicleLog) << "setCurrentMissionSequence: primary link gone!";
2150 return;
2151 }
2152
2154
2155 // send mavlink message (deprecated since Aug 2022).
2156 mavlink_msg_mission_set_current_pack_chan(
2157 static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
2158 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
2159 sharedLink->mavlinkChannel(),
2160 &msg,
2161 static_cast<uint8_t>(id()),
2162 _compID,
2163 static_cast<uint16_t>(seq));
2164 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
2165 },
2166 static_cast<uint8_t>(defaultComponentId()),
2167 MAV_CMD_DO_SET_MISSION_CURRENT,
2168 true, // showError
2169 static_cast<uint16_t>(seq)
2170 );
2171}
2172
2173void Vehicle::sendMavCommand(int compId, MAV_CMD command, bool showError, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
2174{
2175 _mavCmdQueue->sendCommand(compId, command, showError, param1, param2, param3, param4, param5, param6, param7);
2176}
2177
2178void Vehicle::sendMavCommandDelayed(int compId, MAV_CMD command, bool showError, int milliseconds, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
2179{
2180 _mavCmdQueue->sendCommandDelayed(compId, command, showError, milliseconds, param1, param2, param3, param4, param5, param6, param7);
2181}
2182
2183void Vehicle::sendCommand(int compId, int command, bool showError, double param1, double param2, double param3, double param4, double param5, double param6, double param7)
2184{
2186 compId, static_cast<MAV_CMD>(command),
2187 showError,
2188 static_cast<float>(param1),
2189 static_cast<float>(param2),
2190 static_cast<float>(param3),
2191 static_cast<float>(param4),
2192 static_cast<float>(param5),
2193 static_cast<float>(param6),
2194 static_cast<float>(param7));
2195}
2196
2197void Vehicle::sendMavCommandWithHandler(const MavCmdAckHandlerInfo_t* ackHandlerInfo, int compId, MAV_CMD command, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
2198{
2199 _mavCmdQueue->sendCommandWithHandler(ackHandlerInfo, compId, command, param1, param2, param3, param4, param5, param6, param7);
2200}
2201
2202void Vehicle::sendMavCommandInt(int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
2203{
2204 _mavCmdQueue->sendCommandInt(compId, command, frame, showError, param1, param2, param3, param4, param5, param6, param7);
2205}
2206
2207void Vehicle::sendMavCommandIntWithHandler(const MavCmdAckHandlerInfo_t* ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
2208{
2209 _mavCmdQueue->sendCommandIntWithHandler(ackHandlerInfo, compId, command, frame, param1, param2, param3, param4, param5, param6, param7);
2210}
2211
2212void Vehicle::sendMavCommandWithLambdaFallback(std::function<void()> lambda, int compId, MAV_CMD command, bool showError, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
2213{
2214 _mavCmdQueue->sendCommandWithLambdaFallback(std::move(lambda), compId, command, showError, param1, param2, param3, param4, param5, param6, param7);
2215}
2216
2217void Vehicle::sendMavCommandIntWithLambdaFallback(std::function<void()> lambda, int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
2218{
2219 _mavCmdQueue->sendCommandIntWithLambdaFallback(std::move(lambda), compId, command, frame, showError, param1, param2, param3, param4, param5, param6, param7);
2220}
2221
2222bool Vehicle::isMavCommandPending(int targetCompId, MAV_CMD command)
2223{
2224 return _mavCmdQueue->isPending(targetCompId, command);
2225}
2226
2227int Vehicle::_findMavCommandListEntryIndex(int targetCompId, MAV_CMD command)
2228{
2229 return _mavCmdQueue->findEntryIndex(targetCompId, command);
2230}
2231
2236
2237void Vehicle::_handleCommandAck(mavlink_message_t& message)
2238{
2240 mavlink_msg_command_ack_decode(&message, &ack);
2241
2242 QString rawCommandName = MissionCommandTree::instance()->rawName(static_cast<MAV_CMD>(ack.command));
2243 QString logMsg = QStringLiteral("_handleCommandAck command(%1) result(%2)").arg(rawCommandName).arg(QGCMAVLink::mavResultToString(static_cast<MAV_RESULT>(ack.result)));
2244
2245 // For REQUEST_MESSAGE commands, also log which message was requested.
2246 if (ack.command == MAV_CMD_REQUEST_MESSAGE) {
2247 const int entryIndex = _mavCmdQueue->findEntryIndex(message.compid, static_cast<MAV_CMD>(ack.command));
2248 if (entryIndex != -1) {
2249 // The message id was sent as param1 of MAV_CMD_REQUEST_MESSAGE. We can't read it back
2250 // from the queue without exposing entry internals, so just log the ack summary.
2251 logMsg += QStringLiteral(" (entry=%1)").arg(entryIndex);
2252 }
2253 }
2254
2255 qCDebug(VehicleLog) << logMsg;
2256
2257 // Vehicle-level side effects that must fire regardless of queue-match state.
2258 if (ack.command == MAV_CMD_DO_SET_ROI_LOCATION && ack.result == MAV_RESULT_ACCEPTED) {
2259 _isROIEnabled = true;
2260 emit isROIEnabledChanged();
2261 }
2262 if (ack.command == MAV_CMD_DO_SET_ROI_NONE && ack.result == MAV_RESULT_ACCEPTED) {
2263 _isROIEnabled = false;
2264 emit isROIEnabledChanged();
2265 }
2266 if (ack.command == MAV_CMD_PREFLIGHT_STORAGE) {
2267 emit sensorsParametersResetAck(ack.result == MAV_RESULT_ACCEPTED);
2268 }
2269 if (ack.command == MAV_CMD_FLASH_BOOTLOADER && ack.result == MAV_RESULT_ACCEPTED) {
2270 QGC::showAppMessage(tr("Bootloader flash succeeded"));
2271 }
2272
2273 // Delegate queue-matching + user callbacks to MavCommandQueue.
2274 _mavCmdQueue->handleCommandAck(message, ack);
2275
2276 // Advance PID tuning setup/teardown.
2277 if (ack.command == MAV_CMD_SET_MESSAGE_INTERVAL) {
2278 _mavlinkStreamConfig->gotSetMessageIntervalAck();
2279 }
2280}
2281
2282void Vehicle::requestMessage(RequestMessageResultHandler resultHandler, void* resultHandlerData, int compId, int messageId, float param1, float param2, float param3, float param4, float param5)
2283{
2284 _reqMsgCoord->requestMessage(resultHandler, resultHandlerData, compId, messageId, param1, param2, param3, param4, param5);
2285}
2286
2287
2288void Vehicle::setPrearmError(const QString& prearmError)
2289{
2290 _prearmError = prearmError;
2291 emit prearmErrorChanged(_prearmError);
2292 if (!_prearmError.isEmpty()) {
2293 _prearmErrorTimer.start();
2294 }
2295}
2296
2297void Vehicle::_prearmErrorTimeout()
2298{
2299 setPrearmError(QString());
2300}
2301
2302void Vehicle::setFirmwareVersion(int majorVersion, int minorVersion, int patchVersion, FIRMWARE_VERSION_TYPE versionType)
2303{
2304 _firmwareMajorVersion = majorVersion;
2305 _firmwareMinorVersion = minorVersion;
2306 _firmwarePatchVersion = patchVersion;
2307 _firmwareVersionType = versionType;
2309}
2310
2311void Vehicle::setFirmwareCustomVersion(int majorVersion, int minorVersion, int patchVersion)
2312{
2313 _firmwareCustomMajorVersion = majorVersion;
2314 _firmwareCustomMinorVersion = minorVersion;
2315 _firmwareCustomPatchVersion = patchVersion;
2317}
2318
2320{
2321 return QGCMAVLink::firmwareVersionTypeToString(_firmwareVersionType);
2322}
2323
2324void Vehicle::_rebootCommandResultHandler(void* resultHandlerData, int /*compId*/, const mavlink_command_ack_t& ack, MavCmdResultFailureCode_t failureCode)
2325{
2326 Vehicle* vehicle = static_cast<Vehicle*>(resultHandlerData);
2327
2328 if (ack.result != MAV_RESULT_ACCEPTED) {
2329 switch (failureCode) {
2331 qCDebug(VehicleLog) << QStringLiteral("MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN error(%1)").arg(ack.result);
2332 break;
2334 qCDebug(VehicleLog) << "MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN failed: no response from vehicle";
2335 break;
2337 qCDebug(VehicleLog) << "MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN failed: duplicate command";
2338 break;
2339 }
2340 QGC::showAppMessage(tr("Vehicle reboot failed."));
2341 } else {
2342 vehicle->closeVehicle();
2343 }
2344}
2345
2347{
2348 Vehicle::MavCmdAckHandlerInfo_t handlerInfo = {};
2349 handlerInfo.resultHandler = _rebootCommandResultHandler;
2350 handlerInfo.resultHandlerData = this;
2351
2352 sendMavCommandWithHandler(&handlerInfo, _defaultComponentId, MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN, 1);
2353}
2354
2356{
2357 if (_rebootRequired) {
2358 return;
2359 }
2360
2361 _rebootRequired = true;
2362 emit rebootRequiredChanged();
2363}
2364
2365void Vehicle::setNewStableFirmwareVersion(const QString& version)
2366{
2367 if (_newStableFirmwareVersion == version) {
2368 return;
2369 }
2370
2371 _newStableFirmwareVersion = version;
2372 _newStableFirmwareVersionAcknowledged = _isNewStableFirmwareVersionAcknowledged();
2374}
2375
2377{
2378 if (_newStableFirmwareVersion.isEmpty() || _newStableFirmwareVersionAcknowledged) {
2379 return;
2380 }
2381
2382 QSettings().setValue(_acknowledgedStableFirmwareSettingsKey(), _newStableFirmwareVersion);
2383
2384 // The acknowledgement is shared by all vehicles of the same firmware/vehicle class
2385 const QmlObjectListModel* const vehicles = MultiVehicleManager::instance()->vehicles();
2386 for (int i = 0; i < vehicles->count(); i++) {
2387 Vehicle* const vehicle = vehicles->value<Vehicle*>(i);
2388 if (vehicle && !vehicle->_newStableFirmwareVersionAcknowledged &&
2389 vehicle->_isNewStableFirmwareVersionAcknowledged()) {
2390 vehicle->_newStableFirmwareVersionAcknowledged = true;
2391 emit vehicle->newStableFirmwareVersionChanged();
2392 }
2393 }
2394}
2395
2396bool Vehicle::_isNewStableFirmwareVersionAcknowledged() const
2397{
2398 const QString acknowledgedVersion = QSettings().value(_acknowledgedStableFirmwareSettingsKey()).toString();
2399 return !_newStableFirmwareVersion.isEmpty() &&
2400 !FirmwarePlugin::isStableFirmwareVersionUnseen(_newStableFirmwareVersion, acknowledgedVersion);
2401}
2402
2403QString Vehicle::_acknowledgedStableFirmwareSettingsKey() const
2404{
2405 return QStringLiteral("AcknowledgedStableFirmware/") + FirmwarePlugin::stableFirmwareSettingsKey(this);
2406}
2407
2409{
2410 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
2411 if (!sharedLink) {
2412 qCDebug(VehicleLog) << "startCalibration: primary link gone!";
2413 return;
2414 }
2415
2416 float param1 = 0;
2417 float param2 = 0;
2418 float param3 = 0;
2419 float param4 = 0;
2420 float param5 = 0;
2421 float param6 = 0;
2422 float param7 = 0;
2423
2424 switch (calType) {
2426 param1 = 1;
2427 break;
2429 param2 = 1;
2430 break;
2432 param4 = 1;
2433 break;
2435 param4 = 2;
2436 break;
2438 param5 = 1;
2439 break;
2441 param5 = 2;
2442 break;
2444 param7 = 1;
2445 break;
2447 param6 = 2; // 1 is deprecated by PX4, still accepted but 2 is the standard value
2448 break;
2450 param3 = 1;
2451 break;
2453 param6 = 1;
2454 break;
2456 param3 = 1;
2457 break;
2459 param3 = 1; // GroundPressure/Airspeed
2460 if (multiRotor() || rover()) {
2461 // Gyro cal for ArduCopter only
2462 param1 = 1;
2463 }
2464 break;
2466 param5 = 4;
2467 break;
2469 default:
2470 break;
2471 }
2472
2473 // We can't use sendMavCommand here since we have no idea how long it will be before the command returns a result. This in turn
2474 // causes the retry logic to break down.
2476 mavlink_msg_command_long_pack_chan(MAVLinkProtocol::instance()->getSystemId(),
2478 sharedLink->mavlinkChannel(),
2479 &msg,
2480 id(),
2481 defaultComponentId(), // target component
2482 MAV_CMD_PREFLIGHT_CALIBRATION, // command id
2483 0, // 0=first transmission of command
2484 param1, param2, param3, param4, param5, param6, param7);
2485 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
2486}
2487
2488void Vehicle::stopCalibration(bool showError)
2489{
2490 sendMavCommand(defaultComponentId(), // target component
2491 MAV_CMD_PREFLIGHT_CALIBRATION, // command id
2492 showError,
2493 0, // gyro cal
2494 0, // mag cal
2495 0, // ground pressure
2496 0, // radio cal
2497 0, // accel cal
2498 0, // airspeed cal
2499 0); // unused
2500}
2501
2502void Vehicle::setSoloFirmware(bool soloFirmware)
2503{
2504 if (soloFirmware != _soloFirmware) {
2505 _soloFirmware = soloFirmware;
2507 }
2508}
2509
2510void Vehicle::motorTest(int motor, int percent, int timeoutSecs, bool showError)
2511{
2512 sendMavCommand(_defaultComponentId, MAV_CMD_DO_MOTOR_TEST, showError, motor, MOTOR_TEST_THROTTLE_PERCENT, percent, timeoutSecs, 0, MOTOR_TEST_ORDER_BOARD);
2513}
2514
2516{
2517 if (_offlineEditingVehicle) {
2518 _defaultComponentId = defaultComponentId;
2519 } else {
2520 qCWarning(VehicleLog) << "Call to Vehicle::setOfflineEditingDefaultComponentId on vehicle which is not offline";
2521 }
2522}
2523
2524void Vehicle::setVtolInFwdFlight(bool vtolInFwdFlight)
2525{
2526 if (_vtolInFwdFlight != vtolInFwdFlight) {
2527 sendMavCommand(_defaultComponentId,
2528 MAV_CMD_DO_VTOL_TRANSITION,
2529 true, // show errors
2530 vtolInFwdFlight ? MAV_VTOL_STATE_FW : MAV_VTOL_STATE_MC, // transition state
2531 0, 0, 0, 0, 0, 0); // param 2-7 unused
2532 }
2533}
2534
2536{
2537 sendMavCommand(_defaultComponentId, MAV_CMD_LOGGING_START, false /* showError */);
2538}
2539
2541{
2542 sendMavCommand(_defaultComponentId, MAV_CMD_LOGGING_STOP, false /* showError */);
2543}
2544
2545void Vehicle::_ackMavlinkLogData(uint16_t sequence)
2546{
2547 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
2548 if (!sharedLink) {
2549 qCDebug(VehicleLog) << "_ackMavlinkLogData: primary link gone!";
2550 return;
2551 }
2552
2554 mavlink_logging_ack_t ack;
2555
2556 memset(&ack, 0, sizeof(ack));
2557 ack.sequence = sequence;
2558 ack.target_component = _defaultComponentId;
2559 ack.target_system = id();
2560 mavlink_msg_logging_ack_encode_chan(
2561 MAVLinkProtocol::instance()->getSystemId(),
2563 sharedLink->mavlinkChannel(),
2564 &msg,
2565 &ack);
2566 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
2567}
2568
2569void Vehicle::_handleMavlinkLoggingData(mavlink_message_t& message)
2570{
2571 mavlink_logging_data_t log;
2572 mavlink_msg_logging_data_decode(&message, &log);
2573 if (static_cast<size_t>(log.length) > sizeof(log.data)) {
2574 qWarning() << "Invalid length for LOGGING_DATA, discarding." << log.length;
2575 } else {
2576 emit mavlinkLogData(this, log.target_system, log.target_component, log.sequence,
2577 log.first_message_offset, QByteArray((const char*)log.data, log.length), false);
2578 }
2579}
2580
2581void Vehicle::_handleMavlinkLoggingDataAcked(mavlink_message_t& message)
2582{
2583 mavlink_logging_data_acked_t log;
2584 mavlink_msg_logging_data_acked_decode(&message, &log);
2585 _ackMavlinkLogData(log.sequence);
2586 if (static_cast<size_t>(log.length) > sizeof(log.data)) {
2587 qWarning() << "Invalid length for LOGGING_DATA_ACKED, discarding." << log.length;
2588 } else {
2589 emit mavlinkLogData(this, log.target_system, log.target_component, log.sequence,
2590 log.first_message_offset, QByteArray((const char*)log.data, log.length), false);
2591 }
2592}
2593
2595{
2596 firmwarePluginInstanceData->setParent(this);
2597 _firmwarePluginInstanceData = firmwarePluginInstanceData;
2598}
2599
2601{
2602 return _firmwarePlugin->missionFlightMode();
2603}
2604
2606{
2607 return _firmwarePlugin->pauseFlightMode();
2608}
2609
2611{
2612 return _firmwarePlugin->rtlFlightMode();
2613}
2614
2616{
2617 return _firmwarePlugin->smartRTLFlightMode();
2618}
2619
2621{
2622 return _firmwarePlugin->landFlightMode();
2623}
2624
2626{
2627 return _firmwarePlugin->takeControlFlightMode();
2628}
2629
2631{
2632 return _firmwarePlugin->followFlightMode();
2633}
2634
2636{
2637 return _firmwarePlugin->motorDetectionFlightMode();
2638}
2639
2641{
2642 return _firmwarePlugin->stabilizedFlightMode();
2643}
2644
2646{
2647 if(_firmwarePlugin)
2648 return _firmwarePlugin->vehicleImageOpaque(this);
2649 else
2650 return QString();
2651}
2652
2654{
2655 if(_firmwarePlugin)
2656 return _firmwarePlugin->vehicleImageOutline(this);
2657 else
2658 return QString();
2659}
2660
2661const QVariantList& Vehicle::toolIndicators()
2662{
2663 if(_firmwarePlugin) {
2664 return _firmwarePlugin->toolIndicators(this);
2665 }
2666 static QVariantList emptyList;
2667 return emptyList;
2668}
2669
2670void Vehicle::_setupAutoDisarmSignalling()
2671{
2672 QString param = _firmwarePlugin->autoDisarmParameter(this);
2673
2674 if (!param.isEmpty() && _parameterManager->parameterExists(ParameterManager::defaultComponentId, param)) {
2675 Fact* fact = _parameterManager->getParameter(ParameterManager::defaultComponentId,param);
2676 connect(fact, &Fact::rawValueChanged, this, &Vehicle::autoDisarmChanged);
2677 emit autoDisarmChanged();
2678 }
2679}
2680
2682{
2683 QString param = _firmwarePlugin->autoDisarmParameter(this);
2684
2685 if (!param.isEmpty() && _parameterManager->parameterExists(ParameterManager::defaultComponentId, param)) {
2686 Fact* fact = _parameterManager->getParameter(ParameterManager::defaultComponentId,param);
2687 return fact->rawValue().toDouble() > 0;
2688 }
2689
2690 return false;
2691}
2692
2693void Vehicle::_updateDistanceHeadingHome()
2694{
2695 if (coordinate().isValid() && homePosition().isValid()) {
2697 if (_distanceToHomeFact.rawValue().toDouble() > 1.0) {
2700 } else {
2703 }
2704 } else {
2708 }
2709}
2710
2711void Vehicle::_updateHeadingToNextWP()
2712{
2713 const int currentIndex = _missionManager->currentIndex();
2714 QList<MissionItem*> llist = _missionManager->missionItems();
2715
2716 if(llist.size()>currentIndex && currentIndex!=-1
2717 && llist[currentIndex]->coordinate().longitude()!=0.0
2718 && coordinate().distanceTo(llist[currentIndex]->coordinate())>5.0 ){
2719
2720 _headingToNextWPFact.setRawValue(coordinate().azimuthTo(llist[currentIndex]->coordinate()));
2721 }
2722 else{
2724 }
2725}
2726
2727void Vehicle::_updateMissionItemIndex()
2728{
2729 const int currentIndex = _missionManager->currentIndex();
2730
2731 unsigned offset = 0;
2732 if (!_firmwarePlugin->sendHomePositionToVehicle()) {
2733 offset = 1;
2734 }
2735
2736 _missionItemIndexFact.setRawValue(currentIndex + offset);
2737}
2738
2739void Vehicle::_updateDistanceHeadingGCS()
2740{
2741 QGeoCoordinate gcsPosition = GPSManager::instance()->positionManager()->gcsPosition();
2742 if (coordinate().isValid() && gcsPosition.isValid()) {
2743 _distanceToGCSFact.setRawValue(coordinate().distanceTo(gcsPosition));
2744 _headingFromGCSFact.setRawValue(gcsPosition.azimuthTo(coordinate()));
2745 } else {
2748 }
2749}
2750
2751void Vehicle::_updateHomepoint()
2752{
2753 const bool setHomeCmdSupported = firmwarePlugin()->supportedMissionCommands(vehicleClass()).contains(MAV_CMD_DO_SET_HOME);
2754 const bool updateHomeActivated = SettingsManager::instance()->flyViewSettings()->updateHomePosition()->rawValue().toBool();
2755 if(setHomeCmdSupported && updateHomeActivated){
2756 QGeoCoordinate gcsPosition = GPSManager::instance()->positionManager()->gcsPosition();
2757 if (coordinate().isValid() && gcsPosition.isValid()) {
2759 MAV_CMD_DO_SET_HOME, false,
2760 0,
2761 0, 0, 0,
2762 static_cast<float>(gcsPosition.latitude()) ,
2763 static_cast<float>(gcsPosition.longitude()),
2764 static_cast<float>(gcsPosition.altitude()));
2765 }
2766 }
2767}
2768
2769void Vehicle::_updateHobbsMeter()
2770{
2772}
2773
2775{
2776 _initialPlanRequestComplete = true;
2778}
2779
2780void Vehicle::sendPlan(QString planFile)
2781{
2783}
2784
2786{
2787 return _firmwarePlugin->getHobbsMeter(this);
2788}
2789
2790void Vehicle::_vehicleParamLoaded(bool ready)
2791{
2792 //-- TODO: This seems silly but can you think of a better
2793 // way to update this?
2794 if(ready) {
2795 emit hobbsMeterChanged();
2796 }
2797}
2798
2799void Vehicle::_mavlinkMessageStatus(int uasId, uint64_t totalSent, uint64_t totalReceived, uint64_t totalLoss, float lossPercent)
2800{
2801 if(uasId == _systemID) {
2802 _mavlinkSentCount = totalSent;
2803 _mavlinkReceivedCount = totalReceived;
2804 _mavlinkLossCount = totalLoss;
2805 _mavlinkLossPercent = lossPercent;
2806 emit mavlinkStatusChanged();
2807 }
2808}
2809
2810int Vehicle::versionCompare(const QString& compare) const
2811{
2812 return _firmwarePlugin->versionCompare(this, compare);
2813}
2814
2815int Vehicle::versionCompare(int major, int minor, int patch) const
2816{
2817 return _firmwarePlugin->versionCompare(this, major, minor, patch);
2818}
2819
2821{
2822 bool liveUpdate = mode != ModeDisabled;
2823 setLiveUpdates(liveUpdate);
2827
2828 switch (mode) {
2829 case ModeDisabled:
2830 _mavlinkStreamConfig->restoreDefaults();
2831 break;
2833 _mavlinkStreamConfig->setHighRateRateAndAttitude();
2834 break;
2836 _mavlinkStreamConfig->setHighRateVelAndPos();
2837 break;
2839 _mavlinkStreamConfig->setHighRateAltAirspeed();
2840 // reset the altitude offset to the current value, so the plotted value is around 0
2841 if (!qIsNaN(_altitudeTuningOffset)) {
2845 }
2846 break;
2847 }
2848}
2849
2850void Vehicle::_setMessageInterval(int messageId, int rate)
2851{
2853 MAV_CMD_SET_MESSAGE_INTERVAL,
2854 true, // show error
2855 messageId,
2856 rate);
2857}
2858
2859QString Vehicle::_formatMavCommand(MAV_CMD command, float param1)
2860{
2861 QString commandName = MissionCommandTree::instance()->rawName(command);
2862
2863 if (command == MAV_CMD_REQUEST_MESSAGE && param1 > 0) {
2864 const mavlink_message_info_t* info = mavlink_get_message_info_by_id(static_cast<uint32_t>(param1));
2865 QString param1Str = info ? QString("%1(%2)").arg(param1).arg(info->name) : QString::number(param1);
2866 return QString("%1: %2").arg(commandName).arg(param1Str);
2867 }
2868 return QString("%1: %2").arg(commandName).arg(param1);
2869}
2870
2875
2876void Vehicle::_initializeCsv()
2877{
2878 if (!SettingsManager::instance()->mavlinkSettings()->saveCsvTelemetry()->rawValue().toBool()) {
2879 return;
2880 }
2881 QString now = QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss");
2882 QString fileName = QString("%1 vehicle%2.csv").arg(now).arg(_systemID);
2883 QDir saveDir(SettingsManager::instance()->appSettings()->telemetrySavePath());
2884 _csvLogFile.setFileName(saveDir.absoluteFilePath(fileName));
2885
2886 if (!_csvLogFile.open(QIODevice::Append)) {
2887 qCWarning(VehicleLog) << "unable to open file for csv logging, Stopping csv logging!";
2888 return;
2889 }
2890
2891 QTextStream stream(&_csvLogFile);
2892 QStringList allFactNames;
2893 allFactNames << factNames();
2894 for (const QString& groupName: factGroupNames()) {
2895 for(const QString& factName: getFactGroup(groupName)->factNames()){
2896 allFactNames << QString("%1.%2").arg(groupName, factName);
2897 }
2898 }
2899 qCDebug(VehicleLog) << "Facts logged to csv:" << allFactNames;
2900 stream << "Timestamp," << allFactNames.join(",") << "\n";
2901}
2902
2903void Vehicle::_writeCsvLine()
2904{
2905 // Only save the logs after the the vehicle gets armed, unless "Save logs even if vehicle was not armed" is checked
2906 if(!_csvLogFile.isOpen() &&
2907 (_armed || SettingsManager::instance()->mavlinkSettings()->telemetrySaveNotArmed()->rawValue().toBool())){
2908 _initializeCsv();
2909 }
2910
2911 if(!_csvLogFile.isOpen()){
2912 return;
2913 }
2914
2915 QStringList allFactValues;
2916 QTextStream stream(&_csvLogFile);
2917
2918 // Write timestamp to csv file
2919 allFactValues << QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss.zzz"));
2920 // Write Vehicle's own facts
2921 for (const QString& factName : factNames()) {
2922 allFactValues << getFact(factName)->cookedValueString();
2923 }
2924 // write facts from Vehicle's FactGroups
2925 for (const QString& groupName: factGroupNames()) {
2926 for (const QString& factName : getFactGroup(groupName)->factNames()) {
2927 allFactValues << getFactGroup(groupName)->getFact(factName)->cookedValueString();
2928 }
2929 }
2930
2931 stream << allFactValues.join(",") << "\n";
2932}
2933
2934void Vehicle::doSetHome(const QGeoCoordinate& coord)
2935{
2937}
2938
2939void Vehicle::_handleObstacleDistance(const mavlink_message_t& message)
2940{
2942 mavlink_msg_obstacle_distance_decode(&message, &o);
2943 _objectAvoidance->update(&o);
2944}
2945
2946void Vehicle::_handleFenceStatus(const mavlink_message_t& message)
2947{
2948 mavlink_fence_status_t fenceStatus;
2949
2950 mavlink_msg_fence_status_decode(&message, &fenceStatus);
2951
2952 qCDebug(VehicleLog) << "_handleFenceStatus breach_status" << fenceStatus.breach_status;
2953
2954 static qint64 lastUpdate = 0;
2955 qint64 now = QDateTime::currentMSecsSinceEpoch();
2956 if (fenceStatus.breach_status == 1) {
2957 if (now - lastUpdate > 3000) {
2958 lastUpdate = now;
2959 QString breachTypeStr;
2960 switch (fenceStatus.breach_type) {
2961 case FENCE_BREACH_NONE:
2962 return;
2963 case FENCE_BREACH_MINALT:
2964 breachTypeStr = tr("minimum altitude");
2965 break;
2966 case FENCE_BREACH_MAXALT:
2967 breachTypeStr = tr("maximum altitude");
2968 break;
2969 case FENCE_BREACH_BOUNDARY:
2970 breachTypeStr = tr("boundary");
2971 break;
2972 default:
2973 break;
2974 }
2975
2976 _say(breachTypeStr + " " + tr("fence breached"));
2977 }
2978 } else {
2979 lastUpdate = now;
2980 }
2981}
2982
2984{
2986}
2987
2988void Vehicle::sendParamMapRC(const QString& paramName, double scale, double centerValue, int tuningID, double minValue, double maxValue)
2989{
2990 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
2991 if (!sharedLink) {
2992 qCDebug(VehicleLog) << "sendParamMapRC: primary link gone!";
2993 return;
2994 }
2995
2996 mavlink_message_t message;
2997
2998 char param_id_cstr[MAVLINK_MSG_PARAM_MAP_RC_FIELD_PARAM_ID_LEN] = {};
2999 // Copy string into buffer, ensuring not to exceed the buffer size
3000 for (unsigned int i = 0; i < sizeof(param_id_cstr); i++) {
3001 if ((int)i < paramName.length()) {
3002 param_id_cstr[i] = paramName.toLatin1()[i];
3003 }
3004 }
3005
3006 mavlink_msg_param_map_rc_pack_chan(static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
3007 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
3008 sharedLink->mavlinkChannel(),
3009 &message,
3010 _systemID,
3011 MAV_COMP_ID_AUTOPILOT1,
3012 param_id_cstr,
3013 -1, // parameter name specified as string in previous argument
3014 static_cast<uint8_t>(tuningID),
3015 static_cast<float>(centerValue),
3016 static_cast<float>(scale),
3017 static_cast<float>(minValue),
3018 static_cast<float>(maxValue));
3019 sendMessageOnLinkThreadSafe(sharedLink.get(), message);
3020}
3021
3023{
3024 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
3025 if (!sharedLink) {
3026 qCDebug(VehicleLog)<< "clearAllParamMapRC: primary link gone!";
3027 return;
3028 }
3029
3030 char param_id_cstr[MAVLINK_MSG_PARAM_MAP_RC_FIELD_PARAM_ID_LEN] = {};
3031
3032 for (int i = 0; i < 3; i++) {
3033 mavlink_message_t message;
3034 mavlink_msg_param_map_rc_pack_chan(static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
3035 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
3036 sharedLink->mavlinkChannel(),
3037 &message,
3038 _systemID,
3039 MAV_COMP_ID_AUTOPILOT1,
3040 param_id_cstr,
3041 -2, // Disable map for specified tuning id
3042 i, // tuning id
3043 0, 0, 0, 0); // unused
3044 sendMessageOnLinkThreadSafe(sharedLink.get(), message);
3045 }
3046}
3047
3048void Vehicle::sendJoystickDataThreadSafe(float roll, float pitch, float yaw, float thrust, quint16 buttons, quint16 buttons2, float pitchExtension, float rollExtension, float aux1, float aux2, float aux3, float aux4, float aux5, float aux6)
3049{
3050 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
3051 if (!sharedLink) {
3052 qCDebug(VehicleLog)<< "sendJoystickDataThreadSafe: primary link gone!";
3053 return;
3054 }
3055
3056 if (sharedLink->linkConfiguration()->isHighLatency()) {
3057 return;
3058 }
3059
3060 mavlink_message_t message;
3061
3062 float axesScaling = 1.0 * 1000.0;
3063 uint8_t extensions = 0;
3064
3065 // Incoming values are in the range -1:1
3066 float newRollCommand = roll * axesScaling;
3067 float newPitchCommand = pitch * axesScaling;
3068 float newYawCommand = yaw * axesScaling;
3069 float newThrustCommand = thrust * axesScaling;
3070
3071 // Scale and set extension bits/values
3072 float incomingExtensionValues[] = { pitchExtension, rollExtension, aux1, aux2, aux3, aux4, aux5, aux6 };
3073 int16_t outgoingExtensionValues[std::size(incomingExtensionValues)];
3074 for (size_t i = 0; i < std::size(incomingExtensionValues); i++) {
3075 int16_t scaledValue = 0;
3076 if (!qIsNaN(incomingExtensionValues[i])) {
3077 scaledValue = static_cast<int16_t>(incomingExtensionValues[i] * axesScaling);
3078 extensions |= (1 << i);
3079 }
3080 outgoingExtensionValues[i] = scaledValue;
3081 }
3082 mavlink_msg_manual_control_pack_chan(
3083 static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
3084 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
3085 sharedLink->mavlinkChannel(),
3086 &message,
3087 static_cast<uint8_t>(_systemID),
3088 static_cast<int16_t>(newPitchCommand),
3089 static_cast<int16_t>(newRollCommand),
3090 static_cast<int16_t>(newThrustCommand),
3091 static_cast<int16_t>(newYawCommand),
3092 buttons, buttons2,
3093 extensions,
3094 outgoingExtensionValues[0],
3095 outgoingExtensionValues[1],
3096 outgoingExtensionValues[2],
3097 outgoingExtensionValues[3],
3098 outgoingExtensionValues[4],
3099 outgoingExtensionValues[5],
3100 outgoingExtensionValues[6],
3101 outgoingExtensionValues[7]
3102 );
3103 sendMessageOnLinkThreadSafe(sharedLink.get(), message);
3104}
3105
3106// Sends RC_CHANNELS_OVERRIDE for joystick aux axes mapped to RC channels 5–10 only.
3107// Channels 1–4 (attitude axes) always carry UINT16_MAX (ignore) and channels 11–18 are unused.
3108void Vehicle::sendJoystickAuxRcOverrideThreadSafe(const std::array<uint16_t, kAuxRcOverrideChannelCount> &channelValues, const std::array<bool, kAuxRcOverrideChannelCount> &channelEnabled, bool useRcOverride)
3109{
3110 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
3111 if (!sharedLink) {
3112 qCDebug(VehicleLog) << "sendJoystickAuxRcOverrideThreadSafe: primary link gone!";
3113 return;
3114 }
3115
3116 if (sharedLink->linkConfiguration()->isHighLatency()) {
3117 return;
3118 }
3119
3120 bool anyEnabledChannel = false;
3121 for (bool enabled : channelEnabled) {
3122 if (enabled) {
3123 anyEnabledChannel = true;
3124 break;
3125 }
3126 }
3127
3128 if (!useRcOverride || !anyEnabledChannel) {
3129 // Atomically transition true → false so only one thread sends the release packet.
3130 bool expected = true;
3131 if (!_joystickAuxRcOverrideActive.compare_exchange_strong(expected, false)) {
3132 return;
3133 }
3134
3135 mavlink_message_t releaseMessage;
3136 mavlink_msg_rc_channels_override_pack_chan(
3137 static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
3138 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
3139 sharedLink->mavlinkChannel(),
3140 &releaseMessage,
3141 static_cast<uint8_t>(_systemID),
3142 static_cast<uint8_t>(_defaultComponentId),
3143 UINT16_MAX, // chan1: ignore (not overriding attitude axes)
3144 UINT16_MAX, // chan2: ignore
3145 UINT16_MAX, // chan3: ignore
3146 UINT16_MAX, // chan4: ignore
3147 0, // chan5: release (MAVLink standard: 0 = release override)
3148 0, // chan6: release
3149 0, // chan7: release
3150 0, // chan8: release
3151 static_cast<uint16_t>(UINT16_MAX - 1), // chan9: release (extension field: UINT16_MAX-1 = release)
3152 static_cast<uint16_t>(UINT16_MAX - 1), // chan10: release
3153 0, // chan11–18: not used
3154 0,
3155 0,
3156 0,
3157 0,
3158 0,
3159 0,
3160 0);
3161 sendMessageOnLinkThreadSafe(sharedLink.get(), releaseMessage);
3162 return;
3163 }
3164
3165 mavlink_message_t message;
3166 mavlink_msg_rc_channels_override_pack_chan(
3167 static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
3168 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
3169 sharedLink->mavlinkChannel(),
3170 &message,
3171 static_cast<uint8_t>(_systemID),
3172 static_cast<uint8_t>(_defaultComponentId),
3173 UINT16_MAX, // chan1: ignore (not overriding attitude axes)
3174 UINT16_MAX, // chan2: ignore
3175 UINT16_MAX, // chan3: ignore
3176 UINT16_MAX, // chan4: ignore
3177 channelEnabled[0] ? channelValues[0] : static_cast<uint16_t>(0), // chan5: value or release
3178 channelEnabled[1] ? channelValues[1] : static_cast<uint16_t>(0), // chan6: value or release
3179 channelEnabled[2] ? channelValues[2] : static_cast<uint16_t>(0), // chan7: value or release
3180 channelEnabled[3] ? channelValues[3] : static_cast<uint16_t>(0), // chan8: value or release
3181 channelEnabled[4] ? channelValues[4] : static_cast<uint16_t>(UINT16_MAX - 1), // chan9: value or release (extension field)
3182 channelEnabled[5] ? channelValues[5] : static_cast<uint16_t>(UINT16_MAX - 1), // chan10: value or release (extension field)
3183 0, // chan11–18: not used
3184 0,
3185 0,
3186 0,
3187 0,
3188 0,
3189 0,
3190 0);
3191 sendMessageOnLinkThreadSafe(sharedLink.get(), message);
3192 _joystickAuxRcOverrideActive = true;
3193}
3194
3196{
3197 sendMavCommand(_defaultComponentId,
3198 MAV_CMD_DO_DIGICAM_CONTROL,
3199 true, // show errors
3200 0.0, 0.0, 0.0, 0.0, // param 1-4 unused
3201 1.0); // trigger camera
3202}
3203
3204void Vehicle::sendGripperAction(GRIPPER_ACTIONS gripperAction)
3205{
3207 _defaultComponentId,
3208 MAV_CMD_DO_GRIPPER,
3209 true, // Show errors
3210 0, // Param1: Gripper ID (Always set to 0)
3211 gripperAction); // Param2: Gripper Action
3212}
3213
3214void Vehicle::setEstimatorOrigin(const QGeoCoordinate& centerCoord)
3215{
3216 // Prefer MAV_CMD_DO_SET_GLOBAL_ORIGIN (sent as COMMAND_INT, supersedes SET_GPS_GLOBAL_ORIGIN).
3218 [this, centerCoord]() { // fallback: deprecated SET_GPS_GLOBAL_ORIGIN message
3220 },
3222 MAV_CMD_DO_SET_GLOBAL_ORIGIN,
3223 MAV_FRAME_GLOBAL,
3224 false, // showError
3225 0.0f, 0.0f, 0.0f, 0.0f, // param 1-4 empty
3226 centerCoord.latitude(), // param5: latitude (deg) -> degE7
3227 centerCoord.longitude(), // param6: longitude (deg) -> degE7
3228 static_cast<float>(centerCoord.altitude()) // param7: altitude (m)
3229 );
3230}
3231
3232void Vehicle::setEstimatorOrigin_SET_GPS_GLOBAL_ORIGIN(const QGeoCoordinate& centerCoord)
3233{
3234 SharedLinkInterfacePtr sharedLink = vehicleLinkManager()->primaryLink().lock();
3235 if (!sharedLink) {
3236 qCDebug(VehicleLog) << "setEstimatorOrigin: primary link gone!";
3237 return;
3238 }
3239
3241 mavlink_msg_set_gps_global_origin_pack_chan(
3242 MAVLinkProtocol::instance()->getSystemId(),
3244 sharedLink->mavlinkChannel(),
3245 &msg,
3246 id(),
3247 centerCoord.latitude() * 1e7,
3248 centerCoord.longitude() * 1e7,
3249 centerCoord.altitude() * 1e3,
3250 static_cast<float>(qQNaN())
3251 );
3252 sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
3253}
3254
3255void Vehicle::pairRX(int rxType, int rxSubType)
3256{
3257 sendMavCommand(_defaultComponentId,
3258 MAV_CMD_START_RX_PAIR,
3259 true,
3260 rxType,
3261 rxSubType);
3262}
3263
3265{
3266 _timerRevertAllowTakeover.stop();
3267 _timerRevertAllowTakeover.setSingleShot(true);
3268 _timerRevertAllowTakeover.setInterval(operatorControlTakeoverTimeoutMsecs());
3269 // Disconnect any previous connections to avoid multiple handlers
3270 disconnect(&_timerRevertAllowTakeover, &QTimer::timeout, nullptr, nullptr);
3271
3272 connect(&_timerRevertAllowTakeover, &QTimer::timeout, this, [this](){
3273 if (MAVLinkProtocol::instance()->getSystemId() == _gcsMain) {
3274 this->requestOperatorControl(false);
3275 }
3276 });
3277 _timerRevertAllowTakeover.start();
3278}
3279
3280void Vehicle::requestOperatorControl(bool allowOverride, int requestTimeoutSecs)
3281{
3282 int safeRequestTimeoutSecs;
3283 int requestTimeoutSecsMin = SettingsManager::instance()->flyViewSettings()->requestControlTimeout()->cookedMin().toInt();
3284 int requestTimeoutSecsMax = SettingsManager::instance()->flyViewSettings()->requestControlTimeout()->cookedMax().toInt();
3285 if (requestTimeoutSecs >= requestTimeoutSecsMin && requestTimeoutSecs <= requestTimeoutSecsMax) {
3286 safeRequestTimeoutSecs = requestTimeoutSecs;
3287 } else {
3288 // If out of limits use default value
3289 safeRequestTimeoutSecs = SettingsManager::instance()->flyViewSettings()->requestControlTimeout()->cookedDefaultValue().toInt();
3290 }
3291
3292 const MavCmdAckHandlerInfo_t handlerInfo = {&Vehicle::_requestOperatorControlAckHandler, this, nullptr, nullptr};
3294 &handlerInfo,
3295 _defaultComponentId,
3296 MAV_CMD_REQUEST_OPERATOR_CONTROL,
3297 0, // System ID of GCS requesting control, 0 if it is this GCS
3298 1, // Action - 0: Release control, 1: Request control.
3299 allowOverride ? 1 : 0, // Allow takeover - Enable automatic granting of ownership on request. 0: Ask current owner and reject request, 1: Allow automatic takeover.
3300 safeRequestTimeoutSecs // Timeout in seconds before a request to a GCS to allow takeover is assumed to be rejected. This is used to display the timeout graphically on requestor and GCS in control.
3301 );
3302
3303 // If this is a request we sent to other GCS, start timer so User can not keep sending requests until the current timeout expires
3304 if (requestTimeoutSecs > 0) {
3305 requestOperatorControlStartTimer(requestTimeoutSecs * 1000);
3306 }
3307}
3308
3309void Vehicle::_requestOperatorControlAckHandler(void* resultHandlerData, int compId, const mavlink_command_ack_t& ack, MavCmdResultFailureCode_t failureCode)
3310{
3311 // For the moment, this will always come from an autopilot, compid 1
3312 Q_UNUSED(compId);
3313
3314 // If duplicated or no response, show popup to user. Otherwise only log it.
3315 switch (failureCode) {
3317 QGC::showAppMessage(tr("Waiting for previous operator control request"));
3318 return;
3320 QGC::showAppMessage(tr("No response to operator control request"));
3321 return;
3322 default:
3323 break;
3324 }
3325
3326 Vehicle* vehicle = static_cast<Vehicle*>(resultHandlerData);
3327 if (!vehicle) {
3328 return;
3329 }
3330
3331 if (ack.result == MAV_RESULT_ACCEPTED) {
3332 qCDebug(VehicleLog) << "Operator control request accepted";
3333 } else {
3334 qCDebug(VehicleLog) << "Operator control request rejected";
3335 }
3336}
3337
3338void Vehicle::requestOperatorControlStartTimer(int requestTimeoutMsecs)
3339{
3340 // First flag requests not allowed
3341 _sendControlRequestAllowed = false;
3343 // Setup timer to re enable it again after timeout
3344 _timerRequestOperatorControl.stop();
3345 _timerRequestOperatorControl.setSingleShot(true);
3346 _timerRequestOperatorControl.setInterval(requestTimeoutMsecs);
3347 // Disconnect any previous connections to avoid multiple handlers
3348 disconnect(&_timerRequestOperatorControl, &QTimer::timeout, nullptr, nullptr);
3349 connect(&_timerRequestOperatorControl, &QTimer::timeout, this, [this](){
3350 _sendControlRequestAllowed = true;
3352 });
3353 _timerRequestOperatorControl.start();
3354}
3355
3356void Vehicle::_handleControlStatus(const mavlink_message_t& message)
3357{
3358 mavlink_control_status_t controlStatus;
3359 mavlink_msg_control_status_decode(&message, &controlStatus);
3360
3361 bool updateControlStatusSignals = false;
3362 if (_gcsControlStatusFlags != controlStatus.flags) {
3363 _gcsControlStatusFlags = controlStatus.flags;
3364 _gcsControlStatusFlags_SystemManager = controlStatus.flags & GCS_CONTROL_STATUS_FLAGS_SYSTEM_MANAGER;
3365 _gcsControlStatusFlags_TakeoverAllowed = controlStatus.flags & GCS_CONTROL_STATUS_FLAGS_TAKEOVER_ALLOWED;
3366 updateControlStatusSignals = true;
3367 }
3368
3369 if (_gcsMain != controlStatus.gcs_main) {
3370 _gcsMain = controlStatus.gcs_main;
3371 updateControlStatusSignals = true;
3372 }
3373
3374 if (!_firstControlStatusReceived) {
3375 _firstControlStatusReceived = true;
3376 updateControlStatusSignals = true;
3377 }
3378
3379 if (updateControlStatusSignals) {
3381 }
3382
3383 // If we were waiting for a request to be accepted and now it was accepted, adjust flags accordingly so
3384 // UI unlocks the request/take control button
3385 if (!sendControlRequestAllowed() && _gcsControlStatusFlags_TakeoverAllowed) {
3386 disconnect(&_timerRequestOperatorControl, &QTimer::timeout, nullptr, nullptr);
3387 _sendControlRequestAllowed = true;
3389 }
3390}
3391
3392void Vehicle::_handleCommandRequestOperatorControl(const mavlink_command_long_t commandLong)
3393{
3394 emit requestOperatorControlReceived(commandLong.param1, commandLong.param3, commandLong.param4);
3395}
3396
3397void Vehicle::_handleCommandLong(const mavlink_message_t& message)
3398{
3399 mavlink_command_long_t commandLong;
3400 mavlink_msg_command_long_decode(&message, &commandLong);
3401 // Ignore command if it is not targeted for us
3402 if (commandLong.target_system != MAVLinkProtocol::instance()->getSystemId()) {
3403 return;
3404 }
3405 if (commandLong.command == MAV_CMD_REQUEST_OPERATOR_CONTROL) {
3406 _handleCommandRequestOperatorControl(commandLong);
3407 }
3408}
3409
3410int Vehicle::operatorControlTakeoverTimeoutMsecs() const
3411{
3413}
3414
3415int32_t Vehicle::getMessageRate(uint8_t compId, uint16_t msgId)
3416{
3417 return _messageIntervalManager->getMessageRate(compId, msgId);
3418}
3419
3420void Vehicle::setMessageRate(uint8_t compId, uint16_t msgId, int32_t rate)
3421{
3422 _messageIntervalManager->setMessageRate(compId, msgId, rate);
3423}
3424
3425QVariant Vehicle::expandedToolbarIndicatorSource(const QString& indicatorName)
3426{
3427 return _firmwarePlugin->expandedToolbarIndicatorSource(this, indicatorName);
3428}
3429
3434
3439
3440/*===========================================================================*/
3441/* ardupilotmega Dialect */
3442/*===========================================================================*/
3443
3445{
3446 if (apmFirmware()) {
3449 MAV_CMD_FLASH_BOOTLOADER,
3450 true, // show error
3451 0, 0, 0, 0, // param 1-4 not used
3452 290876); // magic number
3453 }
3454}
3455
3457{
3458 if (apmFirmware()) {
3461 MAV_CMD_DO_AUX_FUNCTION,
3462 true,
3464 enable ? MAV_CMD_DO_AUX_FUNCTION_SWITCH_LEVEL_HIGH : MAV_CMD_DO_AUX_FUNCTION_SWITCH_LEVEL_LOW);
3465 }
3466}
3467
3468/*---------------------------------------------------------------------------*/
3469/*===========================================================================*/
3470/* Status Text Handler */
3471/*===========================================================================*/
3472
3474{
3475 m_statusTextHandler->clearMessages();
3476}
3477
3479{
3480 return m_statusTextHandler->criticalMessageCount();
3481}
3482QString Vehicle::formattedMessages() const { return m_statusTextHandler->formattedMessages(); }
3483
3484void Vehicle::_createStatusTextHandler()
3485{
3486 m_statusTextHandler = new StatusTextHandler(this);
3487 (void) connect(m_statusTextHandler, &StatusTextHandler::criticalMessageCountChanged, this,
3489 (void) connect(m_statusTextHandler, &StatusTextHandler::newFormattedMessage, this, &Vehicle::newFormattedMessage);
3490 (void) connect(m_statusTextHandler, &StatusTextHandler::textMessageReceived, this, &Vehicle::_textMessageReceived);
3491 (void) connect(m_statusTextHandler, &StatusTextHandler::newErrorMessage, this, &Vehicle::_errorMessageReceived);
3492}
3493
3494void Vehicle::_onStatusTextFromEvent(uint8_t compid, int severity, const QString &text, const QString &description)
3495{
3496 m_statusTextHandler->handleHTMLEscapedTextMessage(static_cast<MAV_COMPONENT>(compid),
3497 static_cast<MAV_SEVERITY>(severity), text, description);
3498}
3499
3500void Vehicle::_textMessageReceived(MAV_COMPONENT componentid, MAV_SEVERITY severity, QString text, QString description)
3501{
3502 // PX4 backwards compatibility: messages sent out ending with a tab are also sent as event
3503 if (px4Firmware() && text.endsWith('\t')) {
3504 qCDebug(VehicleLog) << "Dropping message (expected as event):" << text;
3505 return;
3506 }
3507
3508 bool skipSpoken = false;
3509 const bool ardupilotPrearm = text.startsWith(QStringLiteral("PreArm"));
3510 const bool px4Prearm = text.startsWith(QStringLiteral("preflight"), Qt::CaseInsensitive) && (severity >= MAV_SEVERITY::MAV_SEVERITY_CRITICAL);
3511 if (ardupilotPrearm || px4Prearm) {
3512 if (_healthAndArmingChecksSupported(componentid)) {
3513 qCDebug(VehicleLog) << "Dropping preflight message (expected as event):" << text;
3514 return;
3515 }
3516
3517 // Limit repeated PreArm message to once every 10 seconds
3518 if (_noisySpokenPrearmMap.contains(text) && _noisySpokenPrearmMap.value(text).msecsTo(QTime::currentTime()) < (10 * 1000)) {
3519 skipSpoken = true;
3520 } else {
3521 (void) _noisySpokenPrearmMap.insert(text, QTime::currentTime());
3522 setPrearmError(text);
3523 }
3524 }
3525
3526 bool readAloud = false;
3527
3528 if (text.startsWith("#")) {
3529 (void) text.remove(0, 1);
3530 readAloud = true;
3531 } else if (severity <= MAV_SEVERITY::MAV_SEVERITY_NOTICE) {
3532 readAloud = true;
3533 }
3534
3535 if (readAloud && !skipSpoken) {
3536 _say(text);
3537 }
3538
3539 emit textMessageReceived(id(), componentid, severity, text, description);
3540 m_statusTextHandler->handleHTMLEscapedTextMessage(componentid, severity, text.toHtmlEscaped(), description);
3541}
3542
3543void Vehicle::_errorMessageReceived(QString message)
3544{
3545 QString vehicleIdPrefix;
3546
3547 if (MultiVehicleManager::instance()->vehicles()->count() > 1) {
3548 vehicleIdPrefix = tr("Vehicle %1: ").arg(id());
3549 }
3550 QGC::showCriticalVehicleMessage(vehicleIdPrefix + message);
3551}
3552
3553/*---------------------------------------------------------------------------*/
3554/*===========================================================================*/
3555/* Signing */
3556/*===========================================================================*/
3557
3558void Vehicle::_createSigningController()
3559{
3560 _signingController = new VehicleSigningController(this);
3561}
3562
3563/*---------------------------------------------------------------------------*/
3564/*===========================================================================*/
3565/* Image Protocol Manager */
3566/*===========================================================================*/
3567
3568void Vehicle::_createImageProtocolManager()
3569{
3570 _imageProtocolManager = new ImageProtocolManager(this);
3571 (void) connect(_imageProtocolManager, &ImageProtocolManager::flowImageIndexChanged, this, &Vehicle::flowImageIndexChanged);
3572 (void) connect(_imageProtocolManager, &ImageProtocolManager::imageReady, this, [this](const QImage &image) {
3573 qgcApp()->qgcImageProvider()->setImage(image, _systemID);
3574 });
3575}
3576
3578{
3579 return (_imageProtocolManager ? _imageProtocolManager->flowImageIndex() : 0);
3580}
3581
3582/*---------------------------------------------------------------------------*/
3583/*===========================================================================*/
3584/* MAVLink Log Manager */
3585/*===========================================================================*/
3586
3587void Vehicle::_createMAVLinkLogManager()
3588{
3589 _mavlinkLogManager = new MAVLinkLogManager(this, this);
3590}
3591
3593{
3594 return _mavlinkLogManager;
3595}
3596
3597/*---------------------------------------------------------------------------*/
3598/*===========================================================================*/
3599/* Camera Manager */
3600/*===========================================================================*/
3601
3602void Vehicle::_createCameraManager()
3603{
3604 if (!_cameraManager && _firmwarePlugin) {
3605 _cameraManager = _firmwarePlugin->createCameraManager(this);
3606 emit cameraManagerChanged();
3607 }
3608}
3609
3610const QVariantList &Vehicle::staticCameraList() const
3611{
3612 if (_cameraManager) {
3613 return _cameraManager->cameraList();
3614 }
3615
3616 static QVariantList emptyCameraList;
3617 return emptyCameraList;
3618}
3619
3620/*---------------------------------------------------------------------------*/
3621/*===========================================================================*/
3622/* MAVLinkEventsManager */
3623/*===========================================================================*/
3624
3625void Vehicle::_createMAVLinkEventManager()
3626{
3627 _eventManager = std::make_unique<MAVLinkEventManager>(this);
3628
3629 (void) connect(_eventManager.get(), &MAVLinkEventManager::statusTextMessageFromEvent, this, &Vehicle::_onStatusTextFromEvent);
3630}
3631
3632void Vehicle::_handleEventMessage(const mavlink_message_t& msg)
3633{
3634 _eventManager->handleEventMessage(msg);
3635}
3636
3637bool Vehicle::_healthAndArmingChecksSupported(uint8_t compid)
3638{
3639 return _eventManager->healthAndArmingChecksSupported(compid);
3640}
3641
3643{
3644 return _eventManager->healthAndArmingCheckReport();
3645}
3646
3647void Vehicle::setEventsMetadata(uint8_t compid, const QString &metadataJsonFileName)
3648{
3649 _eventManager->setMetadata(compid, metadataJsonFileName);
3650
3651 sendMavCommand(_defaultComponentId, MAV_CMD_RUN_PREARM_CHECKS, false);
3652}
3653
3654/*---------------------------------------------------------------------------*/
static const QString guided_mode_not_supported_by_vehicle
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
#define qgcApp()
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
struct __mavlink_command_ack_t mavlink_command_ack_t
struct __mavlink_high_latency2_t mavlink_high_latency2_t
struct __mavlink_command_long_t mavlink_command_long_t
struct __mavlink_battery_status_t mavlink_battery_status_t
struct __mavlink_obstacle_distance_t mavlink_obstacle_distance_t
#define REQUEST_OPERATOR_CONTROL_ALLOW_TAKEOVER_TIMEOUT_MSECS
Definition Vehicle.cc:97
const QString guided_mode_not_supported_by_vehicle
Definition Vehicle.cc:99
void mavlinkMessageReceived(const mavlink_message_t &message)
static ADSBVehicleManager * instance()
void load(const QString &json_file, const QJsonDocument &metadata)
Definition Actuators.cc:113
void say(const QString &text, TextMods textMods=TextMod::None)
static AudioOutput * instance()
void handleMessageForFactGroupCreation(Vehicle *vehicle, const mavlink_message_t &message)
Allows for creation/updating of dynamic FactGroups based on incoming messages.
Used to group Facts together into an object hierarachy.
Definition FactGroup.h:16
const QMap< QString, FactGroup * > & factGroups() const
Definition FactGroup.h:46
Q_INVOKABLE Fact * getFact(const QString &name) const
Definition FactGroup.cc:72
QStringList factNames() const
Definition FactGroup.h:43
void _addFactGroup(FactGroup *factGroup, const QString &name)
Definition FactGroup.cc:133
Q_INVOKABLE FactGroup * getFactGroup(const QString &name) const
Definition FactGroup.cc:102
QStringList factGroupNames() const
Definition FactGroup.h:44
Q_INVOKABLE void setLiveUpdates(bool liveUpdates)
Turning on live updates will allow value changes to flow through as they are received.
Definition FactGroup.cc:152
static QVariant metersToAppSettingsHorizontalDistanceUnits(const QVariant &meters)
Converts from meters to the user specified horizontal distance unit.
static QString appSettingsHorizontalDistanceUnitsString()
Returns the string for horizontal distance units which has configued by user.
A Fact is used to hold a single value within the system.
Definition Fact.h:15
FactMetaData * metaData()
Definition Fact.h:172
void rawValueChanged(const QVariant &value)
void setRawValue(const QVariant &value)
Definition Fact.cc:135
QString cookedValueString() const
Definition Fact.cc:489
QVariant rawValue() const
Definition Fact.h:87
FirmwarePlugin * firmwarePluginForAutopilot(MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType)
static FirmwarePluginManager * instance()
virtual QString motorDetectionFlightMode() const
Returns the flight mode for Motor Detection.
virtual QString pauseFlightMode() const
Returns The flight mode which indicates the vehicle is paused.
virtual void guidedModeChangeEquivalentAirspeedMetersSecond(Vehicle *vehicle, double airspeed_equiv) const
virtual void guidedModeChangeAltitude(Vehicle *vehicle, double altitudeChange, bool pauseVehicle)
virtual void startMission(Vehicle *vehicle) const
Command the vehicle to start the mission.
virtual bool multiRotorCoaxialMotors(Vehicle *) const
virtual double minimumEquivalentAirspeed(Vehicle *) const
virtual const QVariantList & toolIndicators(const Vehicle *vehicle)
virtual void guidedModeChangeGroundSpeedMetersSecond(Vehicle *vehicle, double groundspeed) const
virtual bool setFlightMode(const QString &flightMode, uint8_t *base_mode, uint32_t *custom_mode) const
@ SetFlightModeCapability
FirmwarePlugin::setFlightMode method is supported.
virtual QString vehicleImageOutline(const Vehicle *) const
Return the resource file which contains the vehicle icon used in the flight view when the view is lig...
virtual void guidedModeTakeoff(Vehicle *vehicle, double takeoffAltRel) const
Command vehicle to takeoff from current location to the specified height.
virtual bool isCapable(const Vehicle *, FirmwareCapabilities) const
virtual double maximumEquivalentAirspeed(Vehicle *) const
virtual QString missionFlightMode() const
Returns the flight mode for running missions.
virtual void adjustMetaData(MAV_TYPE, FactMetaData *)
virtual bool adjustIncomingMavlinkMessage(Vehicle *, mavlink_message_t *)
virtual bool fixedWingAirSpeedLimitsAvailable(Vehicle *) const
virtual void guidedModeChangeHeading(Vehicle *vehicle, const QGeoCoordinate &headingCoord) const
Command vehicle to rotate towards specified location.
virtual QString smartRTLFlightMode() const
Returns the flight mode for Smart RTL.
virtual bool guidedModeGotoLocation(Vehicle *vehicle, const QGeoCoordinate &gotoCoord, double forwardFlightLoiterRadius=0.0) const
virtual bool multiRotorXConfig(Vehicle *) const
static QString stableFirmwareSettingsKey(const Vehicle *vehicle)
Settings key identifying the stable firmware stream (firmware + vehicle class) for this vehicle.
virtual QString takeControlFlightMode() const
Returns the flight mode to use when the operator wants to take back control from autonomouse flight.
virtual QString flightMode(uint8_t base_mode, uint32_t custom_mode) const
virtual QString vehicleImageOpaque(const Vehicle *) const
Return the resource file which contains the vehicle icon used in the flight view when the view is dar...
virtual void startTakeoff(Vehicle *vehicle) const
Command the vehicle to start a takeoff.
virtual void pauseVehicle(Vehicle *vehicle) const
virtual QVariant expandedToolbarIndicatorSource(const Vehicle *, const QString &) const
virtual bool mulirotorSpeedLimitsAvailable(Vehicle *) const
int versionCompare(const Vehicle *vehicle, const QString &compare) const
virtual bool hasGripper(const Vehicle *) const
virtual QString landFlightMode() const
Returns the flight mode for Land.
virtual QString gotoFlightMode() const
Returns the flight mode which the vehicle will be in if it is performing a goto location.
virtual Autotune * createAutotune(Vehicle *vehicle) const
Creates Autotune object.
static bool isStableFirmwareVersionUnseen(const QString &latestVersion, const QString &seenVersion)
virtual QStringList flightModes(Vehicle *) const
virtual AutoPilotPlugin * autopilotPlugin(Vehicle *vehicle) const
virtual void guidedModeRTL(Vehicle *vehicle, bool smartRTL) const
Command vehicle to return to launch.
virtual QList< MAV_CMD > supportedMissionCommands(QGCMAVLinkTypes::VehicleClass_t) const
List of supported mission commands. Empty list for all commands supported.
virtual QString autoDisarmParameter(Vehicle *) const
virtual QString stabilizedFlightMode() const
Returns the flight mode for Stabilized.
virtual void adjustOutgoingMavlinkMessageThreadSafe(Vehicle *, LinkInterface *, mavlink_message_t *)
void toolIndicatorsChanged()
virtual void setGuidedMode(Vehicle *vehicle, bool guidedMode) const
Set guided flight mode.
virtual bool guidedModeROI(Vehicle *vehicle, const QGeoCoordinate &roiCenterCoord, double relativeAltitudeMeters) const
virtual QString followFlightMode() const
Returns the flight mode which the vehicle will be for follow me.
virtual uint32_t highLatencyCustomModeTo32Bits(uint16_t hlCustomMode) const
Convert from HIGH_LATENCY2.custom_mode value to correct 32 bit value.
virtual QGCCameraManager * createCameraManager(Vehicle *vehicle) const
Creates vehicle camera manager.
virtual QMap< QString, FactGroup * > * factGroups()
Returns a pointer to a dictionary of firmware-specific FactGroups.
virtual void initializeVehicle(Vehicle *)
Called when Vehicle is first created to perform any firmware specific setup.
virtual bool MAV_CMD_DO_SET_MODE_is_supported() const
returns true if this flight stack supports MAV_CMD_DO_SET_MODE
virtual QString rtlFlightMode() const
Returns the flight mode for RTL.
virtual double maximumHorizontalSpeedMultirotorMetersSecond(Vehicle *) const
virtual void guidedModeLand(Vehicle *vehicle) const
Command vehicle to land at current location.
virtual bool sendHomePositionToVehicle() const
virtual bool isGuidedMode(const Vehicle *) const
Returns whether the vehicle is in guided mode or not.
virtual double minimumTakeoffAltitudeMeters(Vehicle *) const
virtual QString getHobbsMeter(Vehicle *vehicle) const
gets hobbs meter from autopilot. This should be reimplmeented for each firmware
static GPSManager * instance()
Definition GPSManager.cc:67
PositionManager * positionManager() const
Definition GPSManager.h:56
This is the base class for firmware specific geofence managers.
void error(int errorCode, const QString &errorMsg)
void loadComplete(void)
Supports the Mavlink image transmission protocol (https://mavlink.io/en/services/image_transmission....
uint32_t flowImageIndex() const
void flowImageIndexChanged(uint32_t index)
void imageReady(const QImage &image)
bool activeJoystickEnabledForActiveVehicle() const
static JoystickManager * instance()
The link interface defines the interface for all links used to communicate with the ground station ap...
void sendMessageThreadSafe(mavlink_message_t &message)
virtual bool isConnected() const =0
void statusTextMessageFromEvent(uint8_t compid, int severity, const QString &text, const QString &description)
static int getComponentId()
void mavlinkMessageStatus(int sysid, uint64_t totalSent, uint64_t totalReceived, uint64_t totalLoss, float lossPercent)
void messageReceived(LinkInterface *link, const mavlink_message_t &message)
static MAVLinkProtocol * instance()
int getSystemId() const
Allows to configure a set of mavlink streams to a specific rate, and restore back to default.
Owns the COMMAND_LONG / COMMAND_INT send/retry/ack pipeline for a single Vehicle.
void sendCommandInt(int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
static QString failureCodeToString(MavCmdResultFailureCode_t failureCode)
void commandResult(int vehicleId, int targetComponent, int command, int ackResult, int failureCode)
Emitted for every terminal ack that has no user-provided resultHandler.
void sendCommandIntWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0, double param6=0.0, float param7=0.0f)
void sendCommandWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, 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)
void handleCommandAck(const mavlink_message_t &message, const mavlink_command_ack_t &ack)
Process a COMMAND_ACK — match it to a pending entry and fire callbacks.
void sendCommandDelayed(int compId, MAV_CMD command, bool showError, int milliseconds, 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)
bool isPending(int targetCompId, MAV_CMD command) const
True if a matching (targetCompId, command) is already queued or awaiting ack.
static void showCommandAckError(const mavlink_command_ack_t &ack)
void sendCommand(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)
int findEntryIndex(int targetCompId, MAV_CMD command) const
Index of a matching entry in the pending queue, or -1. Exposed for test use.
void sendCommandIntWithLambdaFallback(std::function< void()> lambda, int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0, double param6=0.0, float param7=0.0f)
void sendCommandWithLambdaFallback(std::function< void()> lambda, 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)
Tracks per-component MAVLink message intervals and mediates SET_MESSAGE_INTERVAL commands plus MESSAG...
void handleMessageInterval(const mavlink_message_t &message)
void mavlinkMsgIntervalsChanged(uint8_t compid, uint16_t msgId, int32_t rate)
void setMessageRate(uint8_t compId, uint16_t msgId, int32_t rate)
int32_t getMessageRate(uint8_t compId, uint16_t msgId)
static MissionCommandTree * instance()
QString rawName(MAV_CMD command) const
Returns the raw name for the specified command.
int currentIndex(void) const
Current mission item as reported by MISSION_CURRENT.
static MultiVehicleManager * instance()
Vehicle * activeVehicle() const
QmlObjectListModel * vehicles() const
void parameterReadyVehicleAvailableChanged(bool parameterReadyVehicleAvailable)
void activeVehicleChanged(Vehicle *activeVehicle)
void parametersReadyChanged(bool parametersReady)
static constexpr int defaultComponentId
void loadProgressChanged(float value)
void currentIndexChanged(int currentIndex)
void sendComplete(bool error)
void newMissionItemsAvailable(bool removeAllRequested)
const QList< MissionItem * > & missionItems(void)
Definition PlanManager.h:22
void error(int errorCode, const QString &errorMsg)
static void sendPlanToVehicle(Vehicle *vehicle, const QString &filename)
void gcsPositionChanged(QGeoCoordinate gcsPosition)
QGeoCoordinate gcsPosition() const
const QVariantList & cameraList() const
void showAdvancedUIChanged(bool showAdvancedUI)
static QGCCorePlugin * instance()
The QGCMapCircle represents a circular area which can be displayed on a Map control.
This is a QGeoCoordinate within a QObject such that it can be used on a QmlObjectListModel.
static QGCPressure * instance()
void progressUpdate(float progress)
bool active() const
T value(int index) const
int count() const override final
Radio link telemetry decoded from MAVLINK_MSG_ID_RADIO_STATUS.
This is the base class for firmware specific rally point managers. A rally point manager is responsib...
void loadComplete(void)
void error(int errorCode, const QString &errorMsg)
void mavlinkMessageReceived(mavlink_message_t &message)
Coordinates MAV_CMD_REQUEST_MESSAGE workflows: per-component queueing, ack/message correlation,...
void handleReceivedMessage(const mavlink_message_t &message)
void cancelRequests(void *resultHandlerData)
static QString failureCodeToString(RequestMessageResultHandlerFailureCode_t failureCode)
void requestMessage(RequestMessageResultHandler resultHandler, void *resultHandlerData, int compId, int messageId, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f)
void stop()
Clear pending state without firing callbacks (used during vehicle shutdown).
Provides access to all app settings.
static SettingsManager * instance()
VideoSettings * videoSettings() const
FlyViewSettings * flyViewSettings() const
MavlinkSettings * mavlinkSettings() const
void modesUpdated()
void availableModesMonitorReceived(uint8_t seq)
void criticalMessageCountChanged()
void handleHTMLEscapedTextMessage(MAV_COMPONENT componentid, MAV_SEVERITY severity, const QString &text, const QString &description)
void newErrorMessage(QString message)
uint32_t criticalMessageCount() const
void mavlinkMessageReceived(const mavlink_message_t &message)
void textMessageReceived(MAV_COMPONENT componentid, MAV_SEVERITY severity, QString text, QString description)
void newFormattedMessage(QString message)
QString formattedMessages() const
Class which represents sensor info from the SYS_STATUS mavlink message.
bool mavlinkMessageReceived(const mavlink_message_t &message)
Coordinates the terrain-query workflows attached to a Vehicle:
void doSetHomeWithTerrain(const QGeoCoordinate &coord)
void handleMessage(Vehicle *vehicle, const mavlink_message_t &message) override
Allows a FactGroup to parse incoming messages and fill in values.
void updateRCRSSI(uint8_t rssi)
WeakLinkInterfacePtr primaryLink() const
void mavlinkMessageReceived(LinkInterface *link, const mavlink_message_t &message)
bool containsLink(LinkInterface *link)
void update(mavlink_obstacle_distance_t *message)
Per-vehicle signing facade. Owns the wiring between Vehicle and the active SigningController (which l...
bool guidedMode() const
bool changeHeading() const
bool orbitMode() const
bool roiMode() const
bool pauseVehicle() const
Q_INVOKABLE void triggerSimpleCamera(void)
Trigger camera using MAV_CMD_DO_DIGICAM_CONTROL command.
Definition Vehicle.cc:3195
bool sub() const
Definition Vehicle.cc:1765
bool isInitialConnectComplete() const
Definition Vehicle.cc:2871
Q_INVOKABLE void guidedModeChangeAltitude(double altitudeChange, bool pauseVehicle)
Definition Vehicle.cc:1941
void _setLanding(bool landing)
Definition Vehicle.cc:1842
Vehicle(LinkInterface *link, int vehicleId, int defaultComponentId, MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType, QObject *parent=nullptr)
Definition Vehicle.cc:102
void autoDisarmChanged()
bool px4Firmware() const
Definition Vehicle.h:512
Q_INVOKABLE void motorInterlock(bool enable)
Command vehicle to Enable/Disable Motor Interlock.
Definition Vehicle.cc:3456
Q_INVOKABLE void virtualTabletJoystickValue(double roll, double pitch, double yaw, double thrust)
Definition Vehicle.cc:1729
int32_t getMessageRate(uint8_t compId, uint16_t msgId)
Definition Vehicle.cc:3415
VehicleDistanceSensorFactGroup * _distanceSensorFactGroup
Definition Vehicle.h:1128
TerrainProtocolHandler * _terrainProtocolHandler
Definition Vehicle.h:1146
void firmwareTypeChanged()
QGCMAVLink::VehicleClass_t vehicleClass(void) const
Definition Vehicle.h:447
void setInitialGCSPressure(qreal pressure)
Definition Vehicle.h:432
Q_INVOKABLE void flashBootloader()
Definition Vehicle.cc:3444
void sensorsPresentBitsChanged(int sensorsPresentBits)
void airborneChanged(bool airborne)
void defaultHoverSpeedChanged(double hoverSpeed)
friend class InitialConnectStateMachine
Definition Vehicle.h:105
const QString _vibrationFactGroupName
Definition Vehicle.h:1105
bool _multirotor_speed_limits_available
Definition Vehicle.h:1096
void gcsControlStatusChanged()
void defaultCruiseSpeedChanged(double cruiseSpeed)
const QString _gpsFactGroupName
Definition Vehicle.h:1102
FactGroup * localPositionFactGroup()
Definition Vehicle.cc:425
void setActuatorsMetadata(uint8_t compid, const QString &metadataJsonFileName, const QJsonDocument &metadataJson)
Definition Vehicle.cc:1276
void haveMRSpeedLimChanged()
FactGroup * vibrationFactGroup()
Definition Vehicle.cc:420
void sendMavCommandWithLambdaFallback(std::function< void()> lambda, 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:2212
BatteryFactGroupListModel * _batteryFactGroupListModel
Definition Vehicle.h:1143
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
VehicleLocalPositionFactGroup * _localPositionFactGroup
Definition Vehicle.h:1129
const QString _hygrometerFactGroupName
Definition Vehicle.h:1114
void messagesLostChanged()
Q_INVOKABLE void rebootVehicle()
Reboot vehicle.
Definition Vehicle.cc:2346
VehicleRPMFactGroup * _rpmFactGroup
Definition Vehicle.h:1135
const QString _localPositionFactGroupName
Definition Vehicle.h:1110
VehicleGPSFactGroup * _gps2FactGroup
Definition Vehicle.h:1122
void vtolInFwdFlightChanged(bool vtolInFwdFlight)
QString missionFlightMode() const
Definition Vehicle.cc:2600
void readyToFlyAvailableChanged(bool readyToFlyAvailable)
void forceInitialPlanRequestComplete()
Definition Vehicle.cc:2774
void isROIEnabledChanged()
Q_INVOKABLE void guidedModeOrbit(const QGeoCoordinate &centerCoord, double radius, double amslAltitude)
Definition Vehicle.cc:1970
const QString _terrainFactGroupName
Definition Vehicle.h:1113
Actuators * _actuators
Definition Vehicle.h:1154
const QString _temperatureFactGroupName
Definition Vehicle.h:1106
void _offlineVehicleTypeSettingChanged(QVariant varVehicleType)
Definition Vehicle.cc:498
Q_INVOKABLE void guidedModeTakeoff(double altitudeRelative)
Command vehicle to takeoff from current location.
Definition Vehicle.cc:1873
Q_INVOKABLE void sendGripperAction(GRIPPER_ACTIONS gripperOption)
Definition Vehicle.cc:3204
QString flightMode() const
Definition Vehicle.cc:1485
static QString mavCmdResultFailureCodeToString(MavCmdResultFailureCode_t failureCode)
Definition Vehicle.cc:3435
void setNewStableFirmwareVersion(const QString &version)
Definition Vehicle.cc:2365
QString stabilizedFlightMode() const
Definition Vehicle.cc:2640
const QVariantList & staticCameraList() const
Definition Vehicle.cc:3610
void requestOperatorControlReceived(int sysIdRequestingControl, int allowTakeover, int requestTimeoutSecs)
Q_INVOKABLE QVariant expandedToolbarIndicatorSource(const QString &indicatorName)
Definition Vehicle.cc:3425
void sendJoystickAuxRcOverrideThreadSafe(const std::array< uint16_t, kAuxRcOverrideChannelCount > &channelValues, const std::array< bool, kAuxRcOverrideChannelCount > &channelEnabled, bool useRcOverride)
Definition Vehicle.cc:3108
bool vtol() const
Definition Vehicle.cc:1780
void setSoloFirmware(bool soloFirmware)
Definition Vehicle.cc:2502
void requestDataStream(MAV_DATA_STREAM stream, uint16_t rate, bool sendMultiple=true)
Definition Vehicle.cc:1546
FactGroup * rpmFactGroup()
Definition Vehicle.cc:432
QGeoCoordinate homePosition()
Definition Vehicle.cc:1451
const QString _estimatorStatusFactGroupName
Definition Vehicle.h:1112
const QString _radioStatusFactGroupName
Definition Vehicle.h:1118
QString vehicleImageOutline() const
Definition Vehicle.cc:2653
MissionManager * _missionManager
Definition Vehicle.h:1148
VehicleLocalPositionSetpointFactGroup * _localPositionSetpointFactGroup
Definition Vehicle.h:1130
void textMessageReceived(int sysid, int componentid, int severity, QString text, QString description)
void initialPlanRequestCompleteChanged(bool initialPlanRequestComplete)
Q_INVOKABLE double minimumEquivalentAirspeed()
Definition Vehicle.cc:1899
const QString _clockFactGroupName
Definition Vehicle.h:1107
bool rover() const
Definition Vehicle.cc:1760
bool multiRotor() const
Definition Vehicle.cc:1775
Q_INVOKABLE void stopGuidedModeROI()
Definition Vehicle.cc:2030
void firmwareCustomVersionChanged()
QString pauseFlightMode() const
Definition Vehicle.cc:2605
QString prearmError() const
Definition Vehicle.h:491
EscStatusFactGroupListModel * _escStatusFactGroupListModel
Definition Vehicle.h:1144
float latitude()
Definition Vehicle.h:510
const QString _efiFactGroupName
Definition Vehicle.h:1116
void inFwdFlightChanged()
void setFirmwarePluginInstanceData(FirmwarePluginInstanceData *firmwarePluginInstanceData)
Definition Vehicle.cc:2594
Q_INVOKABLE double maximumHorizontalSpeedMultirotorMetersSecond()
Definition Vehicle.cc:1887
bool hasGripper() const
Definition Vehicle.cc:1904
void sendMessageMultiple(mavlink_message_t message)
Definition Vehicle.cc:1604
void capabilityBitsChanged(uint64_t capabilityBits)
void _setHomePosition(QGeoCoordinate &homeCoord)
Definition Vehicle.cc:1199
void hobbsMeterChanged()
bool airborne() const
Definition Vehicle.h:521
VehicleClockFactGroup * _clockFactGroup
Definition Vehicle.h:1126
uint64_t capabilityBits() const
Definition Vehicle.h:727
int criticalMessageCount() const
Definition Vehicle.cc:3478
Q_INVOKABLE void abortLanding(double climbOutAltitude)
Command vehicle to abort landing.
Definition Vehicle.cc:2083
void setGuidedMode(bool guidedMode)
Definition Vehicle.cc:2097
void readyToFlyChanged(bool readyToFy)
QString firmwareVersionTypeString() const
Definition Vehicle.cc:2319
QString landFlightMode() const
Definition Vehicle.cc:2620
static void showCommandAckError(const mavlink_command_ack_t &ack)
Definition Vehicle.cc:2232
void newFormattedMessage(QString formattedMessage)
MAV_TYPE vehicleType() const
Definition Vehicle.h:446
VehicleLinkManager * vehicleLinkManager()
Definition Vehicle.h:597
void cameraManagerChanged()
void underwayChanged(bool underway)
Q_INVOKABLE void sendParamMapRC(const QString &paramName, double scale, double centerValue, int tuningID, double minValue, double maxValue)
Sends PARAM_MAP_RC message to vehicle.
Definition Vehicle.cc:2988
HealthAndArmingCheckReport * healthAndArmingCheckReport()
Definition Vehicle.cc:3642
void armedChanged(bool armed)
void firmwareVersionChanged()
FactGroup * distanceSensorFactGroup()
Definition Vehicle.cc:424
void logEntry(uint32_t time_utc, uint32_t size, uint16_t id, uint16_t num_logs, uint16_t last_log_num)
void sendControlRequestAllowedChanged(bool sendControlRequestAllowed)
void hasGripperChanged()
FactGroup * generatorFactGroup()
Definition Vehicle.cc:430
void rcChannelsRawChanged(QVector< int > channelValues)
Q_INVOKABLE void acknowledgeNewStableFirmwareVersion()
Hides the update indicator until a newer stable firmware is released.
Definition Vehicle.cc:2376
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
Definition Vehicle.h:462
void sendMavCommandInt(int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
Definition Vehicle.cc:2202
Q_INVOKABLE double minimumTakeoffAltitudeMeters()
Definition Vehicle.cc:1882
InitialConnectStateMachine * _initialConnectStateMachine
Definition Vehicle.h:1153
void sensorsParametersResetAck(bool success)
void sendMavCommandDelayed(int compId, MAV_CMD command, bool showError, int milliseconds, 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:2178
bool guidedMode() const
Definition Vehicle.cc:2092
void setEstimatorOrigin_SET_GPS_GLOBAL_ORIGIN(const QGeoCoordinate &centerCoord)
Fallback for setEstimatorOrigin which sends the deprecated SET_GPS_GLOBAL_ORIGIN message.
Definition Vehicle.cc:3232
const QString _distanceSensorFactGroupName
Definition Vehicle.h:1109
Q_INVOKABLE double maximumEquivalentAirspeed()
Definition Vehicle.cc:1893
PIDTuningTelemetryMode
Definition Vehicle.h:388
@ ModeDisabled
Definition Vehicle.h:389
@ ModeAltitudeAndAirspeed
Definition Vehicle.h:392
@ ModeVelocityAndPosition
Definition Vehicle.h:391
@ ModeRateAndAttitude
Definition Vehicle.h:390
void setPrearmError(const QString &prearmError)
Definition Vehicle.cc:2288
VehicleGPSFactGroup * gpsFactGroup()
Definition Vehicle.cc:410
bool landing() const
Definition Vehicle.h:523
VehicleVibrationFactGroup * _vibrationFactGroup
Definition Vehicle.h:1124
~Vehicle()
Definition Vehicle.cc:387
void setFirmwareCustomVersion(int majorVersion, int minorVersion, int patchVersion)
Definition Vehicle.cc:2311
Q_INVOKABLE void startTimerRevertAllowTakeover()
Definition Vehicle.cc:3264
VehicleGeneratorFactGroup * _generatorFactGroup
Definition Vehicle.h:1133
const QString _generatorFactGroupName
Definition Vehicle.h:1115
void messagesSentChanged()
Q_INVOKABLE void sendPlan(QString planFile)
Definition Vehicle.cc:2780
bool vtolInFwdFlight() const
Definition Vehicle.h:526
Q_INVOKABLE void startMission()
Definition Vehicle.cc:1915
bool isMavCommandPending(int targetCompId, MAV_CMD command)
isMavCommandPending Query whether the specified MAV_CMD is in queue to be sent or has already been se...
Definition Vehicle.cc:2222
void capabilitiesKnownChanged(bool capabilitiesKnown)
Q_INVOKABLE void requestOperatorControl(bool allowOverride, int requestTimeoutSecs=0)
Definition Vehicle.cc:3280
void rcChannelsClampedChanged(QVector< int > channelValues)
VehicleEstimatorStatusFactGroup * _estimatorStatusFactGroup
Definition Vehicle.h:1131
VehicleTemperatureFactGroup * _temperatureFactGroup
Definition Vehicle.h:1125
bool soloFirmware() const
Definition Vehicle.h:697
void coordinateChanged(QGeoCoordinate coordinate)
QString vehicleImageOpaque() const
Definition Vehicle.cc:2645
float _altitudeTuningOffset
Definition Vehicle.h:1093
Q_INVOKABLE void setPIDTuningTelemetryMode(PIDTuningTelemetryMode mode)
Definition Vehicle.cc:2820
void setRebootRequired()
Latches rebootRequired until the vehicle reboots.
Definition Vehicle.cc:2355
void mavlinkLogData(Vehicle *vehicle, uint8_t target_system, uint8_t target_component, uint16_t sequence, uint8_t first_message, QByteArray data, bool acked)
Q_INVOKABLE void emergencyStop()
Command vehicle to kill all motors no matter what state.
Definition Vehicle.cc:2108
void updateFlightDistance(double distance)
Definition Vehicle.cc:2983
int id() const
Definition Vehicle.h:443
Q_INVOKABLE bool guidedModeGotoLocation(const QGeoCoordinate &gotoCoord, double forwardFlightLoiterRadius=0.0f)
Definition Vehicle.cc:1920
void pairRX(int rxType, int rxSubType)
Definition Vehicle.cc:3255
const QString _setpointFactGroupName
Definition Vehicle.h:1108
Q_INVOKABLE void setCurrentMissionSequence(int seq)
Alter the current mission item on the vehicle.
Definition Vehicle.cc:2138
void toolIndicatorsChanged()
void roiRelativeAltitudeMetersChanged()
void sensorsUnhealthyBitsChanged(int sensorsUnhealthyBits)
void landingChanged(bool landing)
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
Definition Vehicle.cc:1401
VehicleWindFactGroup * _windFactGroup
Definition Vehicle.h:1123
bool inFwdFlight() const
Definition Vehicle.cc:2102
const QString _rpmFactGroupName
Definition Vehicle.h:1117
FactGroup * hygrometerFactGroup()
Definition Vehicle.cc:429
static const MAV_AUTOPILOT MAV_AUTOPILOT_TRACK
Definition Vehicle.h:127
Q_INVOKABLE void startTakeoff()
Definition Vehicle.cc:1909
VehicleHygrometerFactGroup * _hygrometerFactGroup
Definition Vehicle.h:1132
void setFlightMode(const QString &flightMode)
Definition Vehicle.cc:1495
Q_INVOKABLE void sendCommand(int compId, int command, bool showError, double param1=0.0, double param2=0.0, double param3=0.0, double param4=0.0, double param5=0.0, double param6=0.0, double param7=0.0)
Same as sendMavCommand but available from Qml.
Definition Vehicle.cc:2183
void loadProgressChanged(float value)
QString smartRTLFlightMode() const
Definition Vehicle.cc:2615
QString followFlightMode() const
Definition Vehicle.cc:2630
bool _fixed_wing_airspeed_limits_available
Definition Vehicle.h:1097
Q_INVOKABLE void motorTest(int motor, int percent, int timeoutSecs, bool showError)
Definition Vehicle.cc:2510
void mavlinkMessageReceived(const mavlink_message_t &message)
void setMessageRate(uint8_t compId, uint16_t msgId, int32_t rate)
Definition Vehicle.cc:3420
Q_INVOKABLE void resetCounters()
< Non-empty when vehicle firmware is older than this stable version
Definition Vehicle.cc:521
const QVariantList & toolIndicators()
Definition Vehicle.cc:2661
void _offlineFirmwareTypeSettingChanged(QVariant varFirmwareType)
Definition Vehicle.cc:485
FactGroup * localPositionSetpointFactGroup()
Definition Vehicle.cc:426
Q_INVOKABLE void guidedModeChangeEquivalentAirspeedMetersSecond(double airspeed)
Definition Vehicle.cc:1961
QmlObjectListModel * escs()
Definition Vehicle.cc:436
void guidedModeChanged(bool guidedMode)
FactGroup * efiFactGroup()
Definition Vehicle.cc:431
void setEventsMetadata(uint8_t compid, const QString &metadataJsonFileName)
Definition Vehicle.cc:3647
QString formattedMessages() const
Definition Vehicle.cc:3482
int _findMavCommandListEntryIndex(int targetCompId, MAV_CMD command)
Test-only helper: forwards to MavCommandQueue::findEntryIndex.
Definition Vehicle.cc:2227
bool autoDisarm()
Definition Vehicle.cc:2681
QObject * sysStatusSensorInfo()
Definition Vehicle.cc:438
QString motorDetectionFlightMode() const
Definition Vehicle.cc:2635
void sendMavCommandIntWithLambdaFallback(std::function< void()> lambda, int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0, double param6=0.0, float param7=0.0f)
Definition Vehicle.cc:2217
void rebootRequiredChanged()
bool coaxialMotors()
Definition Vehicle.cc:1436
void orbitActiveChanged(bool orbitActive)
void allSensorsHealthyChanged(bool allSensorsHealthy)
Q_INVOKABLE void guidedModeRTL(bool smartRTL)
Command vehicle to return to launch.
Definition Vehicle.cc:1855
bool xConfigMotors()
Definition Vehicle.cc:1441
void trackFirmwareVehicleTypeChanges(void)
Definition Vehicle.cc:213
Q_INVOKABLE void landingGearDeploy()
Command vichecle to deploy landing gear.
Definition Vehicle.cc:2118
void _setUnderway(bool underway)
Definition Vehicle.cc:1824
void armedPositionChanged()
VehicleEFIFactGroup * _efiFactGroup
Definition Vehicle.h:1134
int motorCount()
Definition Vehicle.cc:1419
void stopMavlinkLog()
Definition Vehicle.cc:2540
static QString requestMessageResultHandlerFailureCodeToString(RequestMessageResultHandlerFailureCode_t failureCode)
Definition Vehicle.cc:3430
RemoteIDManager * _remoteIDManager
Definition Vehicle.h:1155
Q_INVOKABLE void doSetHome(const QGeoCoordinate &coord)
Set home from flight map coordinate.
Definition Vehicle.cc:2934
void soloFirmwareChanged(bool soloFirmware)
uint32_t flowImageIndex() const
Definition Vehicle.cc:3577
int compId() const
Definition Vehicle.h:444
void homePositionChanged(const QGeoCoordinate &homePosition)
QMap< uint8_t, uint8_t > _lowestBatteryChargeStateAnnouncedMap
Definition Vehicle.h:1091
FactGroup * radioStatusFactGroup()
Definition Vehicle.cc:433
Q_INVOKABLE bool guidedModeROI(const QGeoCoordinate &centerCoord, double relativeAltitudeMeters)
Definition Vehicle.cc:2002
Q_INVOKABLE void pauseVehicle()
Definition Vehicle.cc:2074
void stopTrackingFirmwareVehicleTypeChanges(void)
Definition Vehicle.cc:222
FactGroup * windFactGroup()
Definition Vehicle.cc:419
void flightModesChanged()
const QString _gps2FactGroupName
Definition Vehicle.h:1103
FactGroup * temperatureFactGroup()
Definition Vehicle.cc:421
bool apmFirmware() const
Definition Vehicle.h:513
Q_INVOKABLE void closeVehicle()
Removes the vehicle from the system.
Definition Vehicle.cc:440
void flightModeChanged(const QString &flightMode)
void flowImageIndexChanged()
void roiCoordChanged(const QGeoCoordinate &centerCoord)
Q_INVOKABLE void clearAllParamMapRC(void)
Clears all PARAM_MAP_RC settings from vehicle.
Definition Vehicle.cc:3022
FactGroup * estimatorStatusFactGroup()
Definition Vehicle.cc:427
Q_INVOKABLE void setEstimatorOrigin(const QGeoCoordinate &centerCoord)
Definition Vehicle.cc:3214
void setVtolInFwdFlight(bool vtolInFwdFlight)
Definition Vehicle.cc:2524
Q_INVOKABLE void guidedModeChangeGroundSpeedMetersSecond(double groundspeed)
Definition Vehicle.cc:1951
int defaultComponentId() const
Definition Vehicle.h:700
void setInitialGCSTemperature(qreal temperature)
Definition Vehicle.h:433
void mavlinkStatusChanged()
MAVLinkLogManager * mavlinkLogManager() const
Definition Vehicle.cc:3592
Q_INVOKABLE void clearMessages()
Definition Vehicle.cc:3473
VehicleGPSFactGroup * gps2FactGroup()
Definition Vehicle.cc:415
FactGroup * setpointFactGroup()
Definition Vehicle.cc:423
void sendJoystickDataThreadSafe(float roll, float pitch, float yaw, float thrust, quint16 buttons, quint16 buttons2, float pitchExtension, float rollExtension, float aux1, float aux2, float aux3, float aux4, float aux5, float aux6)
Definition Vehicle.cc:3048
QmlObjectListModel * cameraTriggerPoints()
Definition Vehicle.cc:439
FTPManager * _ftpManager
Definition Vehicle.h:1152
GeoFenceManager * _geoFenceManager
Definition Vehicle.h:1149
float longitude()
Definition Vehicle.h:511
bool flightModeSetAvailable()
Definition Vehicle.cc:1474
VehicleGPSFactGroup * _gpsFactGroup
Definition Vehicle.h:1121
void sensorsHealthBitsChanged(int sensorsHealthBits)
Q_INVOKABLE void guidedModeChangeHeading(const QGeoCoordinate &headingCoord)
Definition Vehicle.cc:2064
QString takeControlFlightMode() const
Definition Vehicle.cc:2625
void messagesReceivedChanged()
const QString _localPositionSetpointFactGroupName
Definition Vehicle.h:1111
void setOfflineEditingDefaultComponentId(int defaultComponentId)
Sets the default component id for an offline editing vehicle.
Definition Vehicle.cc:2515
bool underway() const
Definition Vehicle.h:519
void setFirmwareVersion(int majorVersion, int minorVersion, int patchVersion, FIRMWARE_VERSION_TYPE versionType=FIRMWARE_VERSION_TYPE_OFFICIAL)
Definition Vehicle.cc:2302
QString rtlFlightMode() const
Definition Vehicle.cc:2610
bool fixedWing() const
Definition Vehicle.cc:1755
void requestMessage(RequestMessageResultHandler resultHandler, void *resultHandlerData, int compId, int messageId, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f)
Definition Vehicle.cc:2282
QGeoCoordinate coordinate()
Definition Vehicle.h:427
void startCalibration(QGCMAVLink::CalibrationType calType)
Definition Vehicle.cc:2408
QVector< int > _servoOutputRawValues
Definition Vehicle.h:1140
QString firmwareTypeString() const
Definition Vehicle.cc:516
FactGroup * clockFactGroup()
Definition Vehicle.cc:422
void stopCalibration(bool showError)
Definition Vehicle.cc:2488
void newStableFirmwareVersionChanged()
friend class VehicleLinkManager
Definition Vehicle.h:106
QmlObjectListModel * batteries()
Definition Vehicle.cc:435
void haveFWSpeedLimChanged()
RallyPointManager * _rallyPointManager
Definition Vehicle.h:1150
RadioStatusFactGroup * _radioStatusFactGroup
Definition Vehicle.h:1137
QString gotoFlightMode() const
Definition Vehicle.cc:1850
void sendMavCommandIntWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0f, double param6=0.0f, float param7=0.0f)
Definition Vehicle.cc:2207
bool armed() const
Definition Vehicle.h:467
Q_INVOKABLE void landingGearRetract()
Command vichecle to retract landing gear.
Definition Vehicle.cc:2128
VehicleSupports * supports()
Definition Vehicle.h:420
const QString _windFactGroupName
Definition Vehicle.h:1104
void mavCommandResult(int vehicleId, int targetComponent, int command, int ackResult, int failureCode)
void sensorsEnabledBitsChanged(int sensorsEnabledBits)
class FirmwarePluginInstanceData * firmwarePluginInstanceData()
Definition Vehicle.h:715
VehicleSetpointFactGroup * _setpointFactGroup
Definition Vehicle.h:1127
Q_INVOKABLE int versionCompare(const QString &compare) const
Used to check if running current version is equal or higher than the one being compared.
Definition Vehicle.cc:2810
TerrainFactGroup * _terrainFactGroup
Definition Vehicle.h:1136
Q_INVOKABLE void forceArm()
Definition Vehicle.cc:1465
void requiresGpsFixChanged()
void setArmed(bool armed, bool showError)
Definition Vehicle.cc:1456
QStringList flightModes()
Definition Vehicle.cc:1479
void mavlinkMsgIntervalsChanged(uint8_t compid, uint16_t msgId, int32_t rate)
FactGroup * terrainFactGroup()
Definition Vehicle.cc:428
void mavlinkSerialControl(uint8_t device, uint8_t flags, uint16_t timeout, uint32_t baudrate, QByteArray data)
Q_INVOKABLE QString vehicleClassInternalName() const
Definition Vehicle.cc:1790
VehicleLinkManager * _vehicleLinkManager
Definition Vehicle.h:1151
void servoOutputsChanged(QVector< int > servoValues)
QString hobbsMeter()
Definition Vehicle.cc:2785
TerrainQueryCoordinator * _terrainQueryCoordinator
Definition Vehicle.h:1159
void prearmErrorChanged(const QString &prearmError)
void startMavlinkLog()
Definition Vehicle.cc:2535
void vehicleTypeChanged()
Q_INVOKABLE void guidedModeLand()
Command vehicle to land at current location.
Definition Vehicle.cc:1864
void sendMavCommandWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, 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)
Sends the command and calls the callback with the result.
Definition Vehicle.cc:2197
bool airship() const
Definition Vehicle.cc:1750
StandardModes * _standardModes
Definition Vehicle.h:1156
QString vehicleUIDStr()
Definition Vehicle.cc:1019
bool spacecraft() const
Definition Vehicle.cc:1770
friend class GimbalController
Definition Vehicle.h:114
QString vehicleTypeString() const
Definition Vehicle.cc:1785
void logData(uint32_t ofs, uint16_t id, uint8_t count, const uint8_t *data)
void criticalMessageCountChanged()
static VideoManager * instance()
Q_INVOKABLE void stopVideo()
static constexpr const char * videoSourceUDPH264
static constexpr const char * videoDisabled
@ MOTOR_INTERLOCK
Definition APM.h:35
GPSCommandSequence sequence(std::span< const Setting > settings, char port)
settings for port, each acknowledged by an ACK.
bool runningUnitTests()
bool fuzzyCompare(double value1, double value2)
Returns true if the two values are equal or close. Correctly handles 0 and NaN values.
Definition QGCMath.cc:71
void showCriticalVehicleMessage(const QString &message)
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Definition AppMessages.cc:9
Callback info bundle for sendMavCommandWithHandler.
MavCmdResultHandler resultHandler
nullptr for no handler
@ MavCmdResultFailureDuplicateCommand
Unable to send command since duplicate is already being waited on for response.
@ MavCmdResultCommandResultOnly
commandResult specifies full success/fail info
@ MavCmdResultFailureNoResponseToCommand
No response from vehicle to command.
RequestMessageResultHandlerFailureCode_t