QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
SensorsSetup.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/// Page for sensor calibration. This control is used within the SensorsComponent control and can also be used
11/// standalone for custom uis. When using standadalone you can use the various show* bools to show/hide what you want.
12Item {
13 id: _root
14
15 property bool showSensorCalibrationCompass: true ///< true: Show this calibration button
16 property bool showSensorCalibrationGyro: true ///< true: Show this calibration button
17 property bool showSensorCalibrationAccel: true ///< true: Show this calibration button
18 property bool showSensorCalibrationLevel: true ///< true: Show this calibration button
19 property bool showSensorCalibrationAirspeed: true ///< true: Show this calibration button
20 property bool showSetOrientations: true ///< true: Show this calibration button
21 property bool showNextButton: false ///< true: Show Next button which will signal nextButtonClicked
22
23 signal nextButtonClicked
24
25 // Help text which is shown both in the status text area prior to pressing a cal button and in the
26 // pre-calibration dialog.
27
28 readonly property string boardRotationText: qsTr("If the orientation is in the direction of flight, select ROTATION_NONE.")
29 readonly property string compassRotationText: qsTr("If the orientation is in the direction of flight, select ROTATION_NONE.")
30
31 readonly property string compassHelp: qsTr("For Compass calibration you will need to rotate your vehicle through a number of positions.")
32 readonly property string gyroHelp: qsTr("For Gyroscope calibration you will need to place your vehicle on a surface and leave it still.")
33 readonly property string accelHelp: qsTr("For Accelerometer calibration you will need to place your vehicle on all six sides on a perfectly level surface and hold it still in each orientation for a few seconds.")
34 readonly property string levelHelp: qsTr("To level the horizon you need to place the vehicle in its level flight position and leave still.")
35 readonly property string airspeedHelp: qsTr("For Airspeed calibration you will need to keep your airspeed sensor out of any wind and then blow across the sensor. Do not touch the sensor or obstruct any holes during the calibration.")
36
37 readonly property string statusTextAreaDefaultText: qsTr("Start the individual calibration steps by clicking one of the buttons to the left.")
38
39 // Used to pass what type of calibration is being performed to the preCalibrationDialog
40 property string preCalibrationDialogType
41
42 // Used to pass help text to the preCalibrationDialog dialog
43 property string preCalibrationDialogHelp
44
45 property Fact cal_mag0_id: controller.getParameterFact(-1, "CAL_MAG0_ID")
46 property Fact cal_mag1_id: controller.getParameterFact(-1, "CAL_MAG1_ID")
47 property Fact cal_mag2_id: controller.getParameterFact(-1, "CAL_MAG2_ID")
48 property Fact cal_mag0_rot: controller.getParameterFact(-1, "CAL_MAG0_ROT")
49 property Fact cal_mag1_rot: controller.getParameterFact(-1, "CAL_MAG1_ROT")
50 property Fact cal_mag2_rot: controller.getParameterFact(-1, "CAL_MAG2_ROT")
51
52 property Fact cal_gyro0_id: controller.getParameterFact(-1, "CAL_GYRO0_ID")
53 property Fact cal_acc0_id: controller.getParameterFact(-1, "CAL_ACC0_ID")
54
55 property Fact sens_board_rot: controller.getParameterFact(-1, "SENS_BOARD_ROT")
56 property Fact sens_dpres_off: controller.getParameterFact(-1, "SENS_DPRES_OFF")
57
58 // Id > = signals compass available, rot < 0 signals internal compass
59 property bool showCompass0Rot: cal_mag0_id.value > 0 && cal_mag0_rot.value >= 0
60 property bool showCompass1Rot: cal_mag1_id.value > 0 && cal_mag1_rot.value >= 0
61 property bool showCompass2Rot: cal_mag2_id.value > 0 && cal_mag2_rot.value >= 0
62
63 property bool _sensorsHaveFixedOrientation: QGroundControl.corePlugin.options.sensorsHaveFixedOrientation
64 property string _calMagIdParamFormat: "CAL_MAG#_ID"
65 property string _calMagRotParamFormat: "CAL_MAG#_ROT"
66 property bool _allMagsDisabled: controller.parameterExists(-1, "SYS_HAS_MAG") ? controller.getParameterFact(-1, "SYS_HAS_MAG").value === 0 : false
67 property bool _boardOrientationChangeAllowed: !_sensorsHaveFixedOrientation && setOrientationsDialogShowBoardOrientation
68 property bool _compassOrientationChangeAllowed: !_sensorsHaveFixedOrientation
69 property int _arbitrarilyLargeMaxMagIndex: 50
70
71 function currentMagParamCount() {
72 if (_allMagsDisabled) {
73 return 0
74 } else {
75 for (var index=0; index<_arbitrarilyLargeMaxMagIndex; index++) {
76 var magIdParam = _calMagIdParamFormat.replace("#", index)
77 if (!controller.parameterExists(-1, magIdParam)) {
78 return index
79 }
80 }
81 console.warn("SensorSetup.qml:currentMagParamCount internal error")
82 return -1
83 }
84 }
85
86 function currentExternalMagCount() {
87 if (_allMagsDisabled) {
88 return 0
89 } else {
90 var externalMagCount = 0
91 for (var index=0; index<_arbitrarilyLargeMaxMagIndex; index++) {
92 var magIdParam = _calMagIdParamFormat.replace("#", index)
93 if (controller.parameterExists(-1, magIdParam)) {
94 var calMagIdFact = controller.getParameterFact(-1, magIdParam)
95 var calMagRotFact = controller.getParameterFact(-1, _calMagRotParamFormat.replace("#", index))
96 if (calMagIdFact.value > 0 && calMagRotFact.value >= 0) {
97 externalMagCount++
98 }
99 } else {
100 return externalMagCount
101 }
102 }
103 console.warn("SensorSetup.qml:currentExternalMagCount internal error")
104 return 0
105 }
106 }
107
108 function orientationsButtonVisible() {
109 // Deliberately independent of setOrientationsDialogShowBoardOrientation: that is a
110 // transient flag controlling dialog contents only (cleared by onMagCalComplete) and
111 // must not hide the Orientations button after a compass calibration completes.
112 return !_sensorsHaveFixedOrientation && showSetOrientations
113 }
114
115 QGCPalette { id: qgcPal; colorGroupEnabled: true }
116
117 SensorsComponentController {
118 id: controller
119 statusLog: statusTextArea
120 progressBar: progressBar
121 orientationCalAreaHelpText: orientationCalAreaHelpText
122
123 onResetStatusTextArea: statusLog.text = statusTextAreaDefaultText
124
125 onMagCalComplete: {
126 setOrientationsDialogShowBoardOrientation = false
127 setOrientationsDialogFactory.open({ title: qsTr("Compass Calibration Complete"), showRebootVehicleButton: true })
128 }
129
130 onWaitingForCancelChanged: {
131 if (controller.waitingForCancel) {
132 waitForCancelDialogFactory.open()
133 }
134 }
135
136 onCalibrationActiveChanged: {
137 if (controller.calibrationActive) {
138 globals.navigationBlockedReason = qsTr("Complete or cancel the current calibration first")
139 } else {
140 globals.navigationBlockedReason = ""
141 }
142 }
143 }
144
145 Component.onDestruction: globals.navigationBlockedReason = ""
146
147 QGCPopupDialogFactory {
148 id: waitForCancelDialogFactory
149
150 dialogComponent: waitForCancelDialogComponent
151 }
152
153 Component {
154 id: waitForCancelDialogComponent
155
156 QGCSimpleMessageDialog {
157 title: qsTr("Calibration Cancel")
158 text: qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds.")
159 buttons: 0
160
161 Connections {
162 target: controller
163
164 onWaitingForCancelChanged: {
165 if (!controller.waitingForCancel) {
166 close()
167 }
168 }
169 }
170 }
171 }
172
173 QGCPopupDialogFactory {
174 id: preCalibrationDialogFactory
175
176 dialogComponent: preCalibrationDialogComponent
177 }
178
179 Component {
180 id: preCalibrationDialogComponent
181
182 QGCPopupDialog {
183 buttons: Dialog.Cancel | Dialog.Ok
184
185 onAccepted: {
186 if (preCalibrationDialogType == "gyro") {
187 controller.calibrateGyro()
188 } else if (preCalibrationDialogType == "accel") {
189 controller.calibrateAccel()
190 } else if (preCalibrationDialogType == "level") {
191 controller.calibrateLevel()
192 } else if (preCalibrationDialogType == "compass") {
193 controller.calibrateCompass()
194 } else if (preCalibrationDialogType == "airspeed") {
195 controller.calibrateAirspeed()
196 }
197 }
198
199 ColumnLayout {
200 spacing: ScreenTools.defaultFontPixelHeight
201
202 QGCLabel {
203 Layout.minimumWidth: ScreenTools.defaultFontPixelWidth * 50
204 Layout.preferredWidth: innerColumn.width
205 wrapMode: Text.WordWrap
206 text: preCalibrationDialogHelp
207 }
208
209 Column {
210 id: innerColumn
211 spacing: parent.spacing
212
213 QGCLabel {
214 id: boardRotationHelp
215 wrapMode: Text.WordWrap
216 visible: !_sensorsHaveFixedOrientation && (preCalibrationDialogType == "accel" || preCalibrationDialogType == "compass")
217 text: qsTr("Set autopilot orientation before calibrating.")
218 }
219
220 Column {
221 visible: boardRotationHelp.visible
222 QGCLabel { text: qsTr("Autopilot Orientation") }
223
224 FactComboBox {
225 sizeToContents: true
226 fact: sens_board_rot
227 }
228
229 QGCLabel {
230 wrapMode: Text.WordWrap
231 text: qsTr("ROTATION_NONE indicates component points in direction of flight.")
232 }
233 }
234
235 QGCLabel {
236 wrapMode: Text.WordWrap
237 text: qsTr("Click Ok to start calibration.")
238 }
239 }
240 }
241 }
242 }
243
244 property bool setOrientationsDialogShowBoardOrientation: true
245
246 QGCPopupDialogFactory {
247 id: setOrientationsDialogFactory
248
249 dialogComponent: setOrientationsDialogComponent
250 }
251
252 Component {
253 id: setOrientationsDialogComponent
254
255 QGCPopupDialog {
256 buttons: Dialog.Ok
257
258 property bool showRebootVehicleButton: true
259
260 ColumnLayout {
261 spacing: ScreenTools.defaultFontPixelHeight
262
263 QGCLabel {
264 text: qsTr("Reboot the vehicle prior to flight.")
265 visible: showRebootVehicleButton
266 }
267
268 QGCButton {
269 text: qsTr("Reboot Vehicle")
270 visible: showRebootVehicleButton
271 onClicked: { controller.vehicle.rebootVehicle(); close() }
272 }
273
274 QGCLabel {
275 text: qsTr("Adjust orientations as needed.\n\nROTATION_NONE indicates component points in direction of flight.")
276 visible: _boardOrientationChangeAllowed || (_compassOrientationChangeAllowed && currentExternalMagCount() !== 0)
277 }
278
279 Column {
280 visible: _boardOrientationChangeAllowed
281
282 QGCLabel {
283 text: qsTr("Autopilot Orientation")
284 }
285
286 FactComboBox {
287 sizeToContents: true
288 fact: sens_board_rot
289 }
290 }
291
292 Repeater {
293 model: _compassOrientationChangeAllowed ? currentMagParamCount() : 0
294
295 Column {
296 // id > = signals compass available, rot < 0 signals internal compass
297 visible: calMagIdFact.value > 0 && calMagRotFact.value >= 0
298
299 property Fact calMagIdFact: controller.getParameterFact(-1, _calMagIdParamFormat.replace("#", index))
300 property Fact calMagRotFact: controller.getParameterFact(-1, _calMagRotParamFormat.replace("#", index))
301
302 QGCLabel {
303 text: qsTr("Mag %1 Orientation").arg(index)
304 }
305
306 FactComboBox {
307 sizeToContents: true
308 fact: parent.calMagRotFact
309 }
310 }
311 }
312 } // Column
313 } // QGCPopupDialog
314 } // Component - setOrientationsDialogComponent
315
316 property string sectionNameFilter: ""
317
318 // Completed (green) side indicators are only meaningful for the sensor that was
319 // just calibrated. Return them to the neutral idle state when the preview switches
320 // to a different sensor.
321 onSectionNameFilterChanged: controller.resetSidesToIdle()
322
323 function sectionVisible(name) {
324 if (name === qsTr("Compass")) return !_allMagsDisabled && QGroundControl.corePlugin.options.showSensorCalibrationCompass && showSensorCalibrationCompass
325 if (name === qsTr("Gyroscope")) return QGroundControl.corePlugin.options.showSensorCalibrationGyro && showSensorCalibrationGyro
326 if (name === qsTr("Accelerometer")) return QGroundControl.corePlugin.options.showSensorCalibrationAccel && showSensorCalibrationAccel
327 if (name === qsTr("Level Horizon")) return QGroundControl.corePlugin.options.showSensorCalibrationLevel && showSensorCalibrationLevel
328 if (name === qsTr("Airspeed")) return vehicleComponent.airspeedCalSupported && QGroundControl.corePlugin.options.showSensorCalibrationAirspeed && showSensorCalibrationAirspeed
329 if (name === qsTr("Orientations")) return orientationsButtonVisible()
330 return true
331 }
332
333 function _startCalibration(type, help, title) {
334 preCalibrationDialogType = type
335 preCalibrationDialogHelp = help
336 preCalibrationDialogFactory.open({ title: title })
337 }
338
339 // Mag calibration requires the vehicle to be rotated while a side is calibrating
340 function _sideRotating(calState) {
341 return (calState === VehicleRotationCal.CalState.InProgress) && controller.magCalInProgress
342 }
343
344 property bool _showOrientationPreview: !controller.calibrationActive &&
345 (sectionNameFilter === qsTr("Accelerometer") || sectionNameFilter === qsTr("Compass") || sectionNameFilter === qsTr("Gyroscope"))
346
347 property bool _showAllSidesPreview: _showOrientationPreview &&
348 (sectionNameFilter === qsTr("Accelerometer") || sectionNameFilter === qsTr("Compass"))
349
350 property bool _showDownOnlyPreview: _showOrientationPreview &&
351 sectionNameFilter === qsTr("Gyroscope")
352
353 property bool _showStatusPreview: !controller.calibrationActive &&
354 (sectionNameFilter === qsTr("Level Horizon") || sectionNameFilter === qsTr("Airspeed"))
355
356 ColumnLayout {
357 anchors.fill: parent
358 spacing: 0
359
360 // Calibration trigger buttons — one per section, shown based on sectionNameFilter
361 ColumnLayout {
362 Layout.fillWidth: true
363 spacing: ScreenTools.defaultFontPixelHeight / 2
364 visible: !controller.calibrationActive
365
366 QGCButton {
367 objectName: "sensorsSetup_calibrateCompass"
368 Layout.fillWidth: true
369 text: qsTr("Calibrate Compass")
370 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Compass")
371 onClicked: _startCalibration("compass", compassHelp, qsTr("Calibrate Compass"))
372 }
373
374 QGCButton {
375 Layout.fillWidth: true
376 text: qsTr("Calibrate Gyroscope")
377 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Gyroscope")
378 onClicked: _startCalibration("gyro", gyroHelp, qsTr("Calibrate Gyro"))
379 }
380
381 QGCButton {
382 objectName: "sensorsSetup_calibrateAccel"
383 Layout.fillWidth: true
384 text: qsTr("Calibrate Accelerometer")
385 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Accelerometer")
386 onClicked: _startCalibration("accel", accelHelp, qsTr("Calibrate Accelerometer"))
387 }
388
389 QGCButton {
390 Layout.fillWidth: true
391 text: qsTr("Level Horizon")
392 enabled: cal_acc0_id.value !== 0 && cal_gyro0_id.value !== 0
393 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Level Horizon")
394 onClicked: _startCalibration("level", levelHelp, qsTr("Level Horizon"))
395 }
396
397 QGCButton {
398 Layout.fillWidth: true
399 text: qsTr("Calibrate Airspeed")
400 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Airspeed")
401 onClicked: _startCalibration("airspeed", airspeedHelp, qsTr("Calibrate Airspeed"))
402 }
403
404 QGCButton {
405 Layout.fillWidth: true
406 text: qsTr("Set Orientations")
407 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Orientations")
408 onClicked: {
409 setOrientationsDialogShowBoardOrientation = true
410 setOrientationsDialogFactory.open({ title: qsTr("Set Orientations"), showRebootVehicleButton: false })
411 }
412 }
413
414 QGCButton {
415 Layout.fillWidth: true
416 text: qsTr("Factory Reset")
417 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Orientations")
418 onClicked: controller.resetFactoryParameters()
419 }
420
421 QGCButton {
422 Layout.fillWidth: true
423 text: qsTr("Next")
424 visible: showNextButton
425 onClicked: _root.nextButtonClicked()
426 }
427 }
428
429 // Active calibration area — visible during calibration
430 RowLayout {
431 Layout.fillWidth: true
432 visible: controller.calibrationActive
433 spacing: ScreenTools.defaultFontPixelWidth
434
435 ProgressBar {
436 id: progressBar
437 objectName: "sensorsSetup_progressBar"
438 Layout.fillWidth: true
439 }
440
441 QGCButton {
442 objectName: "sensorsSetup_cancelCalibration"
443 text: qsTr("Cancel")
444 onClicked: controller.cancelCalibration()
445 }
446 }
447
448 Item {
449 Layout.fillWidth: true
450 Layout.fillHeight: true
451 visible: controller.calibrationActive || _showOrientationPreview || _showStatusPreview
452
453 TextArea {
454 id: statusTextArea
455 anchors.fill: parent
456 readOnly: true
457 visible: !orientationCalArea.visible
458 text: statusTextAreaDefaultText
459 color: qgcPal.text
460 background: Rectangle { color: qgcPal.windowShade }
461 }
462
463 Rectangle {
464 id: orientationCalArea
465 anchors.fill: parent
466 visible: controller.showOrientationCalArea || _showOrientationPreview
467 color: qgcPal.windowShade
468
469 QGCLabel {
470 id: orientationCalAreaHelpText
471 anchors.margins: ScreenTools.defaultFontPixelWidth
472 anchors.top: orientationCalArea.top
473 anchors.left: orientationCalArea.left
474 width: parent.width
475 wrapMode: Text.WordWrap
476 font.pointSize: ScreenTools.mediumFontPointSize
477 visible: text !== ""
478 }
479
480 Flow {
481 anchors.topMargin: ScreenTools.defaultFontPixelWidth
482 anchors.top: orientationCalAreaHelpText.bottom
483 anchors.bottom: parent.bottom
484 anchors.left: parent.left
485 anchors.right: parent.right
486 spacing: ScreenTools.defaultFontPixelWidth / 2
487
488 property real indicatorWidth: (width / 3) - (spacing * 2)
489 property real indicatorHeight: (height / 2) - spacing
490
491 VehicleRotationCal {
492 objectName: "sensorsCal_downSide"
493 width: parent.indicatorWidth
494 height: parent.indicatorHeight
495 visible: controller.orientationCalDownSideVisible || _showAllSidesPreview || _showDownOnlyPreview
496 calState: controller.orientationCalDownSideState
497 calInProgressText: controller.magCalInProgress ? qsTr("Rotate") : qsTr("Hold Still")
498 imageSource: _sideRotating(calState) ? "qrc:///qmlimages/VehicleDownRotate.png" : "qrc:///qmlimages/VehicleDown.png"
499 }
500 VehicleRotationCal {
501 objectName: "sensorsCal_upsideDownSide"
502 width: parent.indicatorWidth
503 height: parent.indicatorHeight
504 visible: controller.orientationCalUpsideDownSideVisible || _showAllSidesPreview
505 calState: controller.orientationCalUpsideDownSideState
506 calInProgressText: controller.magCalInProgress ? qsTr("Rotate") : qsTr("Hold Still")
507 imageSource: _sideRotating(calState) ? "qrc:///qmlimages/VehicleUpsideDownRotate.png" : "qrc:///qmlimages/VehicleUpsideDown.png"
508 }
509 VehicleRotationCal {
510 objectName: "sensorsCal_noseDownSide"
511 width: parent.indicatorWidth
512 height: parent.indicatorHeight
513 visible: controller.orientationCalNoseDownSideVisible || _showAllSidesPreview
514 calState: controller.orientationCalNoseDownSideState
515 calInProgressText: controller.magCalInProgress ? qsTr("Rotate") : qsTr("Hold Still")
516 imageSource: _sideRotating(calState) ? "qrc:///qmlimages/VehicleNoseDownRotate.png" : "qrc:///qmlimages/VehicleNoseDown.png"
517 }
518 VehicleRotationCal {
519 objectName: "sensorsCal_tailDownSide"
520 width: parent.indicatorWidth
521 height: parent.indicatorHeight
522 visible: controller.orientationCalTailDownSideVisible || _showAllSidesPreview
523 calState: controller.orientationCalTailDownSideState
524 calInProgressText: controller.magCalInProgress ? qsTr("Rotate") : qsTr("Hold Still")
525 imageSource: _sideRotating(calState) ? "qrc:///qmlimages/VehicleTailDownRotate.png" : "qrc:///qmlimages/VehicleTailDown.png"
526 }
527 VehicleRotationCal {
528 objectName: "sensorsCal_leftSide"
529 width: parent.indicatorWidth
530 height: parent.indicatorHeight
531 visible: controller.orientationCalLeftSideVisible || _showAllSidesPreview
532 calState: controller.orientationCalLeftSideState
533 calInProgressText: controller.magCalInProgress ? qsTr("Rotate") : qsTr("Hold Still")
534 imageSource: _sideRotating(calState) ? "qrc:///qmlimages/VehicleLeftRotate.png" : "qrc:///qmlimages/VehicleLeft.png"
535 }
536 VehicleRotationCal {
537 objectName: "sensorsCal_rightSide"
538 width: parent.indicatorWidth
539 height: parent.indicatorHeight
540 visible: controller.orientationCalRightSideVisible || _showAllSidesPreview
541 calState: controller.orientationCalRightSideState
542 calInProgressText: controller.magCalInProgress ? qsTr("Rotate") : qsTr("Hold Still")
543 imageSource: _sideRotating(calState) ? "qrc:///qmlimages/VehicleRightRotate.png" : "qrc:///qmlimages/VehicleRight.png"
544 }
545 }
546 }
547 }
548 }
549}