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