QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
RemoteControlCalibration.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Dialogs
4import QtQuick.Layouts
5
6import QGroundControl
7import QGroundControl.FactControls
8import QGroundControl.Controls
9
10/// Base class for Remote Control Calibration (supports both RC and Joystick)
11ColumnLayout {
12 required property var controller
13 property Component additionalSetupComponent
14 property Component additionalMonitorComponent
15
16 // Controllers need access to these UI elements
17 property alias statusText: statusText
18 property alias cancelButton: cancelButton
19 property alias nextButton: nextButton
20
21 id: root
22 spacing: ScreenTools.defaultFontPixelHeight
23
24 property bool useDeadband: false
25
26 property real _channelValueDisplayWidth: ScreenTools.defaultFontPixelWidth * 30
27 property bool _deadbandActive: useDeadband
28
29 QGCPalette { id: qgcPal; colorGroupEnabled: root.enabled }
30
31 RowLayout {
32 // Left Column - Attitude Controls display
33 ColumnLayout {
34 Layout.alignment: Qt.AlignTop
35 spacing: ScreenTools.defaultFontPixelHeight
36
37 ColumnLayout {
38 id: attitudeControlsLayout
39 Layout.fillWidth: true
40 spacing: ScreenTools.defaultFontPixelHeight
41
42 QGCLabel { text: qsTr("Attitude Controls") }
43
44 Repeater {
45 model: [
46 { name: qsTr("Pitch"), mapped: controller.pitchChannelMapped, value: controller.adjustedPitchChannelValue, deadband: controller.pitchDeadband },
47 { name: qsTr("Roll"), mapped: controller.rollChannelMapped, value: controller.adjustedRollChannelValue, deadband: controller.rollDeadband },
48 { name: qsTr("Yaw"), mapped: controller.yawChannelMapped, value: controller.adjustedYawChannelValue, deadband: controller.yawDeadband },
49 { name: qsTr("Throttle"), mapped: controller.throttleChannelMapped, value: controller.adjustedThrottleChannelValue, deadband: controller.throttleDeadband }
50 ]
51
52 RowLayout {
53 Layout.fillWidth: true
54
55 QGCLabel {
56 Layout.fillWidth: true
57 text: modelData.name
58 }
59
60 RemoteControlChannelValueDisplay {
61 Layout.preferredWidth: root._channelValueDisplayWidth
62 mode: RemoteControlChannelValueDisplay.MappedValue
63 channelValueMin: controller.channelValueMin
64 channelValueMax: controller.channelValueMax
65 channelMapped: modelData.mapped
66 channelValue: modelData.value
67 deadbandValue: modelData.deadband
68 deadbandEnabled: root._deadbandActive
69 }
70 }
71 }
72
73 QGCLabel {
74 text: qsTr("Aux Extensions")
75 visible: controller.pitchExtensionEnabled || controller.rollExtensionEnabled
76 }
77
78 Repeater {
79 model: [
80 { name: qsTr("Pitch"), extensionEnabled: controller.pitchExtensionEnabled, mapped: controller.pitchExtensionChannelMapped, value: controller.adjustedPitchExtensionChannelValue, deadband: controller.pitchExtensionDeadband },
81 { name: qsTr("Roll"), extensionEnabled: controller.rollExtensionEnabled, mapped: controller.rollExtensionChannelMapped, value: controller.adjustedRollExtensionChannelValue, deadband: controller.rollExtensionDeadband },
82 ]
83
84 RowLayout {
85 Layout.fillWidth: true
86 visible: modelData.extensionEnabled
87
88 QGCLabel {
89 Layout.fillWidth: true
90 text: modelData.name
91 }
92
93 RemoteControlChannelValueDisplay {
94 Layout.preferredWidth: root._channelValueDisplayWidth
95 mode: RemoteControlChannelValueDisplay.MappedValue
96 channelValueMin: controller.channelValueMin
97 channelValueMax: controller.channelValueMax
98 channelMapped: modelData.mapped
99 channelValue: modelData.value
100 deadbandValue: modelData.deadband
101 deadbandEnabled: root._deadbandActive
102 }
103 }
104 }
105
106 QGCLabel {
107 text: qsTr("Additional Axes")
108 visible: controller.additionalAxis1Enabled || controller.additionalAxis2Enabled || controller.additionalAxis3Enabled ||
109 controller.additionalAxis4Enabled || controller.additionalAxis5Enabled || controller.additionalAxis6Enabled
110 }
111
112 Repeater {
113 model: [
114 { name: qsTr("Aux 1"), extensionEnabled: controller.additionalAxis1Enabled, mapped: controller.additionalAxis1ChannelMapped, value: controller.adjustedAdditionalAxis1ChannelValue, deadband: controller.additionalAxis1Deadband },
115 { name: qsTr("Aux 2"), extensionEnabled: controller.additionalAxis2Enabled, mapped: controller.additionalAxis2ChannelMapped, value: controller.adjustedAdditionalAxis2ChannelValue, deadband: controller.additionalAxis2Deadband },
116 { name: qsTr("Aux 3"), extensionEnabled: controller.additionalAxis3Enabled, mapped: controller.additionalAxis3ChannelMapped, value: controller.adjustedAdditionalAxis3ChannelValue, deadband: controller.additionalAxis3Deadband },
117 { name: qsTr("Aux 4"), extensionEnabled: controller.additionalAxis4Enabled, mapped: controller.additionalAxis4ChannelMapped, value: controller.adjustedAdditionalAxis4ChannelValue, deadband: controller.additionalAxis4Deadband },
118 { name: qsTr("Aux 5"), extensionEnabled: controller.additionalAxis5Enabled, mapped: controller.additionalAxis5ChannelMapped, value: controller.adjustedAdditionalAxis5ChannelValue, deadband: controller.additionalAxis5Deadband },
119 { name: qsTr("Aux 6"), extensionEnabled: controller.additionalAxis6Enabled, mapped: controller.additionalAxis6ChannelMapped, value: controller.adjustedAdditionalAxis6ChannelValue, deadband: controller.additionalAxis6Deadband }
120 ]
121
122 RowLayout {
123 Layout.fillWidth: true
124 visible: modelData.extensionEnabled
125
126 QGCLabel {
127 Layout.fillWidth: true
128 text: modelData.name
129 }
130
131 RemoteControlChannelValueDisplay {
132 Layout.preferredWidth: root._channelValueDisplayWidth
133 mode: RemoteControlChannelValueDisplay.MappedValue
134 channelValueMin: controller.channelValueMin
135 channelValueMax: controller.channelValueMax
136 channelMapped: modelData.mapped
137 channelValue: modelData.value
138 deadbandValue: modelData.deadband
139 deadbandEnabled: root._deadbandActive
140 }
141 }
142 }
143 }
144 }
145
146 // Right Column - Stick Display
147 ColumnLayout {
148 Layout.alignment: Qt.AlignTop
149 spacing: ScreenTools.defaultFontPixelHeight / 2
150
151 Rectangle {
152 id: stickDisplayContainer
153 implicitWidth: stickDisplayLayout.width + _margins * 2
154 implicitHeight: stickDisplayLayout.height + _margins * 2
155 border.color: qgcPal.text
156 border.width: 1
157 color: qgcPal.window
158 radius: ScreenTools.defaultBorderRadius
159
160 property real _margins: ScreenTools.defaultFontPixelHeight / 2
161 property real _stickAdjust: leftStickDisplay.width / 2 - _margins * 1.25
162
163 ColumnLayout {
164 id: stickDisplayLayout
165 anchors.leftMargin: stickDisplayContainer._margins
166 anchors.topMargin: stickDisplayContainer._margins
167 anchors.left: parent.left
168 anchors.top: parent.top
169 spacing: stickDisplayContainer._margins
170
171 RowLayout {
172 spacing: ScreenTools.defaultFontPixelWidth * 2
173
174 QGCComboBox {
175 id: transmitterModeComboBox
176 model: [ qsTr("Mode 1"), qsTr("Mode 2"), qsTr("Mode 3"), qsTr("Mode 4") ]
177 enabled: !controller.calibrating
178
179 onActivated: (index) => controller.transmitterMode = index + 1
180
181 Component.onCompleted: currentIndex = controller.transmitterMode - 1
182 }
183
184 QGCCheckBox {
185 id: centeredThrottleCheckBox
186 text: qsTr("Centered Throttle")
187 checked: controller.centeredThrottle
188 enabled: !controller.calibrating
189 visible: !controller.joystickMode
190
191 onClicked: controller.centeredThrottle = checked
192 }
193 }
194
195 RowLayout {
196 id: stickDisplayRow
197 Layout.fillWidth: true
198 spacing: stickDisplayContainer._margins * 2
199
200 property color stickColor: controller.calibrating ? stickPal.buttonHighlight : stickPal.text
201
202 QGCPalette { id: stickPal; colorGroupEnabled: controller.calibrating }
203
204 Rectangle {
205 id: leftStickDisplay
206 Layout.alignment: Qt.AlignLeft
207 implicitWidth: ScreenTools.defaultFontPixelHeight * 5
208 implicitHeight: implicitWidth
209 radius: implicitWidth / 2
210 border.color: stickDisplayRow.stickColor
211 border.width: 1
212 color: qgcPal.window
213
214 Rectangle {
215 x: parent.width / 2 + stickDisplayContainer._stickAdjust * controller.stickDisplayPositions[0] - width / 2
216 y: parent.height / 2 + stickDisplayContainer._stickAdjust * -controller.stickDisplayPositions[1] - height / 2
217 width: ScreenTools.defaultFontPixelHeight
218 height: width
219 radius: width / 2
220 color: stickDisplayRow.stickColor
221 }
222 }
223
224 Rectangle {
225 Layout.alignment: Qt.AlignRight
226 implicitWidth: leftStickDisplay.implicitWidth
227 implicitHeight: implicitWidth
228 radius: implicitWidth / 2
229 border.color: stickDisplayRow.stickColor
230 border.width: 1
231 color: qgcPal.window
232 visible: !controller.singleStickDisplay
233
234 Rectangle {
235 x: parent.width / 2 + stickDisplayContainer._stickAdjust * controller.stickDisplayPositions[2] - width / 2
236 y: parent.height / 2 + stickDisplayContainer._stickAdjust * -controller.stickDisplayPositions[3] - height / 2
237 width: ScreenTools.defaultFontPixelHeight
238 height: width
239 radius: width / 2
240 color: stickDisplayRow.stickColor
241 }
242 }
243 }
244 }
245 }
246 }
247 }
248
249 // Command Buttons and Status Text
250 RowLayout {
251 Layout.preferredWidth: parent.width
252 spacing: ScreenTools.defaultFontPixelWidth
253
254 QGCButton {
255 id: cancelButton
256 text: qsTr("Cancel")
257 onClicked: controller.cancelButtonClicked()
258 }
259
260 QGCButton {
261 text: qsTr("One-Sided")
262 visible: controller.oneSidedButtonVisible
263 onClicked: controller.oneSidedButtonClicked()
264 }
265
266 QGCButton {
267 id: nextButton
268 primary: true
269 text: qsTr("Calibrate")
270
271 onClicked: {
272 if (text === qsTr("Calibrate")) {
273 if (controller.channelCount < controller.minChannelCount) {
274 let errorMessage = ""
275 let title = ""
276 if (controller.joystickMode) {
277 title = qsTr("Joystick Not Ready")
278 errorMessage = qsTr("%1 axes or more are needed to fly. Joystick is reporting %2 axes.").arg(controller.minChannelCount).arg(controller.channelCount)
279 } else {
280 title = qsTr("Not Ready")
281 errorMessage = controller.channelCount === 0 ? qsTr("Please turn on RC transmitter.") : qsTr("%1 channels or more are needed to fly.").arg(controller.minChannelCount)
282 }
283 QGroundControl.showMessageDialog(root, title, errorMessage)
284 return
285 } else if (!controller.joystickMode) {
286 QGroundControl.showMessageDialog(root, qsTr("Zero Trims"),
287 qsTr("Before calibrating you should zero all your trims and subtrims. Click Ok to start Calibration.\n\n%1").arg(
288 (QGroundControl.multiVehicleManager.activeVehicle.px4Firmware ? "" : qsTr("Please ensure all motor power is disconnected AND all props are removed from the vehicle."))),
289 Dialog.Ok,
290 function() { controller.nextButtonClicked() })
291 return
292 }
293 }
294 controller.nextButtonClicked()
295 }
296 }
297
298 QGCLabel {
299 id: statusText
300 Layout.fillWidth: true
301 wrapMode: Text.WordWrap
302 }
303 }
304
305 Rectangle {
306 id: separator
307 Layout.fillWidth: true
308 implicitHeight: 1
309 color: qgcPal.text
310 }
311
312 // Additional Setup + Channel Monitor
313 RowLayout {
314 Layout.fillWidth: true
315 spacing: ScreenTools.defaultFontPixelHeight
316
317
318 Item {
319 Layout.fillWidth: true
320 implicitHeight: 1
321 visible: additionalSetupComponent === undefined
322 }
323
324 Loader {
325 id: additionalSetupLoader
326 Layout.alignment: Qt.AlignTop
327 sourceComponent: additionalSetupComponent
328 }
329
330 ColumnLayout {
331 Layout.alignment: Qt.AlignTop
332 Layout.fillWidth: true
333 spacing: ScreenTools.defaultFontPixelHeight
334
335 RemoteControlChannelMonitor {
336 id: channelMonitor
337 Layout.fillWidth: true
338 twoColumn: false
339 channelCount: controller.channelCount
340 channelValueMin: controller.channelValueMin
341 channelValueMax: controller.channelValueMax
342
343 Connections {
344 target: controller
345 onRawChannelValueChanged: (channel, channelValue) => channelMonitor.rawChannelValueChanged(channel, channelValue)
346 }
347 }
348
349 Loader {
350 id: additionalMonitorLoader
351 Layout.preferredWidth: parent.width
352 sourceComponent: additionalMonitorComponent
353 }
354 }
355 }
356}