QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GuidedActionsController.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Dialogs
4import QtLocation
5import QtPositioning
6import QtQuick.Layouts
7
8import QGroundControl
9import QGroundControl.Controls
10import QGroundControl.FlightMap
11import QGroundControl.Logging
12
13/// This provides the smarts behind the guided mode commands, minus the user interface. This way you can change UI
14/// without affecting the underlying functionality.
15Item {
16 id: _root
17
18 property var missionController
19 property var confirmDialog
20 property var guidedValueSlider
21 property var fwdFlightGotoMapCircle
22 property var orbitMapCircle
23
24 readonly property string emergencyStopTitle: qsTr("EMERGENCY STOP")
25 readonly property string armTitle: qsTr("Arm")
26 readonly property string mvArmTitle: qsTr("Arm (MV)")
27 readonly property string forceArmTitle: qsTr("Force Arm")
28 readonly property string disarmTitle: qsTr("Disarm")
29 readonly property string mvDisarmTitle: qsTr("Disarm (MV)")
30 readonly property string rtlTitle: qsTr("Return")
31 readonly property string takeoffTitle: qsTr("Takeoff")
32 readonly property string landTitle: qsTr("Land")
33 readonly property string startMissionTitle: qsTr("Start Mission")
34 readonly property string mvStartMissionTitle: qsTr("Start Mission (MV)")
35 readonly property string continueMissionTitle: qsTr("Continue Mission")
36 readonly property string resumeMissionUploadFailTitle: qsTr("Resume FAILED")
37 readonly property string pauseTitle: qsTr("Pause")
38 readonly property string mvPauseTitle: qsTr("Pause (MV)")
39 readonly property string changeAltTitle: qsTr("Change Altitude")
40 readonly property string changeLoiterRadiusTitle: qsTr("Change Loiter Radius")
41 readonly property string changeCruiseSpeedTitle: qsTr("Change Max Ground Speed")
42 readonly property string changeAirspeedTitle: qsTr("Change Airspeed")
43 readonly property string orbitTitle: qsTr("Orbit")
44 readonly property string landAbortTitle: qsTr("Land Abort")
45 readonly property string setWaypointTitle: qsTr("Set Waypoint")
46 readonly property string gotoTitle: qsTr("Go To Location")
47 readonly property string roiTitle: qsTr("ROI")
48 readonly property string setHomeTitle: qsTr("Set Home")
49 readonly property string setEstimatorOriginTitle: qsTr("Set Estimator Origin")
50 readonly property string setFlightMode: qsTr("Set Flight Mode")
51 readonly property string changeHeadingTitle: qsTr("Change Heading")
52
53 readonly property string armMessage: qsTr("Arm the vehicle.")
54 readonly property string mvArmMessage: qsTr("Arm selected vehicles.")
55 readonly property string forceArmMessage: qsTr("WARNING: This will force arming of the vehicle bypassing any safety checks.")
56 readonly property string disarmMessage: qsTr("Disarm the vehicle")
57 readonly property string mvDisarmMessage: qsTr("Disarm selected vehicles.")
58 readonly property string emergencyStopMessage: qsTr("WARNING: THIS WILL STOP ALL MOTORS. IF VEHICLE IS CURRENTLY IN THE AIR IT WILL CRASH.")
59 readonly property string takeoffMessage: qsTr("Takeoff and hold position")
60 readonly property string startMissionMessage: qsTr("Takeoff and start the current mission")
61 readonly property string mvStartMissionMessage: qsTr("Takeoff and start the current mission for selected vehicles")
62 readonly property string continueMissionMessage: qsTr("Continue the mission from the current waypoint")
63 readonly property string resumeMissionUploadFailMessage: qsTr("Upload of resume mission failed. Confirm to retry upload")
64 readonly property string landMessage: qsTr("Land the vehicle at the current position")
65 readonly property string rtlMessage: qsTr("Return to the launch position of the vehicle")
66 readonly property string changeAltMessage: qsTr("Change the altitude of the vehicle up or down")
67 readonly property string changeLoiterRadiusMessage: qsTr("Change the forward flight loiter radius")
68 readonly property string changeCruiseSpeedMessage: qsTr("Change the maximum horizontal cruise speed")
69 readonly property string changeAirspeedMessage: qsTr("Change the equivalent airspeed setpoint")
70 readonly property string gotoMessage: qsTr("Move the vehicle to the specified location")
71 property string setWaypointMessage: qsTr("Adjust current waypoint to %1").arg(_actionData)
72 readonly property string orbitMessage: qsTr("Orbit the vehicle around the specified location")
73 readonly property string landAbortMessage: qsTr("Abort the landing sequence")
74 readonly property string pauseMessage: qsTr("Pause at current position")
75 readonly property string mvPauseMessage: qsTr("Pause selected vehicles at their current position")
76 readonly property string roiMessage: qsTr("Make the specified location a Region Of Interest")
77 readonly property string setHomeMessage: qsTr("Set vehicle home as the specified location. This will affect Return to Home position")
78 readonly property string setEstimatorOriginMessage: qsTr("Make the specified location the estimator origin")
79 readonly property string setFlightModeMessage: qsTr("Set the vehicle flight mode to %1").arg(_actionData)
80 readonly property string changeHeadingMessage: qsTr("Set the vehicle heading towards the specified location")
81
82 readonly property int actionRTL: 1
83 readonly property int actionLand: 2
84 readonly property int actionTakeoff: 3
85 readonly property int actionArm: 4
86 readonly property int actionDisarm: 5
87 readonly property int actionEmergencyStop: 6
88 readonly property int actionChangeAlt: 7
89 readonly property int actionGoto: 8
90 readonly property int actionSetWaypoint: 9
91 readonly property int actionOrbit: 10
92 readonly property int actionLandAbort: 11
93 readonly property int actionStartMission: 12
94 readonly property int actionContinueMission: 13
95 readonly property int actionResumeMission: 14
96 readonly property int _actionUnused: 15
97 readonly property int actionResumeMissionUploadFail: 16
98 readonly property int actionPause: 17
99 readonly property int actionMVPause: 18
100 readonly property int actionMVStartMission: 19
101 readonly property int actionROI: 20
102 readonly property int actionForceArm: 21
103 readonly property int actionChangeSpeed: 22
104 readonly property int actionSetHome: 24
105 readonly property int actionSetEstimatorOrigin: 25
106 readonly property int actionSetFlightMode: 26
107 readonly property int actionChangeHeading: 27
108 readonly property int actionMVArm: 28
109 readonly property int actionMVDisarm: 29
110 readonly property int actionChangeLoiterRadius: 30
111
112 readonly property int customActionStart: 10000 // Custom actions ids should start here so that they don't collide with the built in actions
113
114 property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
115 property var _flyViewSettings: QGroundControl.settingsManager.flyViewSettings
116 property var _unitsConversion: QGroundControl.unitsConversion
117 property bool _useChecklist: QGroundControl.settingsManager.appSettings.useChecklist.rawValue && QGroundControl.corePlugin.options.preFlightChecklistUrl.toString().length
118 property bool _enforceChecklist: _useChecklist && QGroundControl.settingsManager.appSettings.enforceChecklist.rawValue
119 property bool _checklistPassed: _activeVehicle ? (_useChecklist ? (_enforceChecklist ? _activeVehicle.checkListState === Vehicle.CheckListPassed : true) : true) : true
120 property bool _canArm: _activeVehicle ? (_checklistPassed && (!_activeVehicle.healthAndArmingCheckReport.supported || _activeVehicle.healthAndArmingCheckReport.canArm)) : false
121 property bool _canTakeoff: _activeVehicle ? (_checklistPassed && (!_activeVehicle.healthAndArmingCheckReport.supported || _activeVehicle.healthAndArmingCheckReport.canTakeoff)) : false
122 property bool _canStartMission: _activeVehicle ? (_checklistPassed && (!_activeVehicle.healthAndArmingCheckReport.supported || _activeVehicle.healthAndArmingCheckReport.canStartMission)) : false
123 property bool _initialConnectComplete: _activeVehicle ? _activeVehicle.initialConnectComplete : false
124
125 property bool showEmergencyStop: !_hideEmergencyStop && _vehicleArmed && _vehicleAirborne
126 property bool showArm: _guidedActionsEnabled && !_vehicleArmed && _canArm
127 property bool showForceArm: _guidedActionsEnabled && !_vehicleArmed && _flyViewSettings.allowForceArm.rawValue
128 property bool showDisarm: _vehicleArmed && !_vehicleAirborne
129 property bool showRTL: _guidedActionsEnabled && _activeVehicle && _vehicleArmed && _activeVehicle.supports.guidedMode && _vehicleUnderway && !_vehicleInRTLMode
130 property bool showTakeoff: _guidedActionsEnabled && _activeVehicle && (_activeVehicle.supports.guidedTakeoffWithAltitude || _activeVehicle.supports.guidedTakeoffWithoutAltitude) && !_vehicleUnderway && _canTakeoff
131 property bool showLand: _guidedActionsEnabled && _activeVehicle && _activeVehicle.supports.guidedMode && _vehicleArmed && !_activeVehicle.fixedWing && !_vehicleInLandMode
132 property bool showStartMission: _guidedActionsEnabled && _missionAvailable && !_missionActive && !_vehicleUnderway && _canStartMission
133 property bool showContinueMission: _guidedActionsEnabled && _missionAvailable && !_missionActive && _vehicleArmed && _vehicleUnderway && (_currentMissionIndex < _visualItemsCount - 1)
134 property bool showPause: _guidedActionsEnabled && _activeVehicle && _vehicleArmed && _activeVehicle.supports.pauseVehicle && _vehicleUnderway && !_vehiclePaused && !_fixedWingOnApproach
135 property bool showChangeAlt: _guidedActionsEnabled && _activeVehicle && _vehicleUnderway && _activeVehicle.supports.guidedMode && _vehicleArmed && !_missionActive
136 property bool showChangeLoiterRadius: _guidedActionsEnabled && _activeVehicle && _vehicleUnderway && _activeVehicle.supports.guidedMode && _vehicleArmed && !_missionActive && _vehicleInFwdFlight && fwdFlightGotoMapCircle.visible
137 property bool showChangeSpeed: _guidedActionsEnabled && _activeVehicle && _vehicleUnderway && _activeVehicle.supports.guidedMode && _vehicleArmed && !_missionActive && _speedLimitsAvailable
138 property bool showOrbit: _guidedActionsEnabled && _activeVehicle && _vehicleUnderway && __orbitSupported && !_missionActive && _activeVehicle.homePosition.isValid && !isNaN(_activeVehicle.homePosition.altitude)
139 property bool showROI: _guidedActionsEnabled && _vehicleUnderway && __roiSupported
140 property bool showLandAbort: _guidedActionsEnabled && _vehicleUnderway && _fixedWingOnApproach
141 property bool showGotoLocation: _guidedActionsEnabled && _vehicleUnderway
142 property bool showSetHome: _guidedActionsEnabled
143 property bool showSetEstimatorOrigin: _activeVehicle && !(_activeVehicle.sensorsPresentBits & MAVLinkEnums.MAV_SYS_STATUS_SENSOR_GPS)
144 property bool showChangeHeading: _guidedActionsEnabled && _vehicleUnderway
145
146 property string changeSpeedTitle: _vehicleInFwdFlight ? changeAirspeedTitle : changeCruiseSpeedTitle
147 property string changeSpeedMessage: _vehicleInFwdFlight ? changeAirspeedMessage : changeCruiseSpeedMessage
148
149 // Note: The '_visualItemsCount - 2' is a hack to not trigger resume mission when a mission ends with an RTL item
150 property bool showResumeMission: _activeVehicle && !_vehicleArmed && _vehicleWasUnderway && _missionAvailable && _resumeMissionIndex > 0 && (_resumeMissionIndex < _visualItemsCount - 2)
151
152 property bool guidedUIVisible: confirmDialog.visible
153
154 property var _corePlugin: QGroundControl.corePlugin
155 property var _corePluginOptions: QGroundControl.corePlugin.options
156 property bool _guidedActionsEnabled: (!ScreenTools.isDebug && _corePluginOptions.guidedActionsRequireRCRSSI && _activeVehicle) ? _rcRSSIAvailable : _activeVehicle
157 property string _flightMode: _activeVehicle ? _activeVehicle.flightMode : ""
158 property bool _missionAvailable: missionController.containsItems
159 property bool _missionActive: _activeVehicle ? _vehicleArmed && (_vehicleInLandMode || _vehicleInRTLMode || _vehicleInMissionMode) : false
160 property bool _vehicleArmed: _activeVehicle ? _activeVehicle.armed : false
161 property bool _vehicleUnderway: _activeVehicle ? _activeVehicle.underway : false
162 // Rover/Sub are underway whenever armed but accept a normal disarm, so only airborne vehicles need emergency stop
163 property bool _vehicleAirborne: _activeVehicle ? _activeVehicle.airborne : false
164 property bool _vehicleLanding: _activeVehicle ? _activeVehicle.landing : false
165 property bool _vehiclePaused: false
166 property bool _vehicleInMissionMode: false
167 property bool _vehicleInRTLMode: false
168 property bool _vehicleInLandMode: false
169 property int _visualItemsCount: missionController.visualItems ? missionController.visualItems.count : 0
170 property int _currentMissionIndex: missionController.currentMissionIndex
171 property int _resumeMissionIndex: missionController.resumeMissionIndex
172 property bool _hideEmergencyStop: !_corePluginOptions.flyView.guidedBarShowEmergencyStop
173 property bool _hideOrbit: !_corePluginOptions.flyView.guidedBarShowOrbit
174 property bool _hideROI: !_corePluginOptions.flyView.guidedBarShowROI
175 property bool _vehicleWasUnderway: false
176 property bool _rcRSSIAvailable: _activeVehicle ? _activeVehicle.rcRSSI.rawValue > 0 && _activeVehicle.rcRSSI.rawValue <= 100 : false
177 property bool _fixedWingOnApproach: _activeVehicle ? _activeVehicle.fixedWing && _vehicleLanding : false
178 property bool _vehicleInFwdFlight: _activeVehicle ? _activeVehicle.inFwdFlight : false
179 property bool _speedLimitsAvailable: _activeVehicle && ((_vehicleInFwdFlight && _activeVehicle.haveFWSpeedLimits) || (!_vehicleInFwdFlight && _activeVehicle.haveMRSpeedLimits))
180
181 // You can turn on log output for GuidedActionsController by turning on GuidedActionsControllerLog category
182 property bool __guidedModeSupported: _activeVehicle ? _activeVehicle.supports.guidedMode : false
183 property bool __pauseVehicleSupported: _activeVehicle ? _activeVehicle.supports.pauseVehicle : false
184 property bool __roiSupported: _activeVehicle ? !_hideROI && _activeVehicle.supports.roiMode : false
185 property bool __orbitSupported: _activeVehicle ? !_hideOrbit && _activeVehicle.supports.orbitMode : false
186 property bool __flightMode: _flightMode
187
188 // Allow custom builds to add custom actions by overriding CustomGuidedActionsController.qml
189 CustomGuidedActionsController {
190 id: customController
191 }
192 property var _customController: customController
193
194 function _isGuidedActionsControllerLogEnabled() {
195 return QGCLoggingCategoryManager.isCategoryEnabled("GuidedActionsControllerLog")
196 }
197
198 function _outputState() {
199 if (_isGuidedActionsControllerLogEnabled()) {
200 console.log(qsTr("_activeVehicle(%1) _vehicleArmed(%2) guidedModeSupported(%3) _vehicleUnderway(%4) _vehicleWasUnderway(%5) _vehicleInRTLMode(%6) pauseVehicleSupported(%7) _vehiclePaused(%8) _flightMode(%9) _visualItemsCount(%10) roiSupported(%11) orbitSupported(%12) _missionActive(%13) _hideROI(%14) _hideOrbit(%15)").arg(_activeVehicle ? 1 : 0).arg(_vehicleArmed ? 1 : 0).arg(__guidedModeSupported ? 1 : 0).arg(_vehicleUnderway ? 1 : 0).arg(_vehicleWasUnderway ? 1 : 0).arg(_vehicleInRTLMode ? 1 : 0).arg(__pauseVehicleSupported ? 1 : 0).arg(_vehiclePaused ? 1 : 0).arg(_flightMode).arg(_visualItemsCount).arg(__roiSupported).arg(__orbitSupported).arg(_missionActive).arg(_hideROI).arg(_hideOrbit))
201 }
202 }
203
204 function setupSlider(actionCode) {
205 if (actionCode === actionTakeoff) {
206 guidedValueSlider.setupSlider(
207 GuidedValueSlider.SliderType.Takeoff,
208 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_activeVehicle.minimumTakeoffAltitudeMeters()),
209 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_flyViewSettings.guidedMaximumAltitude.rawValue),
210 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_activeVehicle.minimumTakeoffAltitudeMeters()),
211 qsTr("Height (rel)"))
212 } else if (actionCode === actionChangeSpeed) {
213 if (_vehicleInFwdFlight) {
214 guidedValueSlider.setupSlider(
215 GuidedValueSlider.SliderType.Speed,
216 _unitsConversion.metersSecondToAppSettingsSpeedUnits(_activeVehicle.minimumEquivalentAirspeed()).toFixed(1),
217 _unitsConversion.metersSecondToAppSettingsSpeedUnits(_activeVehicle.maximumEquivalentAirspeed()).toFixed(1),
218 _unitsConversion.metersSecondToAppSettingsSpeedUnits(_activeVehicle.airSpeed.rawValue),
219 qsTr("Airspeed"))
220 } else if (!_vehicleInFwdFlight && _activeVehicle.haveMRSpeedLimits) {
221 guidedValueSlider.setupSlider(
222 GuidedValueSlider.SliderType.Speed,
223 _unitsConversion.metersSecondToAppSettingsSpeedUnits(0.1).toFixed(1),
224 _unitsConversion.metersSecondToAppSettingsSpeedUnits(_activeVehicle.maximumHorizontalSpeedMultirotorMetersSecond()).toFixed(1),
225 _unitsConversion.metersSecondToAppSettingsSpeedUnits(_activeVehicle.maximumHorizontalSpeedMultirotorMetersSecond()/2).toFixed(1),
226 qsTr("Speed"))
227 } else {
228 console.error("setupSlider called for inapproproate change speed action", _vehicleInFwdFlight, _activeVehicle.haveMRSpeedLimits)
229 }
230 } else if (actionCode === actionChangeAlt || actionCode === actionOrbit || actionCode === actionGoto || actionCode === actionPause) {
231 guidedValueSlider.setupSlider(
232 GuidedValueSlider.SliderType.Altitude,
233 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_flyViewSettings.guidedMinimumAltitude.rawValue),
234 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_flyViewSettings.guidedMaximumAltitude.rawValue),
235 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_activeVehicle.altitudeRelative.rawValue),
236 qsTr("Alt (rel)"))
237 } else if (actionCode === actionROI) {
238 // ROI targets a point on the ground by default, so start at 0 above home
239 guidedValueSlider.setupSlider(
240 GuidedValueSlider.SliderType.Altitude,
241 0,
242 _unitsConversion.metersToAppSettingsVerticalDistanceUnits(_flyViewSettings.guidedMaximumAltitude.rawValue),
243 0,
244 qsTr("Alt (rel)"))
245 }
246 }
247
248 on_ActiveVehicleChanged: _outputState()
249
250 Component.onCompleted: _outputState()
251 on_VehicleArmedChanged: _outputState()
252 on_VehicleInRTLModeChanged: _outputState()
253 on_VehiclePausedChanged: _outputState()
254 on__FlightModeChanged: _outputState()
255 on__GuidedModeSupportedChanged: _outputState()
256 on__PauseVehicleSupportedChanged: _outputState()
257 on__RoiSupportedChanged: _outputState()
258 on__OrbitSupportedChanged: _outputState()
259 on_VisualItemsCountChanged: _outputState()
260 on_MissionActiveChanged: _outputState()
261
262 on_CurrentMissionIndexChanged: {
263 if (_isGuidedActionsControllerLogEnabled()) {
264 console.log("_currentMissionIndex", _currentMissionIndex)
265 }
266 }
267 on_ResumeMissionIndexChanged: {
268 if (_isGuidedActionsControllerLogEnabled()) {
269 console.log("_resumeMissionIndex", _resumeMissionIndex)
270 }
271 }
272 onShowResumeMissionChanged: {
273 if (_isGuidedActionsControllerLogEnabled()) {
274 console.log("showResumeMission", showResumeMission)
275 }
276 _outputState()
277 }
278 onShowStartMissionChanged: {
279 if (_isGuidedActionsControllerLogEnabled()) {
280 console.log("showStartMission", showStartMission)
281 }
282 _outputState()
283 if (showStartMission &&
284 _flyViewSettings.enableAutomaticMissionPopups.rawValue) {
285 confirmAction(actionStartMission)
286 }
287 }
288 onShowContinueMissionChanged: {
289 if (_isGuidedActionsControllerLogEnabled()) {
290 console.log("showContinueMission", showContinueMission)
291 }
292 _outputState()
293 if (showContinueMission &&
294 _flyViewSettings.enableAutomaticMissionPopups.rawValue) {
295 confirmAction(actionContinueMission)
296 }
297 }
298 onShowRTLChanged: {
299 if (_isGuidedActionsControllerLogEnabled()) {
300 console.log("showRTL", showRTL)
301 }
302 _outputState()
303 }
304 onShowChangeAltChanged: {
305 if (_isGuidedActionsControllerLogEnabled()) {
306 console.log("showChangeAlt", showChangeAlt)
307 }
308 _outputState()
309 }
310 onShowROIChanged: {
311 if (_isGuidedActionsControllerLogEnabled()) {
312 console.log("showROI", showROI)
313 }
314 _outputState()
315 }
316 onShowOrbitChanged: {
317 if (_isGuidedActionsControllerLogEnabled()) {
318 console.log("showOrbit", showOrbit)
319 }
320 _outputState()
321 }
322 onShowGotoLocationChanged: {
323 if (_isGuidedActionsControllerLogEnabled()) {
324 console.log("showGotoLocation", showGotoLocation)
325 }
326 _outputState()
327 }
328 onShowLandAbortChanged: {
329 if (showLandAbort) {
330 confirmAction(actionLandAbort)
331 }
332 }
333
334 on_VehicleUnderwayChanged: {
335 _outputState()
336 if (!_vehicleUnderway) {
337 // We use _vehicleWasUnderway to help trigger Resume Mission only if the vehicle actually moved and came back down.
338 // Otherwise it may trigger during the Start Mission sequence due to signal ordering or armed and resume mission index.
339 _vehicleWasUnderway = true
340 }
341 }
342
343 property var _actionData
344
345 on_FlightModeChanged: {
346 _vehiclePaused = _activeVehicle ? _flightMode === _activeVehicle.pauseFlightMode : false
347 _vehicleInRTLMode = _activeVehicle ? _flightMode === _activeVehicle.rtlFlightMode || _flightMode === _activeVehicle.smartRTLFlightMode : false
348 _vehicleInLandMode = _activeVehicle ? _flightMode === _activeVehicle.landFlightMode : false
349 _vehicleInMissionMode = _activeVehicle ? _flightMode === _activeVehicle.missionFlightMode : false // Must be last to get correct signalling for showStartMission popups
350 }
351
352 Connections {
353 target: missionController
354 function onResumeMissionUploadFail() { confirmAction(actionResumeMissionUploadFail) }
355 }
356
357 Connections {
358 target: mainWindow
359 function onArmVehicleRequest() { armVehicleRequest() }
360 function onForceArmVehicleRequest() { forceArmVehicleRequest() }
361 function onDisarmVehicleRequest() { disarmVehicleRequest() }
362 }
363
364 Connections {
365 target: _unitsConversion
366
367 function onUnitsChanged() {
368 // Slider range and value were captured in the previous units
369 if (_activeVehicle && guidedValueSlider.visible) {
370 setupSlider(confirmDialog.action)
371 }
372 }
373 }
374
375 function armVehicleRequest() {
376 confirmAction(actionArm)
377 }
378
379 function forceArmVehicleRequest() {
380 confirmAction(actionForceArm)
381 }
382
383 function disarmVehicleRequest() {
384 if (showEmergencyStop) {
385 confirmAction(actionEmergencyStop)
386 } else {
387 confirmAction(actionDisarm)
388 }
389
390 }
391
392 function closeAll() {
393 confirmDialog.visible = false
394 guidedValueSlider.visible = false
395 }
396
397 // Called when an action is about to be executed in order to confirm
398 function confirmAction(actionCode, actionData, mapIndicator) {
399 var showImmediate = true
400
401 // Cancel any previously pending action, notifying its map indicator if it differs from the incoming one
402 confirmDialog.confirmCancelled(mapIndicator)
403
404 confirmDialog.action = actionCode
405 confirmDialog.actionData = actionData
406 confirmDialog.mapIndicator = mapIndicator
407 confirmDialog.optionText = ""
408 _actionData = actionData
409
410 setupSlider(actionCode)
411
412 switch (actionCode) {
413 case actionArm:
414 if (_vehicleUnderway || !_guidedActionsEnabled) {
415 return
416 }
417 confirmDialog.title = armTitle
418 confirmDialog.message = armMessage
419 confirmDialog.hideTrigger = Qt.binding(function() { return !showArm })
420 break;
421 case actionMVArm:
422 confirmDialog.title = mvArmTitle
423 confirmDialog.message = mvArmMessage
424 break;
425 case actionForceArm:
426 confirmDialog.title = forceArmTitle
427 confirmDialog.message = forceArmMessage
428 confirmDialog.hideTrigger = Qt.binding(function() { return !showForceArm })
429 break;
430 case actionDisarm:
431 if (_vehicleAirborne) {
432 return
433 }
434 confirmDialog.title = disarmTitle
435 confirmDialog.message = disarmMessage
436 confirmDialog.hideTrigger = Qt.binding(function() { return !showDisarm })
437 break;
438 case actionMVDisarm:
439 confirmDialog.title = mvDisarmTitle
440 confirmDialog.message = mvDisarmMessage
441 break;
442 case actionEmergencyStop:
443 confirmDialog.title = emergencyStopTitle
444 confirmDialog.message = emergencyStopMessage
445 confirmDialog.hideTrigger = Qt.binding(function() { return !showEmergencyStop })
446 break;
447 case actionTakeoff:
448 confirmDialog.title = takeoffTitle
449 confirmDialog.message = takeoffMessage
450 confirmDialog.hideTrigger = Qt.binding(function() { return !showTakeoff })
451 guidedValueSlider.visible = _activeVehicle.supports.guidedTakeoffWithAltitude
452 break;
453 case actionStartMission:
454 showImmediate = false
455 confirmDialog.title = startMissionTitle
456 confirmDialog.message = startMissionMessage
457 confirmDialog.hideTrigger = Qt.binding(function() { return !showStartMission })
458 break;
459 case actionMVStartMission:
460 confirmDialog.title = mvStartMissionTitle
461 confirmDialog.message = mvStartMissionMessage
462 break;
463 case actionContinueMission:
464 showImmediate = false
465 confirmDialog.title = continueMissionTitle
466 confirmDialog.message = continueMissionMessage
467 confirmDialog.hideTrigger = Qt.binding(function() { return !showContinueMission })
468 break;
469 case actionResumeMission:
470 // Resume Mission is handled in mission end dialog
471 return
472 case actionResumeMissionUploadFail:
473 confirmDialog.title = resumeMissionUploadFailTitle
474 confirmDialog.message = resumeMissionUploadFailMessage
475 confirmDialog.hideTrigger = Qt.binding(function() { return !showResumeMission })
476 break;
477 case actionLand:
478 confirmDialog.title = landTitle
479 confirmDialog.message = landMessage
480 confirmDialog.hideTrigger = Qt.binding(function() { return !showLand })
481 break;
482 case actionRTL:
483 confirmDialog.title = rtlTitle
484 confirmDialog.message = rtlMessage
485 if (_activeVehicle.supports.smartRTL) {
486 confirmDialog.optionText = qsTr("Smart RTL")
487 confirmDialog.optionChecked = false
488 }
489 confirmDialog.hideTrigger = Qt.binding(function() { return !showRTL })
490 break;
491 case actionChangeAlt:
492 confirmDialog.title = changeAltTitle
493 confirmDialog.message = changeAltMessage
494 confirmDialog.hideTrigger = Qt.binding(function() { return !showChangeAlt })
495 guidedValueSlider.visible = true
496 break;
497 case actionChangeLoiterRadius:
498 confirmDialog.title = changeLoiterRadiusTitle
499 confirmDialog.message = changeLoiterRadiusMessage
500 confirmDialog.hideTrigger = Qt.binding(function() { return !showChangeLoiterRadius })
501 confirmDialog.mapIndicator = fwdFlightGotoMapCircle
502 fwdFlightGotoMapCircle.startLoiterRadiusEdit()
503 break
504 case actionGoto:
505 confirmDialog.title = gotoTitle
506 confirmDialog.message = gotoMessage
507 confirmDialog.hideTrigger = Qt.binding(function() { return !showGotoLocation })
508 break;
509 case actionSetWaypoint:
510 confirmDialog.title = setWaypointTitle
511 confirmDialog.message = setWaypointMessage
512 break;
513 case actionOrbit:
514 confirmDialog.title = orbitTitle
515 confirmDialog.message = orbitMessage
516 confirmDialog.hideTrigger = Qt.binding(function() { return !showOrbit })
517 guidedValueSlider.visible = true
518 break;
519 case actionLandAbort:
520 confirmDialog.title = landAbortTitle
521 confirmDialog.message = landAbortMessage
522 confirmDialog.hideTrigger = Qt.binding(function() { return !showLandAbort })
523 break;
524 case actionPause:
525 confirmDialog.title = pauseTitle
526 confirmDialog.message = pauseMessage
527 confirmDialog.hideTrigger = Qt.binding(function() { return !showPause })
528 guidedValueSlider.visible = true
529 break;
530 case actionMVPause:
531 confirmDialog.title = mvPauseTitle
532 confirmDialog.message = mvPauseMessage
533 break;
534 case actionROI:
535 confirmDialog.title = roiTitle
536 confirmDialog.message = roiMessage
537 confirmDialog.hideTrigger = Qt.binding(function() { return !showROI })
538 guidedValueSlider.visible = true
539 break;
540 case actionChangeSpeed:
541 confirmDialog.title = changeSpeedTitle
542 confirmDialog.message = changeSpeedMessage
543 guidedValueSlider.visible = true
544 break
545 case actionSetHome:
546 confirmDialog.title = setHomeTitle
547 confirmDialog.message = setHomeMessage
548 confirmDialog.hideTrigger = Qt.binding(function() { return !showSetHome })
549 break
550 case actionSetEstimatorOrigin:
551 confirmDialog.title = setEstimatorOriginTitle
552 confirmDialog.message = setEstimatorOriginMessage
553 break
554 case actionSetFlightMode:
555 confirmDialog.title = setFlightMode
556 confirmDialog.message = setFlightModeMessage
557 break
558 case actionChangeHeading:
559 confirmDialog.title = changeHeadingTitle
560 confirmDialog.message = changeHeadingMessage
561 break
562 default:
563 if (!customController.customConfirmAction(actionCode, actionData, mapIndicator, confirmDialog)) {
564 console.warn("Unknown actionCode", actionCode)
565 return
566 }
567 }
568 confirmDialog.show(showImmediate)
569 }
570
571 // Executes the specified action
572 // Returns false if the action failed and any associated map indicator should be restored
573 function executeAction(actionCode, actionData, sliderOutputValue, optionChecked) {
574 var i;
575 var selectedVehicles;
576 switch (actionCode) {
577 case actionRTL:
578 _activeVehicle.guidedModeRTL(optionChecked)
579 break
580 case actionLand:
581 _activeVehicle.guidedModeLand()
582 break
583 case actionTakeoff:
584 if (_activeVehicle.supports.guidedTakeoffWithAltitude) {
585 var valueInMeters = _unitsConversion.appSettingsVerticalDistanceUnitsToMeters(sliderOutputValue)
586 _activeVehicle.guidedModeTakeoff(valueInMeters)
587 } else {
588 _activeVehicle.startTakeoff()
589 }
590 break
591 case actionResumeMission:
592 case actionResumeMissionUploadFail:
593 missionController.resumeMission(missionController.resumeMissionIndex)
594 break
595 case actionStartMission:
596 case actionContinueMission:
597 _activeVehicle.startMission()
598 break
599 case actionMVStartMission:
600 selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
601 for (i = 0; i < selectedVehicles.count; i++) {
602 var vehicle = selectedVehicles.get(i)
603 if (vehicle.armed === true){
604 vehicle.startMission()
605 }
606 }
607 break
608 case actionArm:
609 _activeVehicle.armed = true
610 break
611 case actionMVArm:
612 selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
613 for (i = 0; i < selectedVehicles.count; i++) {
614 selectedVehicles.get(i).armed = true
615 }
616 break
617 case actionForceArm:
618 _activeVehicle.forceArm()
619 break
620 case actionDisarm:
621 _activeVehicle.armed = false
622 break
623 case actionMVDisarm:
624 selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
625 for (i = 0; i < selectedVehicles.count; i++) {
626 selectedVehicles.get(i).armed = false
627 }
628 break
629 case actionEmergencyStop:
630 _activeVehicle.emergencyStop()
631 break
632 case actionChangeAlt:
633 var valueInMeters = _unitsConversion.appSettingsVerticalDistanceUnitsToMeters(sliderOutputValue)
634 var altitudeChangeInMeters = valueInMeters - _activeVehicle.altitudeRelative.rawValue
635 _activeVehicle.guidedModeChangeAltitude(altitudeChangeInMeters, false /* pauseVehicle */)
636 break
637 case actionChangeLoiterRadius:
638 if (!_activeVehicle.guidedModeGotoLocation(
639 fwdFlightGotoMapCircle.coordinate,
640 (fwdFlightGotoMapCircle.clockwiseRotation ? 1 : -1) *
641 Math.abs(fwdFlightGotoMapCircle.radius.rawValue)
642 )) {
643 return false
644 }
645 break
646 case actionGoto:
647 if (!_activeVehicle.guidedModeGotoLocation(
648 actionData,
649 _vehicleInFwdFlight /* forwardFlightLoiterRadius */
650 ? _flyViewSettings.forwardFlightGoToLocationLoiterRad.rawValue
651 : 0
652 )) {
653 return false
654 }
655 break
656 case actionSetWaypoint:
657 _activeVehicle.setCurrentMissionSequence(actionData)
658 break
659 case actionOrbit:
660 var valueInMeters = _unitsConversion.appSettingsVerticalDistanceUnitsToMeters(sliderOutputValue)
661 _activeVehicle.guidedModeOrbit(orbitMapCircle.center, orbitMapCircle.radius() * (orbitMapCircle.clockwiseRotation ? 1 : -1), _activeVehicle.homePosition.altitude + valueInMeters)
662 break
663 case actionLandAbort:
664 _activeVehicle.abortLanding(50) // hardcoded value for climbOutAltitude that is currently ignored
665 break
666 case actionPause:
667 var valueInMeters = _unitsConversion.appSettingsVerticalDistanceUnitsToMeters(sliderOutputValue)
668 var altitudeChangeInMeters = valueInMeters - _activeVehicle.altitudeRelative.rawValue
669 _activeVehicle.guidedModeChangeAltitude(altitudeChangeInMeters, true /* pauseVehicle */)
670 break
671 case actionMVPause:
672 selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
673 for (i = 0; i < selectedVehicles.count; i++) {
674 selectedVehicles.get(i).pauseVehicle()
675 }
676 break
677 case actionROI: {
678 const roiRelativeAltitudeMeters = _unitsConversion.appSettingsVerticalDistanceUnitsToMeters(sliderOutputValue)
679 if (!_activeVehicle.guidedModeROI(actionData, roiRelativeAltitudeMeters)) {
680 return false
681 }
682 break
683 }
684 case actionChangeSpeed:
685 if (_activeVehicle) {
686 // We need to convert back to m/s as that is what mavlink standard uses for MAV_CMD_DO_CHANGE_SPEED
687 var metersSecondSpeed = _unitsConversion.appSettingsSpeedUnitsToMetersSecond(sliderOutputValue)
688 if (_vehicleInFwdFlight) {
689 _activeVehicle.guidedModeChangeEquivalentAirspeedMetersSecond(metersSecondSpeed)
690 } else {
691 _activeVehicle.guidedModeChangeGroundSpeedMetersSecond(metersSecondSpeed)
692 }
693 }
694 break
695 case actionSetHome:
696 _activeVehicle.doSetHome(actionData)
697 break
698 case actionSetEstimatorOrigin:
699 _activeVehicle.setEstimatorOrigin(actionData)
700 break
701 case actionSetFlightMode:
702 _activeVehicle.flightMode = actionData
703 break
704 case actionChangeHeading:
705 _activeVehicle.guidedModeChangeHeading(actionData)
706 break
707 default:
708 if (!customController.customExecuteAction(actionCode, actionData, sliderOutputValue, optionChecked)) {
709 console.warn(qsTr("Internal error: unknown actionCode"), actionCode)
710 return false
711 }
712 break
713 }
714 return true
715 }
716}