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