7import QGroundControl.Controls
8import QGroundControl.FactControls
9import QGroundControl.AutoPilotPlugins.PX4
13 pageComponent: pageComponent
16 property var actuators: globals.activeVehicle.actuators
18 property var _showAdvanced: advanced
19 readonly property real _margins: ScreenTools.defaultFontPixelHeight
25 spacing: ScreenTools.defaultFontPixelWidth * 4
26 property var _leftColumnWidth: Math.max(actuatorTesting.implicitWidth, mixerUi.implicitWidth) + (_margins * 2)
29 spacing: ScreenTools.defaultFontPixelHeight
30 implicitWidth: _leftColumnWidth
34 width: _leftColumnWidth
35 visible: actuators.mixer.groups.count > 0
37 text: qsTr("Geometry") + (actuators.mixer.title ? ": " + actuators.mixer.title : "")
38 font.pointSize: ScreenTools.mediumFontPointSize
39 Layout.fillWidth: true
42 text: "<a href='"+actuators.mixer.helpUrl+"'>?</a>"
43 font.pointSize: ScreenTools.mediumFontPointSize
44 visible: actuators.mixer.helpUrl
45 textFormat: Text.RichText
46 onLinkActivated: (link) => {
47 Qt.openUrlExternally(link);
53 implicitWidth: _leftColumnWidth
54 implicitHeight: mixerUi.height + (_margins * 2)
55 color: qgcPal.windowShade
56 visible: actuators.mixer.groups.count > 0
64 verticalCenter: parent.verticalCenter
66 enabled: !safetySwitch.checked && !actuators.motorAssignmentActive
68 model: actuators.mixer.groups
70 property var mixerGroup: object
74 text: mixerGroup.label
76 rightPadding: ScreenTools.defaultFontPixelWidth * 3
79 property var countParam: mixerGroup.countParam
80 visible: countParam != null
81 fact: countParam ? countParam.fact : null
86 rows: 1 + mixerGroup.channels.count
87 columns: 1 + mixerGroup.channelConfigs.count
93 // param config labels
95 model: mixerGroup.channelConfigs
98 visible: object.visible && (_showAdvanced || !object.advanced)
100 Layout.column: 1 + index
105 model: mixerGroup.channels
107 text: object.label + ":"
108 Layout.row: 1 + index
113 model: mixerGroup.channels
115 property var channel: object
116 property var channelIndex: index
118 model: object.configInstances
122 Layout.row: 1 + channelIndex
123 Layout.column: 1 + index
124 visible: object.config.visible && (_showAdvanced || !object.config.advanced) && object.visible
125 enabled: object.enabled
131 // extra group config params
133 model: mixerGroup.configParams
136 spacing: ScreenTools.defaultFontPixelWidth
138 text: object.label + ":"
139 visible: _showAdvanced || !object.advanced
143 visible: _showAdvanced || !object.advanced
155 source: "image://actuators/geometry"+refreshFlag
156 sourceSize.width: imageSize
157 sourceSize.height: imageSize
158 Layout.preferredWidth: imageSize
159 Layout.preferredHeight: imageSize
160 Layout.alignment: Qt.AlignHCenter
161 visible: actuators.isMultirotor
164 property var refreshFlag: actuators.imageRefreshFlag
165 readonly property real imageSize: 9 * ScreenTools.defaultFontPixelHeight
169 onClicked: (mouse) => {
170 if (mouse.button == Qt.LeftButton) {
171 actuators.imageClicked(Qt.size(width, height), mouse.x, mouse.y);
179 text: qsTr("Actuator Testing")
180 font.pointSize: ScreenTools.mediumFontPointSize
184 implicitWidth: _leftColumnWidth
185 implicitHeight: actuatorTesting.height + (_margins * 2)
186 color: qgcPal.windowShade
194 verticalCenter: parent.verticalCenter
198 text: qsTr("Configure some outputs in order to test them.")
199 visible: actuators.actuatorTest.actuators.count == 0
203 spacing: ScreenTools.defaultFontPixelWidth
204 visible: actuators.actuatorTest.actuators.count > 0
208 enabled: !actuators.motorAssignmentActive && !actuators.actuatorTest.hadFailure
210 target: actuators.actuatorTest
211 onHadFailureChanged: {
212 if (actuators.actuatorTest.hadFailure) {
213 safetySwitch.checked = false;
214 safetySwitch.switchUpdated();
221 function switchUpdated() {
223 for (var channelIdx=0; channelIdx<sliderRepeater.count; channelIdx++) {
224 sliderRepeater.itemAt(channelIdx).stop();
226 if (allMotorsLoader.item != null)
227 allMotorsLoader.item.stop();
229 actuators.actuatorTest.setActive(checked);
234 color: qgcPal.warningText
235 text: safetySwitch.checked ? qsTr("Careful: Actuator sliders are enabled") : qsTr("Propellers are removed - Enable sliders")
240 spacing: ScreenTools.defaultFontPixelWidth * 2
241 enabled: safetySwitch.checked
243 // (optional) slider for all motors
246 sourceComponent: actuators.actuatorTest.allMotorsActuator ? allMotorsComponent : null
247 Layout.alignment: Qt.AlignTop
250 id: allMotorsComponent
252 channel: actuators.actuatorTest.allMotorsActuator
253 rightPadding: ScreenTools.defaultFontPixelWidth * 3
254 onActuatorValueChanged: (value, sliderValue) => {
256 for (var channelIdx=0; channelIdx<sliderRepeater.count; channelIdx++) {
257 var channelSlider = sliderRepeater.itemAt(channelIdx);
258 if (channelSlider.channel.isMotor) {
259 channelSlider.value = sliderValue;
269 model: actuators.actuatorTest.actuators
273 onActuatorValueChanged: (value) =>{
275 actuators.actuatorTest.stopControl(index);
278 actuators.actuatorTest.setChannelTo(index, value);
287 visible: actuators.actuatorActions.count > 0
288 enabled: !safetySwitch.checked && !actuators.motorAssignmentActive
290 spacing: ScreenTools.defaultFontPixelWidth * 2
292 model: actuators.actuatorActions
295 property var actionGroup: object
296 text: actionGroup.label
297 onClicked: actionMenu.popup()
302 model: actionGroup.actions
305 onTriggered: object.trigger()
307 onObjectAdded: (index, object) => actionMenu.insertItem(index, object)
308 onObjectRemoved: (index, object) => actionMenu.removeItem(object)
324 text: qsTr("Actuator Outputs")
325 font.pointSize: ScreenTools.mediumFontPointSize
326 bottomPadding: ScreenTools.defaultFontPixelHeight
329 text: qsTr("One or more actuator still needs to be assigned to an output.")
330 visible: actuators.hasUnsetRequiredFunctions
331 color: qgcPal.warningText
332 bottomPadding: ScreenTools.defaultFontPixelHeight
336 // actuator output selection tabs
339 model: actuators.actuatorOutputs
341 text: ' ' + object.label + ' '
345 onCurrentIndexChanged: {
346 actuators.selectActuatorOutput(currentIndex)
352 id: selActuatorOutput
353 implicitWidth: actuatorGroupColumn.width + (_margins * 2)
354 implicitHeight: actuatorGroupColumn.height + (_margins * 2)
355 color: qgcPal.windowShade
357 property var actuatorOutput: actuators.selectedActuatorOutput
360 id: actuatorGroupColumn
362 anchors.centerIn: parent
366 visible: actuators.isMultirotor
367 enabled: !safetySwitch.checked
368 anchors.right: parent.right
371 text: qsTr("Identify & Assign Motors")
372 visible: !actuators.motorAssignmentActive && selActuatorOutput.actuatorOutput.groupsVisible
373 enabled: actuators.motorAssignmentEnabled
375 var success = actuators.initMotorAssignment()
377 motorAssignmentConfirmDialog.open()
379 motorAssignmentFailureDialog.open()
383 id: motorAssignmentConfirmDialog
385 //icon: StandardIcon.Warning
386 buttons: MessageDialog.Yes | MessageDialog.No
387 title: qsTr("Motor Order Identification and Assignment")
388 text: actuators.motorAssignmentMessage
389 onButtonClicked: function (button, role) {
391 case MessageDialog.Yes:
392 actuators.startMotorAssignment()
398 id: motorAssignmentFailureDialog
400 //icon: StandardIcon.Critical
401 buttons: MessageDialog.Ok
403 text: actuators.motorAssignmentMessage
407 text: qsTr("Spin Motor Again")
408 visible: actuators.motorAssignmentActive
410 actuators.spinCurrentMotor()
415 visible: actuators.motorAssignmentActive
417 actuators.abortMotorAssignment()
423 enabled: !safetySwitch.checked && !actuators.motorAssignmentActive
427 property var enableParam: selActuatorOutput.actuatorOutput.enableParam
429 visible: parent.enableParam != null
430 text: parent.enableParam ? parent.enableParam.label + ":" : ""
433 visible: parent.enableParam != null
434 fact: parent.enableParam ? parent.enableParam.fact : null
440 model: selActuatorOutput.actuatorOutput.subgroups
443 property var subgroup: object
444 visible: selActuatorOutput.actuatorOutput.groupsVisible
447 visible: subgroup.label != ""
451 rightPadding: ScreenTools.defaultFontPixelWidth * 3
454 property var primaryParam: subgroup.primaryParam
455 visible: primaryParam != null
456 fact: primaryParam ? primaryParam.fact : null
461 rows: 1 + subgroup.channels.count
462 columns: 1 + subgroup.channelConfigs.count
468 // param config labels
470 model: subgroup.channelConfigs
473 visible: object.visible && (_showAdvanced || !object.advanced)
475 Layout.column: 1 + index
480 model: subgroup.channels
482 text: object.label + ":"
483 Layout.row: 1 + index
488 model: subgroup.channels
490 property var channel: object
491 property var channelIndex: index
492 model: object.configInstances
495 Layout.row: 1 + channelIndex
496 Layout.column: 1 + index
497 visible: object.config.visible && (_showAdvanced || !object.config.advanced)
503 // extra subgroup config params
505 model: subgroup.configParams
509 text: object.label + ":"
518 } // subgroup Repeater
520 // extra actuator config params
522 model: selActuatorOutput.actuatorOutput.configParams
526 text: object.label + ":"
536 model: selActuatorOutput.actuatorOutput.notes
538 spacing: ScreenTools.defaultFontPixelHeight
541 color: qgcPal.warningText