QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
APMGimbalInstance.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3
4import QGroundControl
5import QGroundControl.FactControls
6import QGroundControl.Controls
7import QGroundControl.AutoPilotPlugins.APM
8
9ColumnLayout {
10 property int instance: 1
11 property real verticalSpacing: ScreenTools.defaultFontPixelHeight / 2
12 property real horizontalSpacing: ScreenTools.defaultFontPixelWidth * 2
13
14 id: control
15
16 property real _sliderWidth: ScreenTools.defaultFontPixelWidth * 20
17 property var _controller: gimbalParams.controller
18 property var _rcRateFact: gimbalParams.rcRateFact
19
20 function _servoChannelCount() {
21 let servoIndex = 1
22 while (_controller.parameterExists(-1, "SERVO" + servoIndex + "_FUNCTION")) {
23 servoIndex++
24 }
25 return servoIndex - 1
26 }
27
28 function _rcChannelCount() {
29 let rcIndex = 1
30 while (_controller.parameterExists(-1, "RC" + rcIndex + "_OPTION")) {
31 rcIndex++
32 }
33 return rcIndex - 1
34 }
35
36 function _servoChannelModel() {
37 let model = [ qsTr("Disabled") ]
38 let channelCount = _servoChannelCount()
39 for (let i = 1; i <= channelCount; i++) {
40 model.push(qsTr("Channel ") + i)
41 }
42 return model
43 }
44
45 function _rcChannelModel() {
46 let model = [ qsTr("Disabled") ]
47 let channelCount = _rcChannelCount()
48 for (let i = 1; i <= channelCount; i++) {
49 model.push(qsTr("Channel ") + i)
50 }
51 return model
52 }
53
54 APMGimbalParams { id: gimbalParams; instance: control.instance }
55
56 RowLayout {
57 Layout.fillWidth: false
58 spacing: horizontalSpacing
59 visible: gimbalParams.instanceCount > 0
60
61 LabelledFactComboBox {
62 label: qsTr("Gimbal Type")
63 fact: gimbalParams.typeFact
64 indexModel: false
65 }
66
67 LabelledFactComboBox {
68 label: qsTr("Default Mode")
69 fact: gimbalParams.defaultModeFact
70 indexModel: false
71 visible: fact !== null
72 }
73 }
74
75 Loader {
76 sourceComponent: gimbalParams.paramsAvailable ? configComponent : rebootRequiredComponent
77 }
78
79 Component {
80 id: configComponent
81
82 ColumnLayout {
83 spacing: verticalSpacing
84
85 SettingsGroupLayout {
86 heading: qsTr("Neutral Position")
87
88 RowLayout {
89 spacing: horizontalSpacing
90
91 LabelledFactTextField {
92 Layout.fillWidth: true
93 label: qsTr("Pitch")
94 fact: gimbalParams.neutralYFact
95 }
96
97 LabelledFactTextField {
98 Layout.fillWidth: true
99 label: qsTr("Yaw")
100 fact: gimbalParams.neutralZFact
101 }
102
103 LabelledFactTextField {
104 Layout.fillWidth: true
105 label: qsTr("Roll")
106 fact: gimbalParams.neutralXFact
107 }
108 }
109 }
110
111 SettingsGroupLayout {
112 heading: qsTr("Retracted Position")
113
114 RowLayout {
115 spacing: horizontalSpacing
116
117 LabelledFactTextField {
118 Layout.fillWidth: true
119 label: qsTr("Pitch")
120 fact: gimbalParams.retractYFact
121 }
122
123 LabelledFactTextField {
124 Layout.fillWidth: true
125 label: qsTr("Yaw")
126 fact: gimbalParams.retractZFact
127 }
128
129 LabelledFactTextField {
130 Layout.fillWidth: true
131 label: qsTr("Roll")
132 fact: gimbalParams.retractXFact
133 }
134 }
135 }
136
137 SettingsGroupLayout {
138 heading: qsTr("Axis Constraints")
139
140 Repeater {
141 model: [
142 {
143 axisLabel: qsTr("Pitch"),
144 minFact: gimbalParams.pitchMinFact,
145 maxFact: gimbalParams.pitchMaxFact
146 },
147 {
148 axisLabel: qsTr("Yaw"),
149 minFact: gimbalParams.yawMinFact,
150 maxFact: gimbalParams.yawMaxFact
151 },
152 {
153 axisLabel: qsTr("Roll"),
154 minFact: gimbalParams.rollMinFact,
155 maxFact: gimbalParams.rollMaxFact
156 }
157 ]
158
159 ColumnLayout {
160 spacing: verticalSpacing
161
162 QGCLabel {
163 text: modelData.axisLabel
164 }
165
166 RowLayout {
167 spacing: horizontalSpacing
168
169 LabelledFactTextField {
170 Layout.fillWidth: true
171 label: qsTr("Min Angle")
172 fact: modelData.minFact
173 }
174
175 LabelledFactTextField {
176 Layout.fillWidth: true
177 label: qsTr("Max Angle")
178 fact: modelData.maxFact
179 }
180 }
181 }
182 }
183 }
184
185 SettingsGroupLayout {
186 heading: qsTr("RC Targetting")
187
188 RowLayout {
189 spacing: horizontalSpacing
190
191 Repeater {
192 model: [
193 { comboLabel: qsTr("Pitch"), optionValue: 213 },
194 { comboLabel: qsTr("Yaw"), optionValue: 214 },
195 { comboLabel: qsTr("Roll"), optionValue: 212 }
196 ]
197
198 LabelledComboBox {
199 id: outputChannelCombo
200 label: modelData.comboLabel
201 model: _rcChannelModel()
202
203 Component.onCompleted: {
204 let maxRcChannel = _rcChannelCount()
205 for (var rcIndex = 1; rcIndex <= maxRcChannel; rcIndex++) {
206 var parameterName = "RC" + rcIndex + "_OPTION"
207 var functionFact = _controller.getParameterFact(-1, parameterName)
208 if (functionFact.value == modelData.optionValue) {
209 currentIndex = rcIndex
210 return
211 }
212 }
213 currentIndex = 0
214 }
215
216 onActivated: {
217 if (currentIndex == 0) {
218 // Disabled selected
219 let maxRcChannel = _rcChannelCount()
220 for (let rcIndex = 1; rcIndex <= maxRcChannel; rcIndex++) {
221 let parameterName = "RC" + rcIndex + "_OPTION"
222 let functionFact = _controller.getParameterFact(-1, parameterName)
223 if (functionFact.value == modelData.optionValue) {
224 functionFact.rawValue = 0
225 return
226 }
227 }
228 return
229 }
230 let rcIndex = currentIndex
231 let parameterName = "RC" + rcIndex + "_OPTION"
232 _controller.getParameterFact(-1, parameterName).rawValue = modelData.optionValue
233 }
234 }
235 }
236 }
237
238 ColumnLayout {
239 spacing: 0
240
241 RowLayout {
242 spacing: horizontalSpacing
243
244 QGCRadioButton {
245 text: qsTr("Angle Control")
246 checked: !(_rcRateFact.rawValue > 0)
247 onClicked: _rcRateFact.rawValue = 0
248 }
249
250 QGCRadioButton {
251 text: qsTr("Rate Control")
252 checked: _rcRateFact.rawValue > 0
253 onClicked: _rcRateFact.rawValue = 90
254 }
255
256 LabelledFactTextField {
257 Layout.fillWidth: true
258 label: qsTr("Rate")
259 fact: _rcRateFact
260 }
261 }
262 }
263 }
264
265 SettingsGroupLayout {
266 heading: qsTr("Servo Controlled Gimbal")
267 visible: gimbalParams.typeFact.rawValue === 1
268
269 Repeater {
270 model: [
271 { axisLabel: qsTr("Pitch"), functionValue: 7, stabilizeFact: gimbalParams.pitchLeadFact },
272 { axisLabel: qsTr("Yaw"), functionValue: 6, stabilizeFact: null },
273 { axisLabel: qsTr("Roll"), functionValue: 8, stabilizeFact: gimbalParams.rollLeadFact }
274 ]
275
276 ColumnLayout {
277 spacing: verticalSpacing
278
279 property bool servoChannelValid: outputChannelCombo.currentIndex > 0
280 property int validServoChannel: servoChannelValid ? outputChannelCombo.currentIndex : 1
281 property string servoPrefix: "SERVO" + validServoChannel + "_"
282 property bool hasStabilizeParam: modelData.stabilizeFact !== null
283
284 RowLayout {
285 Layout.fillWidth: false
286 spacing: horizontalSpacing
287
288 QGCLabel {
289 text: modelData.axisLabel
290 }
291
292 FactCheckBox {
293 text: qsTr("Servo Reversed")
294 fact: _controller.getParameterFact(-1, servoPrefix + "REVERSED")
295 enabled: servoChannelValid
296 }
297 }
298
299 RowLayout {
300 Layout.fillWidth: hasStabilizeParam
301 spacing: horizontalSpacing
302
303 LabelledComboBox {
304 Layout.fillWidth: hasStabilizeParam
305 id: outputChannelCombo
306 label: qsTr("Output Channel")
307 model: _servoChannelModel()
308
309 Component.onCompleted: {
310 let maxServoChannel = _servoChannelCount()
311 for (var servoIndex = 1; servoIndex <= maxServoChannel; servoIndex++) {
312 var parameterName = "SERVO" + servoIndex + "_FUNCTION"
313 var functionFact = _controller.getParameterFact(-1, parameterName)
314 if (functionFact.value == modelData.functionValue) {
315 currentIndex = servoIndex
316 return
317 }
318 }
319 currentIndex = 0
320 }
321
322 onActivated: {
323 if (currentIndex == 0) {
324 // Disabled selected
325 let maxServoChannel = _servoChannelCount()
326 for (let servoIndex = 1; servoIndex <= maxServoChannel; servoIndex++) {
327 let parameterName = "SERVO" + servoIndex + "_FUNCTION"
328 let functionFact = _controller.getParameterFact(-1, parameterName)
329 if (functionFact.value == modelData.functionValue) {
330 functionFact.rawValue = 0
331 return
332 }
333 }
334 return
335 }
336 let servoIndex = currentIndex
337 let parameterName = "SERVO" + servoIndex + "_FUNCTION"
338 _controller.getParameterFact(-1, parameterName).rawValue = modelData.functionValue
339 }
340 }
341
342 LabelledFactTextField {
343 Layout.fillWidth: true
344 label: qsTr("Stabilization Lead")
345 fact: modelData.stabilizeFact
346 visible: hasStabilizeParam
347 enabled: servoChannelValid
348 }
349 }
350
351 RowLayout {
352 Layout.alignment: Qt.AlignHCenter
353 Layout.fillWidth: true
354 spacing: horizontalSpacing
355 enabled: servoChannelValid
356
357 LabelledFactTextField {
358 Layout.fillWidth: true
359 label: qsTr("Min PWM")
360 fact: _controller.getParameterFact(-1, servoPrefix + "MIN")
361 }
362
363 LabelledFactTextField {
364 Layout.fillWidth: true
365 label: qsTr("Max PWM")
366 fact: _controller.getParameterFact(-1, servoPrefix + "MAX")
367 }
368 }
369 }
370 }
371 }
372 }
373 }
374
375 Component {
376 id: rebootRequiredComponent
377
378 QGCLabel {
379 text: qsTr("Gimbal settings will be available after rebooting the vehicle.")
380 visible: gimbalParams.typeFact.rawValue !== 0
381 }
382 }
383}