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("Extension Controls")
75 visible: controller.anyExtensionEnabled
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 { name: qsTr("Aux 1"), extensionEnabled: controller.aux1ExtensionEnabled, mapped: controller.aux1ExtensionChannelMapped, value: controller.adjustedAux1ExtensionChannelValue, deadband: controller.aux1ExtensionDeadband },
83 { name: qsTr("Aux 2"), extensionEnabled: controller.aux2ExtensionEnabled, mapped: controller.aux2ExtensionChannelMapped, value: controller.adjustedAux2ExtensionChannelValue, deadband: controller.aux2ExtensionDeadband },
84 { name: qsTr("Aux 3"), extensionEnabled: controller.aux3ExtensionEnabled, mapped: controller.aux3ExtensionChannelMapped, value: controller.adjustedAux3ExtensionChannelValue, deadband: controller.aux3ExtensionDeadband },
85 { name: qsTr("Aux 4"), extensionEnabled: controller.aux4ExtensionEnabled, mapped: controller.aux4ExtensionChannelMapped, value: controller.adjustedAux4ExtensionChannelValue, deadband: controller.aux4ExtensionDeadband },
86 { name: qsTr("Aux 5"), extensionEnabled: controller.aux5ExtensionEnabled, mapped: controller.aux5ExtensionChannelMapped, value: controller.adjustedAux5ExtensionChannelValue, deadband: controller.aux5ExtensionDeadband },
87 { name: qsTr("Aux 6"), extensionEnabled: controller.aux6ExtensionEnabled, mapped: controller.aux6ExtensionChannelMapped, value: controller.adjustedAux6ExtensionChannelValue, deadband: controller.aux6ExtensionDeadband }
88 ]
89
90 RowLayout {
91 Layout.fillWidth: true
92 visible: modelData.extensionEnabled
93
94 QGCLabel {
95 Layout.fillWidth: true
96 text: modelData.name
97 }
98
99 RemoteControlChannelValueDisplay {
100 Layout.preferredWidth: root._channelValueDisplayWidth
101 mode: RemoteControlChannelValueDisplay.MappedValue
102 channelValueMin: controller.channelValueMin
103 channelValueMax: controller.channelValueMax
104 channelMapped: modelData.mapped
105 channelValue: modelData.value
106 deadbandValue: modelData.deadband
107 deadbandEnabled: root._deadbandActive
108 }
109 }
110 }
111 }
112 }
113
114 // Right Column - Stick Display
115 ColumnLayout {
116 Layout.alignment: Qt.AlignTop
117 spacing: ScreenTools.defaultFontPixelHeight / 2
118
119 Rectangle {
120 id: stickDisplayContainer
121 implicitWidth: stickDisplayLayout.width + _margins * 2
122 implicitHeight: stickDisplayLayout.height + _margins * 2
123 border.color: qgcPal.text
124 border.width: 1
125 color: qgcPal.window
126 radius: ScreenTools.defaultBorderRadius
127
128 property real _margins: ScreenTools.defaultFontPixelHeight / 2
129 property real _stickAdjust: leftStickDisplay.width / 2 - _margins * 1.25
130
131 ColumnLayout {
132 id: stickDisplayLayout
133 anchors.leftMargin: stickDisplayContainer._margins
134 anchors.topMargin: stickDisplayContainer._margins
135 anchors.left: parent.left
136 anchors.top: parent.top
137 spacing: stickDisplayContainer._margins
138
139 RowLayout {
140 spacing: ScreenTools.defaultFontPixelWidth * 2
141
142 QGCComboBox {
143 id: transmitterModeComboBox
144 model: [ qsTr("Mode 1"), qsTr("Mode 2"), qsTr("Mode 3"), qsTr("Mode 4") ]
145 enabled: !controller.calibrating
146
147 onActivated: (index) => controller.transmitterMode = index + 1
148
149 Component.onCompleted: currentIndex = controller.transmitterMode - 1
150 }
151
152 QGCCheckBox {
153 id: centeredThrottleCheckBox
154 text: qsTr("Centered Throttle")
155 checked: controller.centeredThrottle
156 enabled: !controller.calibrating
157 visible: !controller.joystickMode
158
159 onClicked: controller.centeredThrottle = checked
160 }
161 }
162
163 RowLayout {
164 Layout.fillWidth: true
165 spacing: stickDisplayContainer._margins * 2
166
167 Rectangle {
168 id: leftStickDisplay
169 Layout.alignment: Qt.AlignLeft
170 implicitWidth: ScreenTools.defaultFontPixelHeight * 5
171 implicitHeight: implicitWidth
172 radius: implicitWidth / 2
173 border.color: qgcPal.buttonHighlight
174 border.width: 1
175 color: qgcPal.window
176
177 Rectangle {
178 x: parent.width / 2 + stickDisplayContainer._stickAdjust * controller.stickDisplayPositions[0] - width / 2
179 y: parent.height / 2 + stickDisplayContainer._stickAdjust * -controller.stickDisplayPositions[1] - height / 2
180 width: ScreenTools.defaultFontPixelHeight
181 height: width
182 radius: width / 2
183 color: qgcPal.buttonHighlight
184 }
185 }
186
187 Rectangle {
188 Layout.alignment: Qt.AlignRight
189 implicitWidth: leftStickDisplay.implicitWidth
190 implicitHeight: implicitWidth
191 radius: implicitWidth / 2
192 border.color: qgcPal.buttonHighlight
193 border.width: 1
194 color: qgcPal.window
195 visible: !controller.singleStickDisplay
196
197 Rectangle {
198 x: parent.width / 2 + stickDisplayContainer._stickAdjust * controller.stickDisplayPositions[2] - width / 2
199 y: parent.height / 2 + stickDisplayContainer._stickAdjust * -controller.stickDisplayPositions[3] - height / 2
200 width: ScreenTools.defaultFontPixelHeight
201 height: width
202 radius: width / 2
203 color: qgcPal.buttonHighlight
204 }
205 }
206 }
207 }
208 }
209 }
210 }
211
212 // Command Buttons and Status Text
213 RowLayout {
214 Layout.preferredWidth: parent.width
215 spacing: ScreenTools.defaultFontPixelWidth
216
217 QGCButton {
218 id: cancelButton
219 text: qsTr("Cancel")
220 onClicked: controller.cancelButtonClicked()
221 }
222
223 QGCButton {
224 id: nextButton
225 primary: true
226 text: qsTr("Calibrate")
227
228 onClicked: {
229 if (text === qsTr("Calibrate")) {
230 if (controller.channelCount < controller.minChannelCount) {
231 let errorMessage = ""
232 let title = ""
233 if (controller.joystickMode) {
234 title = qsTr("Joystick Not Ready")
235 errorMessage = qsTr("%1 axes or more are needed to fly. Joystick is reporting %2 axes.").arg(controller.minChannelCount).arg(controller.channelCount)
236 } else {
237 title = qsTr("Not Ready")
238 errorMessage = controller.channelCount === 0 ? qsTr("Please turn on RC transmitter.") : qsTr("%1 channels or more are needed to fly.").arg(controller.minChannelCount)
239 }
240 QGroundControl.showMessageDialog(root, title, errorMessage)
241 return
242 } else if (!controller.joystickMode) {
243 QGroundControl.showMessageDialog(root, qsTr("Zero Trims"),
244 qsTr("Before calibrating you should zero all your trims and subtrims. Click Ok to start Calibration.\n\n%1").arg(
245 (QGroundControl.multiVehicleManager.activeVehicle.px4Firmware ? "" : qsTr("Please ensure all motor power is disconnected AND all props are removed from the vehicle."))),
246 Dialog.Ok,
247 function() { controller.nextButtonClicked() })
248 return
249 }
250 }
251 controller.nextButtonClicked()
252 }
253 }
254
255 QGCLabel {
256 id: statusText
257 Layout.fillWidth: true
258 wrapMode: Text.WordWrap
259 }
260 }
261
262 Rectangle {
263 id: separator
264 Layout.fillWidth: true
265 implicitHeight: 1
266 color: qgcPal.text
267 }
268
269 // Additional Setup + Channel Monitor
270 RowLayout {
271 Layout.fillWidth: true
272 spacing: ScreenTools.defaultFontPixelHeight
273
274
275 Item {
276 Layout.fillWidth: true
277 implicitHeight: 1
278 visible: additionalSetupComponent === undefined
279 }
280
281 Loader {
282 id: additionalSetupLoader
283 Layout.alignment: Qt.AlignTop
284 sourceComponent: additionalSetupComponent
285 }
286
287 ColumnLayout {
288 Layout.alignment: Qt.AlignTop
289 Layout.fillWidth: true
290 spacing: ScreenTools.defaultFontPixelHeight
291
292 RemoteControlChannelMonitor {
293 id: channelMonitor
294 Layout.fillWidth: true
295 twoColumn: false
296 channelCount: controller.channelCount
297 channelValueMin: controller.channelValueMin
298 channelValueMax: controller.channelValueMax
299
300 Connections {
301 target: controller
302 onRawChannelValueChanged: (channel, channelValue) => channelMonitor.rawChannelValueChanged(channel, channelValue)
303 }
304 }
305
306 Loader {
307 id: additionalMonitorLoader
308 Layout.preferredWidth: parent.width
309 sourceComponent: additionalMonitorComponent
310 }
311 }
312 }
313}