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 if (_sensorsHaveFixedOrientation || !showSetOrientations) {
110 return false
111 } else if (_boardOrientationChangeAllowed) {
112 return true
113 } else if (_compassOrientationChangeAllowed && !_allMagsDisabled) {
114 for (var index=0; index<_arbitrarilyLargeMaxMagIndex; index++) {
115 var magIdParam = _calMagIdParamFormat.replace("#", index)
116 if (controller.parameterExists(-1, magIdParam)) {
117 var calMagIdFact = controller.parameterExists(-1, magIdParam)
118 var calMagRotFact = controller.parameterExists(-1, _calMagRotParamFormat.replace("#", index))
119 if (calMagIdFact.value > 0 && calMagRotFact.value >= 0) {
120 // Only external compasses can set orientation
121 return true
122 }
123 }
124 }
125 return false
126 } else {
127 return false
128 }
129 }
130
131 QGCPalette { id: qgcPal; colorGroupEnabled: true }
132
133 SensorsComponentController {
134 id: controller
135 statusLog: statusTextArea
136 progressBar: progressBar
137 orientationCalAreaHelpText: orientationCalAreaHelpText
138
139 onResetStatusTextArea: statusLog.text = statusTextAreaDefaultText
140
141 onMagCalComplete: {
142 setOrientationsDialogShowBoardOrientation = false
143 setOrientationsDialogFactory.open({ title: qsTr("Compass Calibration Complete"), showRebootVehicleButton: true })
144 }
145
146 onWaitingForCancelChanged: {
147 if (controller.waitingForCancel) {
148 waitForCancelDialogFactory.open()
149 }
150 }
151
152 onCalibrationActiveChanged: {
153 if (controller.calibrationActive) {
154 globals.navigationBlockedReason = qsTr("Complete or cancel the current calibration first")
155 } else {
156 globals.navigationBlockedReason = ""
157 }
158 }
159 }
160
161 Component.onDestruction: globals.navigationBlockedReason = ""
162
163 QGCPopupDialogFactory {
164 id: waitForCancelDialogFactory
165
166 dialogComponent: waitForCancelDialogComponent
167 }
168
169 Component {
170 id: waitForCancelDialogComponent
171
172 QGCSimpleMessageDialog {
173 title: qsTr("Calibration Cancel")
174 text: qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds.")
175 buttons: 0
176
177 Connections {
178 target: controller
179
180 onWaitingForCancelChanged: {
181 if (!controller.waitingForCancel) {
182 close()
183 }
184 }
185 }
186 }
187 }
188
189 QGCPopupDialogFactory {
190 id: preCalibrationDialogFactory
191
192 dialogComponent: preCalibrationDialogComponent
193 }
194
195 Component {
196 id: preCalibrationDialogComponent
197
198 QGCPopupDialog {
199 buttons: Dialog.Cancel | Dialog.Ok
200
201 onAccepted: {
202 if (preCalibrationDialogType == "gyro") {
203 controller.calibrateGyro()
204 } else if (preCalibrationDialogType == "accel") {
205 controller.calibrateAccel()
206 } else if (preCalibrationDialogType == "level") {
207 controller.calibrateLevel()
208 } else if (preCalibrationDialogType == "compass") {
209 controller.calibrateCompass()
210 } else if (preCalibrationDialogType == "airspeed") {
211 controller.calibrateAirspeed()
212 }
213 }
214
215 ColumnLayout {
216 spacing: ScreenTools.defaultFontPixelHeight
217
218 QGCLabel {
219 Layout.minimumWidth: ScreenTools.defaultFontPixelWidth * 50
220 Layout.preferredWidth: innerColumn.width
221 wrapMode: Text.WordWrap
222 text: preCalibrationDialogHelp
223 }
224
225 Column {
226 id: innerColumn
227 spacing: parent.spacing
228
229 QGCLabel {
230 id: boardRotationHelp
231 wrapMode: Text.WordWrap
232 visible: !_sensorsHaveFixedOrientation && (preCalibrationDialogType == "accel" || preCalibrationDialogType == "compass")
233 text: qsTr("Set autopilot orientation before calibrating.")
234 }
235
236 Column {
237 visible: boardRotationHelp.visible
238 QGCLabel { text: qsTr("Autopilot Orientation") }
239
240 FactComboBox {
241 sizeToContents: true
242 fact: sens_board_rot
243 }
244
245 QGCLabel {
246 wrapMode: Text.WordWrap
247 text: qsTr("ROTATION_NONE indicates component points in direction of flight.")
248 }
249 }
250
251 QGCLabel {
252 wrapMode: Text.WordWrap
253 text: qsTr("Click Ok to start calibration.")
254 }
255 }
256 }
257 }
258 }
259
260 property bool setOrientationsDialogShowBoardOrientation: true
261
262 QGCPopupDialogFactory {
263 id: setOrientationsDialogFactory
264
265 dialogComponent: setOrientationsDialogComponent
266 }
267
268 Component {
269 id: setOrientationsDialogComponent
270
271 QGCPopupDialog {
272 buttons: Dialog.Ok
273
274 property bool showRebootVehicleButton: true
275
276 ColumnLayout {
277 spacing: ScreenTools.defaultFontPixelHeight
278
279 QGCLabel {
280 text: qsTr("Reboot the vehicle prior to flight.")
281 visible: showRebootVehicleButton
282 }
283
284 QGCButton {
285 text: qsTr("Reboot Vehicle")
286 visible: showRebootVehicleButton
287 onClicked: { controller.vehicle.rebootVehicle(); close() }
288 }
289
290 QGCLabel {
291 text: qsTr("Adjust orientations as needed.\n\nROTATION_NONE indicates component points in direction of flight.")
292 visible: _boardOrientationChangeAllowed || (_compassOrientationChangeAllowed && currentExternalMagCount() !== 0)
293 }
294
295 Column {
296 visible: _boardOrientationChangeAllowed
297
298 QGCLabel {
299 text: qsTr("Autopilot Orientation")
300 }
301
302 FactComboBox {
303 sizeToContents: true
304 fact: sens_board_rot
305 }
306 }
307
308 Repeater {
309 model: _compassOrientationChangeAllowed ? currentMagParamCount() : 0
310
311 Column {
312 // id > = signals compass available, rot < 0 signals internal compass
313 visible: calMagIdFact.value > 0 && calMagRotFact.value >= 0
314
315 property Fact calMagIdFact: controller.getParameterFact(-1, _calMagIdParamFormat.replace("#", index))
316 property Fact calMagRotFact: controller.getParameterFact(-1, _calMagRotParamFormat.replace("#", index))
317
318 QGCLabel {
319 text: qsTr("Mag %1 Orientation").arg(index)
320 }
321
322 FactComboBox {
323 sizeToContents: true
324 fact: parent.calMagRotFact
325 }
326 }
327 }
328 } // Column
329 } // QGCPopupDialog
330 } // Component - setOrientationsDialogComponent
331
332 property string sectionNameFilter: ""
333
334 function sectionVisible(name) {
335 if (name === qsTr("Compass")) return !_allMagsDisabled && QGroundControl.corePlugin.options.showSensorCalibrationCompass && showSensorCalibrationCompass
336 if (name === qsTr("Gyroscope")) return QGroundControl.corePlugin.options.showSensorCalibrationGyro && showSensorCalibrationGyro
337 if (name === qsTr("Accelerometer")) return QGroundControl.corePlugin.options.showSensorCalibrationAccel && showSensorCalibrationAccel
338 if (name === qsTr("Level Horizon")) return QGroundControl.corePlugin.options.showSensorCalibrationLevel && showSensorCalibrationLevel
339 if (name === qsTr("Airspeed")) return vehicleComponent.airspeedCalSupported && QGroundControl.corePlugin.options.showSensorCalibrationAirspeed && showSensorCalibrationAirspeed
340 if (name === qsTr("Orientations")) return orientationsButtonVisible()
341 return true
342 }
343
344 function _startCalibration(type, help, title) {
345 preCalibrationDialogType = type
346 preCalibrationDialogHelp = help
347 preCalibrationDialogFactory.open({ title: title })
348 }
349
350 property bool _showOrientationPreview: !controller.calibrationActive &&
351 (sectionNameFilter === qsTr("Accelerometer") || sectionNameFilter === qsTr("Compass") || sectionNameFilter === qsTr("Gyroscope"))
352
353 property bool _showAllSidesPreview: _showOrientationPreview &&
354 (sectionNameFilter === qsTr("Accelerometer") || sectionNameFilter === qsTr("Compass"))
355
356 property bool _showDownOnlyPreview: _showOrientationPreview &&
357 sectionNameFilter === qsTr("Gyroscope")
358
359 property bool _showStatusPreview: !controller.calibrationActive &&
360 (sectionNameFilter === qsTr("Level Horizon") || sectionNameFilter === qsTr("Airspeed"))
361
362 ColumnLayout {
363 anchors.fill: parent
364 spacing: 0
365
366 // Calibration trigger buttons — one per section, shown based on sectionNameFilter
367 ColumnLayout {
368 Layout.fillWidth: true
369 spacing: ScreenTools.defaultFontPixelHeight / 2
370 visible: !controller.calibrationActive
371
372 QGCButton {
373 Layout.fillWidth: true
374 text: qsTr("Calibrate Compass")
375 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Compass")
376 onClicked: _startCalibration("compass", compassHelp, qsTr("Calibrate Compass"))
377 }
378
379 QGCButton {
380 Layout.fillWidth: true
381 text: qsTr("Calibrate Gyroscope")
382 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Gyroscope")
383 onClicked: _startCalibration("gyro", gyroHelp, qsTr("Calibrate Gyro"))
384 }
385
386 QGCButton {
387 Layout.fillWidth: true
388 text: qsTr("Calibrate Accelerometer")
389 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Accelerometer")
390 onClicked: _startCalibration("accel", accelHelp, qsTr("Calibrate Accelerometer"))
391 }
392
393 QGCButton {
394 Layout.fillWidth: true
395 text: qsTr("Level Horizon")
396 enabled: cal_acc0_id.value !== 0 && cal_gyro0_id.value !== 0
397 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Level Horizon")
398 onClicked: _startCalibration("level", levelHelp, qsTr("Level Horizon"))
399 }
400
401 QGCButton {
402 Layout.fillWidth: true
403 text: qsTr("Calibrate Airspeed")
404 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Airspeed")
405 onClicked: _startCalibration("airspeed", airspeedHelp, qsTr("Calibrate Airspeed"))
406 }
407
408 QGCButton {
409 Layout.fillWidth: true
410 text: qsTr("Set Orientations")
411 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Orientations")
412 onClicked: {
413 setOrientationsDialogShowBoardOrientation = true
414 setOrientationsDialogFactory.open({ title: qsTr("Set Orientations"), showRebootVehicleButton: false })
415 }
416 }
417
418 QGCButton {
419 Layout.fillWidth: true
420 text: qsTr("Factory Reset")
421 visible: sectionNameFilter === "" || sectionNameFilter === qsTr("Orientations")
422 onClicked: controller.resetFactoryParameters()
423 }
424
425 QGCButton {
426 Layout.fillWidth: true
427 text: qsTr("Next")
428 visible: showNextButton
429 onClicked: _root.nextButtonClicked()
430 }
431 }
432
433 // Active calibration area — visible during calibration
434 RowLayout {
435 Layout.fillWidth: true
436 visible: controller.calibrationActive
437 spacing: ScreenTools.defaultFontPixelWidth
438
439 ProgressBar {
440 id: progressBar
441 Layout.fillWidth: true
442 }
443
444 QGCButton {
445 text: qsTr("Cancel")
446 onClicked: controller.cancelCalibration()
447 }
448 }
449
450 Item {
451 Layout.fillWidth: true
452 Layout.fillHeight: true
453 visible: controller.calibrationActive || _showOrientationPreview || _showStatusPreview
454
455 TextArea {
456 id: statusTextArea
457 anchors.fill: parent
458 readOnly: true
459 visible: !orientationCalArea.visible
460 text: statusTextAreaDefaultText
461 color: qgcPal.text
462 background: Rectangle { color: qgcPal.windowShade }
463 }
464
465 Rectangle {
466 id: orientationCalArea
467 anchors.fill: parent
468 visible: controller.showOrientationCalArea || _showOrientationPreview
469 color: qgcPal.windowShade
470
471 QGCLabel {
472 id: orientationCalAreaHelpText
473 anchors.margins: ScreenTools.defaultFontPixelWidth
474 anchors.top: orientationCalArea.top
475 anchors.left: orientationCalArea.left
476 width: parent.width
477 wrapMode: Text.WordWrap
478 font.pointSize: ScreenTools.mediumFontPointSize
479 visible: text !== ""
480 }
481
482 Flow {
483 anchors.topMargin: ScreenTools.defaultFontPixelWidth
484 anchors.top: orientationCalAreaHelpText.bottom
485 anchors.bottom: parent.bottom
486 anchors.left: parent.left
487 anchors.right: parent.right
488 spacing: ScreenTools.defaultFontPixelWidth / 2
489
490 property real indicatorWidth: (width / 3) - (spacing * 2)
491 property real indicatorHeight: (height / 2) - spacing
492
493 VehicleRotationCal {
494 width: parent.indicatorWidth
495 height: parent.indicatorHeight
496 visible: controller.orientationCalDownSideVisible || _showAllSidesPreview || _showDownOnlyPreview
497 calValid: controller.orientationCalDownSideDone && !_showOrientationPreview
498 calInProgress: controller.orientationCalDownSideInProgress
499 calInProgressText: controller.orientationCalDownSideRotate ? qsTr("Rotate") : qsTr("Hold Still")
500 imageSource: controller.orientationCalDownSideRotate ? "qrc:///qmlimages/VehicleDownRotate.png" : "qrc:///qmlimages/VehicleDown.png"
501 }
502 VehicleRotationCal {
503 width: parent.indicatorWidth
504 height: parent.indicatorHeight
505 visible: controller.orientationCalUpsideDownSideVisible || _showAllSidesPreview
506 calValid: controller.orientationCalUpsideDownSideDone && !_showOrientationPreview
507 calInProgress: controller.orientationCalUpsideDownSideInProgress
508 calInProgressText: controller.orientationCalUpsideDownSideRotate ? qsTr("Rotate") : qsTr("Hold Still")
509 imageSource: controller.orientationCalUpsideDownSideRotate ? "qrc:///qmlimages/VehicleUpsideDownRotate.png" : "qrc:///qmlimages/VehicleUpsideDown.png"
510 }
511 VehicleRotationCal {
512 width: parent.indicatorWidth
513 height: parent.indicatorHeight
514 visible: controller.orientationCalNoseDownSideVisible || _showAllSidesPreview
515 calValid: controller.orientationCalNoseDownSideDone && !_showOrientationPreview
516 calInProgress: controller.orientationCalNoseDownSideInProgress
517 calInProgressText: controller.orientationCalNoseDownSideRotate ? qsTr("Rotate") : qsTr("Hold Still")
518 imageSource: controller.orientationCalNoseDownSideRotate ? "qrc:///qmlimages/VehicleNoseDownRotate.png" : "qrc:///qmlimages/VehicleNoseDown.png"
519 }
520 VehicleRotationCal {
521 width: parent.indicatorWidth
522 height: parent.indicatorHeight
523 visible: controller.orientationCalTailDownSideVisible || _showAllSidesPreview
524 calValid: controller.orientationCalTailDownSideDone && !_showOrientationPreview
525 calInProgress: controller.orientationCalTailDownSideInProgress
526 calInProgressText: controller.orientationCalTailDownSideRotate ? qsTr("Rotate") : qsTr("Hold Still")
527 imageSource: controller.orientationCalTailDownSideRotate ? "qrc:///qmlimages/VehicleTailDownRotate.png" : "qrc:///qmlimages/VehicleTailDown.png"
528 }
529 VehicleRotationCal {
530 width: parent.indicatorWidth
531 height: parent.indicatorHeight
532 visible: controller.orientationCalLeftSideVisible || _showAllSidesPreview
533 calValid: controller.orientationCalLeftSideDone && !_showOrientationPreview
534 calInProgress: controller.orientationCalLeftSideInProgress
535 calInProgressText: controller.orientationCalLeftSideRotate ? qsTr("Rotate") : qsTr("Hold Still")
536 imageSource: controller.orientationCalLeftSideRotate ? "qrc:///qmlimages/VehicleLeftRotate.png" : "qrc:///qmlimages/VehicleLeft.png"
537 }
538 VehicleRotationCal {
539 width: parent.indicatorWidth
540 height: parent.indicatorHeight
541 visible: controller.orientationCalRightSideVisible || _showAllSidesPreview
542 calValid: controller.orientationCalRightSideDone && !_showOrientationPreview
543 calInProgress: controller.orientationCalRightSideInProgress
544 calInProgressText: controller.orientationCalRightSideRotate ? qsTr("Rotate") : qsTr("Hold Still")
545 imageSource: controller.orientationCalRightSideRotate ? "qrc:///qmlimages/VehicleRightRotate.png" : "qrc:///qmlimages/VehicleRight.png"
546 }
547 }
548 }
549 }
550 }
551}