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 Layout.fillWidth: true
197 spacing: stickDisplayContainer._margins * 2
198
199 Rectangle {
200 id: leftStickDisplay
201 Layout.alignment: Qt.AlignLeft
202 implicitWidth: ScreenTools.defaultFontPixelHeight * 5
203 implicitHeight: implicitWidth
204 radius: implicitWidth / 2
205 border.color: qgcPal.buttonHighlight
206 border.width: 1
207 color: qgcPal.window
208
209 Rectangle {
210 x: parent.width / 2 + stickDisplayContainer._stickAdjust * controller.stickDisplayPositions[0] - width / 2
211 y: parent.height / 2 + stickDisplayContainer._stickAdjust * -controller.stickDisplayPositions[1] - height / 2
212 width: ScreenTools.defaultFontPixelHeight
213 height: width
214 radius: width / 2
215 color: qgcPal.buttonHighlight
216 }
217 }
218
219 Rectangle {
220 Layout.alignment: Qt.AlignRight
221 implicitWidth: leftStickDisplay.implicitWidth
222 implicitHeight: implicitWidth
223 radius: implicitWidth / 2
224 border.color: qgcPal.buttonHighlight
225 border.width: 1
226 color: qgcPal.window
227 visible: !controller.singleStickDisplay
228
229 Rectangle {
230 x: parent.width / 2 + stickDisplayContainer._stickAdjust * controller.stickDisplayPositions[2] - width / 2
231 y: parent.height / 2 + stickDisplayContainer._stickAdjust * -controller.stickDisplayPositions[3] - height / 2
232 width: ScreenTools.defaultFontPixelHeight
233 height: width
234 radius: width / 2
235 color: qgcPal.buttonHighlight
236 }
237 }
238 }
239 }
240 }
241 }
242 }
243
244 // Command Buttons and Status Text
245 RowLayout {
246 Layout.preferredWidth: parent.width
247 spacing: ScreenTools.defaultFontPixelWidth
248
249 QGCButton {
250 id: cancelButton
251 text: qsTr("Cancel")
252 onClicked: controller.cancelButtonClicked()
253 }
254
255 QGCButton {
256 text: qsTr("One-Sided")
257 visible: controller.oneSidedButtonVisible
258 onClicked: controller.oneSidedButtonClicked()
259 }
260
261 QGCButton {
262 id: nextButton
263 primary: true
264 text: qsTr("Calibrate")
265
266 onClicked: {
267 if (text === qsTr("Calibrate")) {
268 if (controller.channelCount < controller.minChannelCount) {
269 let errorMessage = ""
270 let title = ""
271 if (controller.joystickMode) {
272 title = qsTr("Joystick Not Ready")
273 errorMessage = qsTr("%1 axes or more are needed to fly. Joystick is reporting %2 axes.").arg(controller.minChannelCount).arg(controller.channelCount)
274 } else {
275 title = qsTr("Not Ready")
276 errorMessage = controller.channelCount === 0 ? qsTr("Please turn on RC transmitter.") : qsTr("%1 channels or more are needed to fly.").arg(controller.minChannelCount)
277 }
278 QGroundControl.showMessageDialog(root, title, errorMessage)
279 return
280 } else if (!controller.joystickMode) {
281 QGroundControl.showMessageDialog(root, qsTr("Zero Trims"),
282 qsTr("Before calibrating you should zero all your trims and subtrims. Click Ok to start Calibration.\n\n%1").arg(
283 (QGroundControl.multiVehicleManager.activeVehicle.px4Firmware ? "" : qsTr("Please ensure all motor power is disconnected AND all props are removed from the vehicle."))),
284 Dialog.Ok,
285 function() { controller.nextButtonClicked() })
286 return
287 }
288 }
289 controller.nextButtonClicked()
290 }
291 }
292
293 QGCLabel {
294 id: statusText
295 Layout.fillWidth: true
296 wrapMode: Text.WordWrap
297 }
298 }
299
300 Rectangle {
301 id: separator
302 Layout.fillWidth: true
303 implicitHeight: 1
304 color: qgcPal.text
305 }
306
307 // Additional Setup + Channel Monitor
308 RowLayout {
309 Layout.fillWidth: true
310 spacing: ScreenTools.defaultFontPixelHeight
311
312
313 Item {
314 Layout.fillWidth: true
315 implicitHeight: 1
316 visible: additionalSetupComponent === undefined
317 }
318
319 Loader {
320 id: additionalSetupLoader
321 Layout.alignment: Qt.AlignTop
322 sourceComponent: additionalSetupComponent
323 }
324
325 ColumnLayout {
326 Layout.alignment: Qt.AlignTop
327 Layout.fillWidth: true
328 spacing: ScreenTools.defaultFontPixelHeight
329
330 RemoteControlChannelMonitor {
331 id: channelMonitor
332 Layout.fillWidth: true
333 twoColumn: false
334 channelCount: controller.channelCount
335 channelValueMin: controller.channelValueMin
336 channelValueMax: controller.channelValueMax
337
338 Connections {
339 target: controller
340 onRawChannelValueChanged: (channel, channelValue) => channelMonitor.rawChannelValueChanged(channel, channelValue)
341 }
342 }
343
344 Loader {
345 id: additionalMonitorLoader
346 Layout.preferredWidth: parent.width
347 sourceComponent: additionalMonitorComponent
348 }
349 }
350 }
351}