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