diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index da5e40132490e10b744caa4bc7d9024a395bd2ad..9d95909a76994342dec5de2003f3b9112626031b 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -554,6 +554,8 @@ HEADERS+= \ src/AutoPilotPlugins/APM/APMRadioComponent.h \ src/AutoPilotPlugins/APM/APMFlightModesComponent.h \ src/AutoPilotPlugins/APM/APMFlightModesComponentController.h \ + src/AutoPilotPlugins/APM/APMSensorsComponent.h \ + src/AutoPilotPlugins/APM/APMSensorsComponentController.h \ src/AutoPilotPlugins/Common/RadioComponentController.h \ src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h \ src/AutoPilotPlugins/PX4/AirframeComponent.h \ @@ -601,6 +603,8 @@ SOURCES += \ src/AutoPilotPlugins/APM/APMRadioComponent.cc \ src/AutoPilotPlugins/APM/APMFlightModesComponent.cc \ src/AutoPilotPlugins/APM/APMFlightModesComponentController.cc \ + src/AutoPilotPlugins/APM/APMSensorsComponent.cc \ + src/AutoPilotPlugins/APM/APMSensorsComponentController.cc \ src/AutoPilotPlugins/Common/RadioComponentController.cc \ src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc \ src/AutoPilotPlugins/PX4/AirframeComponent.cc \ diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index df569ec384b32ef02d97f20267f5d3d16f40dd07..d48a6f478bd352fc5d2c99173dff4e441430c2ca 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -111,6 +111,8 @@ src/AutoPilotPlugins/PX4/SensorsComponent.qml src/AutoPilotPlugins/PX4/SensorsComponentSummary.qml src/AutoPilotPlugins/PX4/SensorsComponentSummaryFixedWing.qml + src/AutoPilotPlugins/APM/APMSensorsComponent.qml + src/AutoPilotPlugins/APM/APMSensorsComponentSummary.qml src/VehicleSetup/SetupParameterEditor.qml src/VehicleSetup/SetupView.qml src/test.qml diff --git a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc index f29cd98c221544661ec4d544d9e76c09a12a69b8..93d9fe19ee755fa589e35ee0786ca7c183e8dac9 100644 --- a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc +++ b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc @@ -1,5 +1,5 @@ /*===================================================================== - + QGroundControl Open Source Ground Control Station (c) 2009 - 2015 QGROUNDCONTROL PROJECT @@ -50,19 +50,36 @@ const QVariantList& APMAutoPilotPlugin::vehicleComponents(void) if (parametersReady()) { _airframeComponent = new APMAirframeComponent(_vehicle, this); - Q_CHECK_PTR(_airframeComponent); - _airframeComponent->setupTriggerSignals(); - _components.append(QVariant::fromValue((VehicleComponent*)_airframeComponent)); + if (_airframeComponent) { + _airframeComponent->setupTriggerSignals(); + _components.append(QVariant::fromValue((VehicleComponent*)_airframeComponent)); + } else { + qWarning() << "new APMAirframeComponent failed"; + } _flightModesComponent = new APMFlightModesComponent(_vehicle, this); - Q_CHECK_PTR(_flightModesComponent); - _flightModesComponent->setupTriggerSignals(); - _components.append(QVariant::fromValue((VehicleComponent*)_flightModesComponent)); + if (_flightModesComponent) { + _flightModesComponent->setupTriggerSignals(); + _components.append(QVariant::fromValue((VehicleComponent*)_flightModesComponent)); + } else { + qWarning() << "new APMFlightModesComponent failed"; + } _radioComponent = new APMRadioComponent(_vehicle, this); - Q_CHECK_PTR(_radioComponent); - _radioComponent->setupTriggerSignals(); - _components.append(QVariant::fromValue((VehicleComponent*)_radioComponent)); + if (_radioComponent) { + _radioComponent->setupTriggerSignals(); + _components.append(QVariant::fromValue((VehicleComponent*)_radioComponent)); + } else { + qWarning() << "new APMRadioComponent failed"; + } + + _sensorsComponent = new APMSensorsComponent(_vehicle, this); + if (_sensorsComponent) { + _sensorsComponent->setupTriggerSignals(); + _components.append(QVariant::fromValue((VehicleComponent*)_sensorsComponent)); + } else { + qWarning() << "new APMSensorsComponent failed"; + } } else { qWarning() << "Call to vehicleCompenents prior to parametersReady"; } @@ -76,17 +93,17 @@ void APMAutoPilotPlugin::_parametersReadyPreChecks(bool missingParameters) { #if 0 I believe APM has parameter version stamp, we should check that - - // Check for older parameter version set - // FIXME: Firmware is moving to version stamp parameter set. Once that is complete the version stamp - // should be used instead. - if (parameterExists(FactSystem::defaultComponentId, "SENS_GYRO_XOFF")) { + + // Check for older parameter version set + // FIXME: Firmware is moving to version stamp parameter set. Once that is complete the version stamp + // should be used instead. + if (parameterExists(FactSystem::defaultComponentId, "SENS_GYRO_XOFF")) { _incorrectParameterVersion = true; qgcApp()->showMessage("This version of GroundControl can only perform vehicle setup on a newer version of firmware. " "Please perform a Firmware Upgrade if you wish to use Vehicle Setup."); - } + } #endif - + _parametersReady = true; _missingParameters = missingParameters; emit missingParametersChanged(_missingParameters); diff --git a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h index 60691ce8bc790f91c270b3bd8a015fbe42ba8dff..93b564812dfdf835e03b932276a1f95d65053bb8 100644 --- a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h +++ b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h @@ -27,8 +27,9 @@ #include "AutoPilotPlugin.h" #include "Vehicle.h" #include "APMAirframeComponent.h" -#include "APMRadioComponent.h" #include "APMFlightModesComponent.h" +#include "APMRadioComponent.h" +#include "APMSensorsComponent.h" /// This is the APM specific implementation of the AutoPilot class. class APMAutoPilotPlugin : public AutoPilotPlugin @@ -45,6 +46,7 @@ public: APMAirframeComponent* airframeComponent (void) { return _airframeComponent; } APMFlightModesComponent* flightModesComponent(void) { return _flightModesComponent; } APMRadioComponent* radioComponent (void) { return _radioComponent; } + APMSensorsComponent* sensorsComponent (void) { return _sensorsComponent; } public slots: // FIXME: This is public until we restructure AutoPilotPlugin/FirmwarePlugin/Vehicle @@ -57,6 +59,7 @@ private: APMAirframeComponent* _airframeComponent; APMFlightModesComponent* _flightModesComponent; APMRadioComponent* _radioComponent; + APMSensorsComponent* _sensorsComponent; }; #endif diff --git a/src/AutoPilotPlugins/APM/APMSensorsComponent.cc b/src/AutoPilotPlugins/APM/APMSensorsComponent.cc new file mode 100644 index 0000000000000000000000000000000000000000..da9ed08a5e57a75deecddfa0db0fefa734c0181a --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMSensorsComponent.cc @@ -0,0 +1,116 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "APMSensorsComponent.h" +#include "APMAutoPilotPlugin.h" +#include "APMSensorsComponentController.h" + +// These two list must be kept in sync + +APMSensorsComponent::APMSensorsComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) : + APMComponent(vehicle, autopilot, parent), + _name(tr("Sensors")) +{ + +} + +QString APMSensorsComponent::name(void) const +{ + return _name; +} + +QString APMSensorsComponent::description(void) const +{ + return tr("The Sensors Component allows you to calibrate the sensors within your vehicle. " + "Prior to flight you must calibrate the Magnetometer, Gyroscope and Accelerometer."); +} + +QString APMSensorsComponent::iconResource(void) const +{ + return "/qmlimages/SensorsComponentIcon.png"; +} + +bool APMSensorsComponent::requiresSetup(void) const +{ + return true; +} + +bool APMSensorsComponent::setupComplete(void) const +{ + foreach(QString triggerParam, setupCompleteChangedTriggerList()) { + if (_autopilot->getParameterFact(FactSystem::defaultComponentId, triggerParam)->rawValue().toFloat() == 0.0f) { + return false; + } + } + + return true; +} + +QString APMSensorsComponent::setupStateDescription(void) const +{ + const char* stateDescription; + + if (requiresSetup()) { + stateDescription = "Requires calibration"; + } else { + stateDescription = "Calibrated"; + } + return QString(stateDescription); +} + +QStringList APMSensorsComponent::setupCompleteChangedTriggerList(void) const +{ + QStringList triggers; + + triggers << "COMPASS_OFS_X" << "COMPASS_OFS_X" << "COMPASS_OFS_X" + << "INS_ACCOFFS_X" << "INS_ACCOFFS_Y" << "INS_ACCOFFS_Z"; + + return triggers; +} + +QStringList APMSensorsComponent::paramFilterList(void) const +{ + return QStringList(); +} + +QUrl APMSensorsComponent::setupSource(void) const +{ + return QUrl::fromUserInput("qrc:/qml/APMSensorsComponent.qml"); +} + +QUrl APMSensorsComponent::summaryQmlSource(void) const +{ + return QUrl::fromUserInput("qrc:/qml/APMSensorsComponentSummary.qml"); +} + +QString APMSensorsComponent::prerequisiteSetup(void) const +{ + APMAutoPilotPlugin* plugin = dynamic_cast(_autopilot); + Q_ASSERT(plugin); + + if (!plugin->airframeComponent()->setupComplete()) { + return plugin->airframeComponent()->name(); + } + + return QString(); +} diff --git a/src/AutoPilotPlugins/APM/APMSensorsComponent.h b/src/AutoPilotPlugins/APM/APMSensorsComponent.h new file mode 100644 index 0000000000000000000000000000000000000000..aa53a5bbec815dd0cf68cf274266b55e2c6fa42c --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMSensorsComponent.h @@ -0,0 +1,56 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef APMSensorsComponent_H +#define APMSensorsComponent_H + +#include "APMComponent.h" + +class APMSensorsComponent : public APMComponent +{ + Q_OBJECT + +public: + APMSensorsComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL); + + // Virtuals from APMComponent + virtual QStringList setupCompleteChangedTriggerList(void) const; + + // Virtuals from VehicleComponent + virtual QString name(void) const; + virtual QString description(void) const; + virtual QString iconResource(void) const; + virtual bool requiresSetup(void) const; + virtual bool setupComplete(void) const; + virtual QString setupStateDescription(void) const; + virtual QUrl setupSource(void) const; + virtual QStringList paramFilterList(void) const; + virtual QUrl summaryQmlSource(void) const; + virtual QString prerequisiteSetup(void) const; + +private: + const QString _name; + QVariantList _summaryItems; +}; + +#endif diff --git a/src/AutoPilotPlugins/APM/APMSensorsComponent.qml b/src/AutoPilotPlugins/APM/APMSensorsComponent.qml new file mode 100644 index 0000000000000000000000000000000000000000..4fd3d21a5bd03113d52cf945cf76abcd24dadda9 --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMSensorsComponent.qml @@ -0,0 +1,565 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2015 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 +import QtQuick.Dialogs 1.2 + +import QGroundControl.FactSystem 1.0 +import QGroundControl.FactControls 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Controllers 1.0 + +QGCView { + id: rootQGCView + viewPanel: panel + + // Help text which is shown both in the status text area prior to pressing a cal button and in the + // pre-calibration dialog. + + readonly property string boardRotationText: "If the autopilot is mounted in flight direction, leave the default value (None)" + readonly property string compassRotationText: "If the compass or GPS module is mounted in flight direction, leave the default value (None)" + + readonly property string compassHelp: "For Compass calibration you will need to rotate your vehicle through a number of positions. Most users prefer to do this wirelessly with the telemetry link." + readonly property string gyroHelp: "For Gyroscope calibration you will need to place your vehicle on a surface and leave it still." + readonly property string accelHelp: "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." + readonly property string levelHelp: "To level the horizon you need to place the vehicle in its level flight position and press OK." + readonly property string airspeedHelp: "For Airspeed calibration you will need to keep your airspeed sensor out of any wind and then blow across the sensor." + + readonly property string statusTextAreaDefaultText: "Start the individual calibration steps by clicking one of the buttons above." + + // Used to pass what type of calibration is being performed to the preCalibrationDialog + property string preCalibrationDialogType + + // Used to pass help text to the preCalibrationDialog dialog + property string preCalibrationDialogHelp + + readonly property int sideBarH1PointSize: ScreenTools.mediumFontPixelSize + readonly property int mainTextH1PointSize: ScreenTools.mediumFontPixelSize // Seems to be unused + + readonly property int rotationColumnWidth: 250 + readonly property var rotations: [ + "None", + "Yaw 45", + "Yaw 90", + "Yaw 135", + "Yaw 180", + "Yaw 225", + "Yaw 270", + "Yaw 315", + "Roll 180", + "Roll 180. Yaw 45", + "Roll 180. Yaw 90", + "Roll 180. Yaw 135", + "Pitch 180", + "Roll 180. Yaw 225", + "Roll 180, Yaw 270", + "Roll 180, Yaw 315", + "Roll 90", + "Roll 90, Yaw 45", + "Roll 90, Yaw 90", + "Roll 90, Yaw 135", + "Roll 270", + "Roll 270, Yaw 45", + "Roll 270, Yaw 90", + "Roll 270, Yaw 136", + "Pitch 90", + "Pitch 270", + "Pitch 180, Yaw 90", + "Pitch 180, Yaw 270", + "Roll 90, Pitch 90", + "Roll 180, Pitch 90", + "Roll 270, Pitch 90", + "Roll 90, Pitch 180", + "Roll 270, Pitch 180", + "Roll 90, Pitch 270", + "Roll 180, Pitch 270", + "Roll 270, Pitch 270", + "Roll 90, Pitch 180, Yaw 90", + "Roll 90, Yaw 270", + "Yaw 293, Pitch 68, Roll 90", + ] + + property Fact cal_mag0_id: controller.getParameterFact(-1, "COMPASS_DEV_ID") + property Fact cal_mag1_id: controller.getParameterFact(-1, "COMPASS_DEV_ID2") + property Fact cal_mag2_id: controller.getParameterFact(-1, "COMPASS_DEV_ID3") + property Fact cal_mag0_rot: controller.getParameterFact(-1, "COMPASS_ORIENT") + property Fact cal_mag1_rot: controller.getParameterFact(-1, "COMPASS_ORIENT2") + property Fact cal_mag2_rot: controller.getParameterFact(-1, "COMPASS_ORIENT3") + + property Fact sens_board_rot: controller.getParameterFact(-1, "AHRS_ORIENTATION") + + /* + property Fact cal_gyro0_id: controller.getParameterFact(-1, "CAL_GYRO0_ID") + property Fact cal_acc0_id: controller.getParameterFact(-1, "CAL_ACC0_ID") + + property Fact sens_board_x_off: controller.getParameterFact(-1, "SENS_BOARD_X_OFF") + property Fact sens_dpres_off: controller.getParameterFact(-1, "SENS_DPRES_OFF") + */ + + property Fact ins_accoffs_x: controller.getParameterFact(-1, "INS_ACCOFFS_X") + property Fact ins_accoffs_y: controller.getParameterFact(-1, "INS_ACCOFFS_Y") + property Fact ins_accoffs_z: controller.getParameterFact(-1, "INS_ACCOFFS_Z") + + property Fact compass_ofs_x: controller.getParameterFact(-1, "COMPASS_OFS_X") + property Fact compass_ofs_y: controller.getParameterFact(-1, "COMPASS_OFS_Y") + property Fact compass_ofs_z: controller.getParameterFact(-1, "COMPASS_OFS_Z") + + property bool accelCalNeeded: ins_accoffs_x.value == 0 && ins_accoffs_y.value == 0 && ins_accoffs_z.value == 0 + property bool compassCalNeeded: compass_ofs_x.value == 0 && compass_ofs_y.value == 0 && compass_ofs_y.value == 0 + + // Id > = signals compass available, rot < 0 signals internal compass + property bool showCompass0Rot: cal_mag0_id.value > 0 && cal_mag0_rot.value >= 0 + property bool showCompass1Rot: cal_mag1_id.value > 0 && cal_mag1_rot.value >= 0 + property bool showCompass2Rot: cal_mag2_id.value > 0 && cal_mag2_rot.value >= 0 + + APMSensorsComponentController { + id: controller + factPanel: panel + statusLog: statusTextArea + progressBar: progressBar + compassButton: compassButton + accelButton: accelButton + nextButton: nextButton + cancelButton: cancelButton + orientationCalAreaHelpText: orientationCalAreaHelpText + + onResetStatusTextArea: statusLog.text = statusTextAreaDefaultText + + onSetCompassRotations: { + if (showCompass0Rot || showCompass1Rot || showCompass2Rot) { + showDialog(compassRotationDialogComponent, "Set Compass Rotation(s)", 50, StandardButton.Ok) + } + } + + onWaitingForCancelChanged: { + if (controller.waitingForCancel) { + showMessage("Calibration Cancel", "Waiting for Vehicle to response to Cancel. This may take a few seconds.", 0) + } else { + hideDialog() + } + } + } + + QGCPalette { id: qgcPal; colorGroupEnabled: panel.enabled } + + Component { + id: preCalibrationDialogComponent + + QGCViewDialog { + id: preCalibrationDialog + + function accept() { + if (preCalibrationDialogType == "gyro") { + controller.calibrateGyro() + } else if (preCalibrationDialogType == "accel") { + controller.calibrateAccel() + } else if (preCalibrationDialogType == "level") { + controller.calibrateLevel() + } else if (preCalibrationDialogType == "compass") { + controller.calibrateCompass() + } else if (preCalibrationDialogType == "airspeed") { + controller.calibrateAirspeed() + } + preCalibrationDialog.hideDialog() + } + + Column { + anchors.fill: parent + spacing: 5 + + QGCLabel { + width: parent.width + wrapMode: Text.WordWrap + text: preCalibrationDialogHelp + } + + QGCLabel { + width: parent.width + wrapMode: Text.WordWrap + visible: (preCalibrationDialogType != "airspeed") && (preCalibrationDialogType != "gyro") + text: boardRotationText + } + + FactComboBox { + width: rotationColumnWidth + model: rotations + visible: preCalibrationDialogType != "airspeed" && (preCalibrationDialogType != "gyro") + fact: sens_board_rot + } + } + } + } + + Component { + id: compassRotationDialogComponent + + QGCViewDialog { + id: compassRotationDialog + + Column { + anchors.fill: parent + spacing: ScreenTools.defaultFontPixelHeight + + QGCLabel { + width: parent.width + wrapMode: Text.WordWrap + text: compassRotationText + } + + // Compass 0 rotation + Component { + id: compass0ComponentLabel + + QGCLabel { + font.pixelSize: sideBarH1PointSize + text: "External Compass Orientation" + } + + } + Component { + id: compass0ComponentCombo + + FactComboBox { + id: compass0RotationCombo + width: rotationColumnWidth + model: rotations + fact: cal_mag0_rot + } + } + Loader { sourceComponent: showCompass0Rot ? compass0ComponentLabel : null } + Loader { sourceComponent: showCompass0Rot ? compass0ComponentCombo : null } + // Compass 1 rotation + Component { + id: compass1ComponentLabel + + QGCLabel { text: "Compass 1 Orientation" } + } + Component { + id: compass1ComponentCombo + + FactComboBox { + id: compass1RotationCombo + width: rotationColumnWidth + model: rotations + fact: cal_mag1_rot + } + } + Loader { sourceComponent: showCompass1Rot ? compass1ComponentLabel : null } + Loader { sourceComponent: showCompass1Rot ? compass1ComponentCombo : null } + + // Compass 2 rotation + Component { + id: compass2ComponentLabel + + QGCLabel { text: "Compass 2 Orientation" } + } + Component { + id: compass2ComponentCombo + + FactComboBox { + id: compass1RotationCombo + width: rotationColumnWidth + model: rotations + fact: cal_mag2_rot + } + } + Loader { sourceComponent: showCompass2Rot ? compass2ComponentLabel : null } + Loader { sourceComponent: showCompass2Rot ? compass2ComponentCombo : null } + } // Column + } // QGCViewDialog + } // Component - compassRotationDialogComponent + + QGCViewPanel { + id: panel + anchors.fill: parent + + Column { + anchors.fill: parent + + Row { + readonly property int buttonWidth: ScreenTools.defaultFontPixelWidth * 15 + + spacing: ScreenTools.defaultFontPixelWidth + + QGCLabel { text: "Calibrate:"; anchors.baseline: compassButton.baseline } + + IndicatorButton { + id: compassButton + width: parent.buttonWidth + text: "Compass - NYI" + indicatorGreen: !compassCalNeeded + + onClicked: { + preCalibrationDialogType = "compass" + preCalibrationDialogHelp = compassHelp + showDialog(preCalibrationDialogComponent, "Calibrate Compass", 50, StandardButton.Cancel | StandardButton.Ok) + } + } + + IndicatorButton { + id: accelButton + width: parent.buttonWidth + text: "Accelerometer" + indicatorGreen: !accelCalNeeded + + onClicked: { + preCalibrationDialogType = "accel" + preCalibrationDialogHelp = accelHelp + showDialog(preCalibrationDialogComponent, "Calibrate Accelerometer", 50, StandardButton.Cancel | StandardButton.Ok) + } + } + QGCButton { + id: nextButton + showBorder: true + text: "Next" + enabled: false + onClicked: controller.nextClicked() + } + + QGCButton { + id: cancelButton + showBorder: true + text: "Cancel" + enabled: false + onClicked: controller.cancelCalibration() + } + } + + Item { height: ScreenTools.defaultFontPixelHeight; width: 10 } // spacer + + ProgressBar { + id: progressBar + width: parent.width - rotationColumnWidth + } + + Item { height: ScreenTools.defaultFontPixelHeight; width: 10 } // spacer + + Item { + property int calDisplayAreaWidth: parent.width - rotationColumnWidth + + width: parent.width + height: parent.height - y + + TextArea { + id: statusTextArea + width: parent.calDisplayAreaWidth + height: parent.height + readOnly: true + frameVisible: false + text: statusTextAreaDefaultText + + style: TextAreaStyle { + textColor: qgcPal.text + backgroundColor: qgcPal.windowShade + } + } + + Rectangle { + id: orientationCalArea + width: parent.calDisplayAreaWidth + height: parent.height + visible: controller.showOrientationCalArea + color: qgcPal.windowShade + + QGCLabel { + id: orientationCalAreaHelpText + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.top: orientationCalArea.top + anchors.left: orientationCalArea.left + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: ScreenTools.mediumFontPixelSize + } + + Flow { + anchors.topMargin: ScreenTools.defaultFontPixelWidth + anchors.top: orientationCalAreaHelpText.bottom + anchors.left: orientationCalAreaHelpText.left + width: parent.width + height: parent.height - orientationCalAreaHelpText.implicitHeight + spacing: ScreenTools.defaultFontPixelWidth + + VehicleRotationCal { + visible: controller.orientationCalDownSideVisible + calValid: controller.orientationCalDownSideDone + calInProgress: controller.orientationCalDownSideInProgress + calInProgressText: controller.orientationCalDownSideRotate ? "Rotate" : "Hold Still" + imageSource: controller.orientationCalDownSideRotate ? "qrc:///qmlimages/VehicleDownRotate.png" : "qrc:///qmlimages/VehicleDown.png" + } + VehicleRotationCal { + visible: controller.orientationCalUpsideDownSideVisible + calValid: controller.orientationCalUpsideDownSideDone + calInProgress: controller.orientationCalUpsideDownSideInProgress + calInProgressText: controller.orientationCalUpsideDownSideRotate ? "Rotate" : "Hold Still" + imageSource: "qrc:///qmlimages/VehicleUpsideDown.png" + } + VehicleRotationCal { + visible: controller.orientationCalNoseDownSideVisible + calValid: controller.orientationCalNoseDownSideDone + calInProgress: controller.orientationCalNoseDownSideInProgress + calInProgressText: controller.orientationCalNoseDownSideRotate ? "Rotate" : "Hold Still" + imageSource: controller.orientationCalNoseDownSideRotate ? "qrc:///qmlimages/VehicleNoseDownRotate.png" : "qrc:///qmlimages/VehicleNoseDown.png" + } + VehicleRotationCal { + visible: controller.orientationCalTailDownSideVisible + calValid: controller.orientationCalTailDownSideDone + calInProgress: controller.orientationCalTailDownSideInProgress + calInProgressText: controller.orientationCalTailDownSideRotate ? "Rotate" : "Hold Still" + imageSource: "qrc:///qmlimages/VehicleTailDown.png" + } + VehicleRotationCal { + visible: controller.orientationCalLeftSideVisible + calValid: controller.orientationCalLeftSideDone + calInProgress: controller.orientationCalLeftSideInProgress + calInProgressText: controller.orientationCalLeftSideRotate ? "Rotate" : "Hold Still" + imageSource: controller.orientationCalLeftSideRotate ? "qrc:///qmlimages/VehicleLeftRotate.png" : "qrc:///qmlimages/VehicleLeft.png" + } + VehicleRotationCal { + visible: controller.orientationCalRightSideVisible + calValid: controller.orientationCalRightSideDone + calInProgress: controller.orientationCalRightSideInProgress + calInProgressText: controller.orientationCalRightSideRotate ? "Rotate" : "Hold Still" + imageSource: "qrc:///qmlimages/VehicleRight.png" + } + } + } + + Column { + anchors.leftMargin: ScreenTools.defaultFontPixelWidth + anchors.left: orientationCalArea.right + x: parent.width - rotationColumnWidth + spacing: ScreenTools.defaultFontPixelWidth + + Column { + spacing: ScreenTools.defaultFontPixelWidth + + QGCLabel { + font.pixelSize: sideBarH1PointSize + text: "Autopilot Orientation" + } + + QGCLabel { + width: parent.width + wrapMode: Text.WordWrap + text: boardRotationText + } + + FactComboBox { + id: boardRotationCombo + width: rotationColumnWidth; + model: rotations + fact: sens_board_rot + } + } + + Column { + spacing: ScreenTools.defaultFontPixelWidth + + // Compass 0 rotation + Component { + id: compass0ComponentLabel2 + + QGCLabel { + font.pixelSize: sideBarH1PointSize + text: "External Compass Orientation" + } + } + + Component { + id: compass0ComponentCombo2 + + FactComboBox { + id: compass0RotationCombo + width: rotationColumnWidth + model: rotations + fact: cal_mag0_rot + } + } + + Loader { sourceComponent: showCompass0Rot ? compass0ComponentLabel2 : null } + Loader { sourceComponent: showCompass0Rot ? compass0ComponentCombo2 : null } + } + + Column { + spacing: ScreenTools.defaultFontPixelWidth + + // Compass 1 rotation + Component { + id: compass1ComponentLabel2 + + QGCLabel { + font.pixelSize: sideBarH1PointSize + text: "External Compass 1 Orientation" + } + } + + Component { + id: compass1ComponentCombo2 + + FactComboBox { + id: compass1RotationCombo + width: rotationColumnWidth + model: rotations + fact: cal_mag1_rot + } + } + + Loader { sourceComponent: showCompass1Rot ? compass1ComponentLabel2 : null } + Loader { sourceComponent: showCompass1Rot ? compass1ComponentCombo2 : null } + } + + Column { + spacing: ScreenTools.defaultFontPixelWidth + + // Compass 2 rotation + Component { + id: compass2ComponentLabel2 + + QGCLabel { + font.pixelSize: sidebarH1PointSize + text: "Compass 2 Orientation" + } + } + + Component { + id: compass2ComponentCombo2 + + FactComboBox { + id: compass1RotationCombo + width: rotationColumnWidth + model: rotations + fact: cal_mag2_rot + } + } + Loader { sourceComponent: showCompass2Rot ? compass2ComponentLabel2 : null } + Loader { sourceComponent: showCompass2Rot ? compass2ComponentCombo2 : null } + } + } + } + } + } // QGCViewPanel +} // QGCView diff --git a/src/AutoPilotPlugins/APM/APMSensorsComponentController.cc b/src/AutoPilotPlugins/APM/APMSensorsComponentController.cc new file mode 100644 index 0000000000000000000000000000000000000000..2a267d33c227f5b9ae372914383ef293272b3a62 --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMSensorsComponentController.cc @@ -0,0 +1,469 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009, 2015 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "APMSensorsComponentController.h" +#include "QGCMAVLink.h" +#include "UAS.h" +#include "QGCApplication.h" + +#include +#include + +QGC_LOGGING_CATEGORY(APMSensorsComponentControllerLog, "APMSensorsComponentControllerLog") + +APMSensorsComponentController::APMSensorsComponentController(void) : + _statusLog(NULL), + _progressBar(NULL), + _compassButton(NULL), + _accelButton(NULL), + _nextButton(NULL), + _cancelButton(NULL), + _showOrientationCalArea(false), + _gyroCalInProgress(false), + _magCalInProgress(false), + _accelCalInProgress(false), + _orientationCalDownSideDone(false), + _orientationCalUpsideDownSideDone(false), + _orientationCalLeftSideDone(false), + _orientationCalRightSideDone(false), + _orientationCalNoseDownSideDone(false), + _orientationCalTailDownSideDone(false), + _orientationCalDownSideVisible(false), + _orientationCalUpsideDownSideVisible(false), + _orientationCalLeftSideVisible(false), + _orientationCalRightSideVisible(false), + _orientationCalNoseDownSideVisible(false), + _orientationCalTailDownSideVisible(false), + _orientationCalDownSideInProgress(false), + _orientationCalUpsideDownSideInProgress(false), + _orientationCalLeftSideInProgress(false), + _orientationCalRightSideInProgress(false), + _orientationCalNoseDownSideInProgress(false), + _orientationCalTailDownSideInProgress(false), + _orientationCalDownSideRotate(false), + _orientationCalUpsideDownSideRotate(false), + _orientationCalLeftSideRotate(false), + _orientationCalRightSideRotate(false), + _orientationCalNoseDownSideRotate(false), + _orientationCalTailDownSideRotate(false), + _waitingForCancel(false) +{ + +} + +/// Appends the specified text to the status log area in the ui +void APMSensorsComponentController::_appendStatusLog(const QString& text) +{ + Q_ASSERT(_statusLog); + + QVariant returnedValue; + QVariant varText = text; + QMetaObject::invokeMethod(_statusLog, + "append", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, varText)); +} + +void APMSensorsComponentController::_startLogCalibration(void) +{ + _hideAllCalAreas(); + + connect(_uas, &UASInterface::textMessageReceived, this, &APMSensorsComponentController::_handleUASTextMessage); + + _compassButton->setEnabled(false); + _accelButton->setEnabled(false); + _nextButton->setEnabled(true); + _cancelButton->setEnabled(false); +} + +void APMSensorsComponentController::_startVisualCalibration(void) +{ + _compassButton->setEnabled(false); + _accelButton->setEnabled(false); + _cancelButton->setEnabled(true); + + _resetInternalState(); + + _progressBar->setProperty("value", 0); +} + +void APMSensorsComponentController::_resetInternalState(void) +{ + _orientationCalDownSideDone = true; + _orientationCalUpsideDownSideDone = true; + _orientationCalLeftSideDone = true; + _orientationCalRightSideDone = true; + _orientationCalTailDownSideDone = true; + _orientationCalNoseDownSideDone = true; + _orientationCalDownSideInProgress = false; + _orientationCalUpsideDownSideInProgress = false; + _orientationCalLeftSideInProgress = false; + _orientationCalRightSideInProgress = false; + _orientationCalNoseDownSideInProgress = false; + _orientationCalTailDownSideInProgress = false; + _orientationCalDownSideRotate = false; + _orientationCalUpsideDownSideRotate = false; + _orientationCalLeftSideRotate = false; + _orientationCalRightSideRotate = false; + _orientationCalNoseDownSideRotate = false; + _orientationCalTailDownSideRotate = false; + + emit orientationCalSidesRotateChanged(); + emit orientationCalSidesDoneChanged(); + emit orientationCalSidesInProgressChanged(); +} + +void APMSensorsComponentController::_stopCalibration(APMSensorsComponentController::StopCalibrationCode code) +{ + disconnect(_uas, &UASInterface::textMessageReceived, this, &APMSensorsComponentController::_handleUASTextMessage); + + _compassButton->setEnabled(true); + _accelButton->setEnabled(true); + _nextButton->setEnabled(false); + _cancelButton->setEnabled(false); + + if (code == StopCalibrationSuccess) { + _resetInternalState(); + _progressBar->setProperty("value", 1); + } else { + _progressBar->setProperty("value", 0); + } + + _waitingForCancel = false; + emit waitingForCancelChanged(); + + _refreshParams(); + + switch (code) { + case StopCalibrationSuccess: + _orientationCalAreaHelpText->setProperty("text", "Calibration complete"); + emit resetStatusTextArea(); + if (_magCalInProgress) { + emit setCompassRotations(); + } + break; + + case StopCalibrationCancelled: + emit resetStatusTextArea(); + _hideAllCalAreas(); + break; + + default: + // Assume failed + _hideAllCalAreas(); + qgcApp()->showMessage("Calibration failed. Calibration log will be displayed."); + break; + } + + _magCalInProgress = false; + _accelCalInProgress = false; + _gyroCalInProgress = false; +} + +void APMSensorsComponentController::calibrateGyro(void) +{ + _startLogCalibration(); + _uas->startCalibration(UASInterface::StartCalibrationGyro); +} + +void APMSensorsComponentController::calibrateCompass(void) +{ + _startLogCalibration(); + _uas->startCalibration(UASInterface::StartCalibrationMag); +} + +void APMSensorsComponentController::calibrateAccel(void) +{ + _startLogCalibration(); + _uas->startCalibration(UASInterface::StartCalibrationAccel); +} + +void APMSensorsComponentController::calibrateLevel(void) +{ + _startLogCalibration(); + _uas->startCalibration(UASInterface::StartCalibrationLevel); +} + +void APMSensorsComponentController::calibrateAirspeed(void) +{ + _startLogCalibration(); + _uas->startCalibration(UASInterface::StartCalibrationAirspeed); +} + +void APMSensorsComponentController::_handleUASTextMessage(int uasId, int compId, int severity, QString text) +{ + Q_UNUSED(compId); + Q_UNUSED(severity); + + UASInterface* uas = _autopilot->vehicle()->uas(); + Q_ASSERT(uas); + if (uasId != uas->getUASID()) { + return; + } + + if (text.startsWith("PreArm:") || text.startsWith("EKF") || text.startsWith("Arm") || text.startsWith("Initialising")) { + return; + } + + QString anyKey("and press any"); + if (text.contains(anyKey)) { + text = text.left(text.indexOf(anyKey)) + "and click Next to continue."; + } + + _appendStatusLog(text); + qCDebug(APMSensorsComponentControllerLog) << text << severity; + + if (text.contains("Calibration successful")) { + _stopCalibration(StopCalibrationSuccess); + return; + } + + if (text.contains("FAILED")) { + _stopCalibration(StopCalibrationFailed); + return; + } + +/* + // All calibration messages start with [cal] + QString calPrefix("[cal] "); + if (!text.startsWith(calPrefix)) { + return; + } + text = text.right(text.length() - calPrefix.length()); + + QString calStartPrefix("calibration started: "); + if (text.startsWith(calStartPrefix)) { + text = text.right(text.length() - calStartPrefix.length()); + + _startVisualCalibration(); + + text = parts[1]; + if (text == "accel" || text == "mag" || text == "gyro") { + // Reset all progress indication + _orientationCalDownSideDone = false; + _orientationCalUpsideDownSideDone = false; + _orientationCalLeftSideDone = false; + _orientationCalRightSideDone = false; + _orientationCalTailDownSideDone = false; + _orientationCalNoseDownSideDone = false; + _orientationCalDownSideInProgress = false; + _orientationCalUpsideDownSideInProgress = false; + _orientationCalLeftSideInProgress = false; + _orientationCalRightSideInProgress = false; + _orientationCalNoseDownSideInProgress = false; + _orientationCalTailDownSideInProgress = false; + + // Reset all visibility + _orientationCalDownSideVisible = false; + _orientationCalUpsideDownSideVisible = false; + _orientationCalLeftSideVisible = false; + _orientationCalRightSideVisible = false; + _orientationCalTailDownSideVisible = false; + _orientationCalNoseDownSideVisible = false; + + _orientationCalAreaHelpText->setProperty("text", "Place your vehicle into one of the Incomplete orientations shown below and hold it still"); + + if (text == "accel") { + _accelCalInProgress = true; + _orientationCalDownSideVisible = true; + _orientationCalUpsideDownSideVisible = true; + _orientationCalLeftSideVisible = true; + _orientationCalRightSideVisible = true; + _orientationCalTailDownSideVisible = true; + _orientationCalNoseDownSideVisible = true; + } else if (text == "mag") { + _magCalInProgress = true; + _orientationCalDownSideVisible = true; + _orientationCalUpsideDownSideVisible = true; + _orientationCalLeftSideVisible = true; + _orientationCalRightSideVisible = true; + _orientationCalTailDownSideVisible = true; + _orientationCalNoseDownSideVisible = true; + } else if (text == "gyro") { + _gyroCalInProgress = true; + _orientationCalDownSideVisible = true; + } else { + Q_ASSERT(false); + } + emit orientationCalSidesDoneChanged(); + emit orientationCalSidesVisibleChanged(); + emit orientationCalSidesInProgressChanged(); + _updateAndEmitShowOrientationCalArea(true); + } + return; + } + + if (text.endsWith("orientation detected")) { + QString side = text.section(" ", 0, 0); + qDebug() << "Side started" << side; + + if (side == "down") { + _orientationCalDownSideInProgress = true; + if (_magCalInProgress) { + _orientationCalDownSideRotate = true; + } + } else if (side == "up") { + _orientationCalUpsideDownSideInProgress = true; + if (_magCalInProgress) { + _orientationCalUpsideDownSideRotate = true; + } + } else if (side == "left") { + _orientationCalLeftSideInProgress = true; + if (_magCalInProgress) { + _orientationCalLeftSideRotate = true; + } + } else if (side == "right") { + _orientationCalRightSideInProgress = true; + if (_magCalInProgress) { + _orientationCalRightSideRotate = true; + } + } else if (side == "front") { + _orientationCalNoseDownSideInProgress = true; + if (_magCalInProgress) { + _orientationCalNoseDownSideRotate = true; + } + } else if (side == "back") { + _orientationCalTailDownSideInProgress = true; + if (_magCalInProgress) { + _orientationCalTailDownSideRotate = true; + } + } + + if (_magCalInProgress) { + _orientationCalAreaHelpText->setProperty("text", "Rotate the vehicle continuously as shown in the diagram until marked as Completed"); + } else { + _orientationCalAreaHelpText->setProperty("text", "Hold still in the current orientation"); + } + + emit orientationCalSidesInProgressChanged(); + emit orientationCalSidesRotateChanged(); + return; + } + + if (text.endsWith("side done, rotate to a different side")) { + QString side = text.section(" ", 0, 0); + qDebug() << "Side finished" << side; + + if (side == "down") { + _orientationCalDownSideInProgress = false; + _orientationCalDownSideDone = true; + _orientationCalDownSideRotate = false; + } else if (side == "up") { + _orientationCalUpsideDownSideInProgress = false; + _orientationCalUpsideDownSideDone = true; + } else if (side == "left") { + _orientationCalLeftSideInProgress = false; + _orientationCalLeftSideDone = true; + _orientationCalLeftSideRotate = false; + } else if (side == "right") { + _orientationCalRightSideInProgress = false; + _orientationCalRightSideDone = true; + } else if (side == "front") { + _orientationCalNoseDownSideInProgress = false; + _orientationCalNoseDownSideDone = true; + _orientationCalNoseDownSideRotate = false; + } else if (side == "back") { + _orientationCalTailDownSideInProgress = false; + _orientationCalTailDownSideDone = true; + } + + _orientationCalAreaHelpText->setProperty("text", "Place you vehicle into one of the orientations shown below and hold it still"); + + emit orientationCalSidesInProgressChanged(); + emit orientationCalSidesDoneChanged(); + emit orientationCalSidesRotateChanged(); + return; + } + + if (text.startsWith("calibration cancelled")) { + _stopCalibration(_waitingForCancel ? StopCalibrationCancelled : StopCalibrationFailed); + return; + } + + */ +} + +void APMSensorsComponentController::_refreshParams(void) +{ + QStringList fastRefreshList; + + fastRefreshList << "COMPASS_OFS_X" << "COMPASS_OFS_X" << "COMPASS_OFS_X" + << "INS_ACCOFFS_X" << "INS_ACCOFFS_Y" << "INS_ACCOFFS_Z"; + foreach (QString paramName, fastRefreshList) { + _autopilot->refreshParameter(FactSystem::defaultComponentId, paramName); + } + + // Now ask for all to refresh + _autopilot->refreshParametersPrefix(FactSystem::defaultComponentId, "COMPASS_"); + _autopilot->refreshParametersPrefix(FactSystem::defaultComponentId, "INS_"); +} + +bool APMSensorsComponentController::fixedWing(void) +{ + switch (_vehicle->vehicleType()) { + case MAV_TYPE_FIXED_WING: + case MAV_TYPE_VTOL_DUOROTOR: + case MAV_TYPE_VTOL_QUADROTOR: + case MAV_TYPE_VTOL_TILTROTOR: + case MAV_TYPE_VTOL_RESERVED2: + case MAV_TYPE_VTOL_RESERVED3: + case MAV_TYPE_VTOL_RESERVED4: + case MAV_TYPE_VTOL_RESERVED5: + return true; + default: + return false; + } +} + +void APMSensorsComponentController::_updateAndEmitShowOrientationCalArea(bool show) +{ + _showOrientationCalArea = show; + emit showOrientationCalAreaChanged(); +} + +void APMSensorsComponentController::_hideAllCalAreas(void) +{ + _updateAndEmitShowOrientationCalArea(false); +} + +void APMSensorsComponentController::cancelCalibration(void) +{ + // The firmware doesn't allow us to cancel calibration. The best we can do is wait + // for it to timeout. + _waitingForCancel = true; + emit waitingForCancelChanged(); + _cancelButton->setEnabled(false); + _uas->stopCalibration(); +} + +void APMSensorsComponentController::nextClicked(void) +{ + mavlink_message_t msg; + mavlink_command_ack_t ack; + + ack.command = 0; + ack.result = 1; + mavlink_msg_command_ack_encode(qgcApp()->toolbox()->mavlinkProtocol()->getSystemId(), qgcApp()->toolbox()->mavlinkProtocol()->getComponentId(), &msg, &ack); + + _vehicle->sendMessage(msg); +} diff --git a/src/AutoPilotPlugins/APM/APMSensorsComponentController.h b/src/AutoPilotPlugins/APM/APMSensorsComponentController.h new file mode 100644 index 0000000000000000000000000000000000000000..aba7ea3b7b1a6ae3b9d1f0765cafe2b233e6ab5b --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMSensorsComponentController.h @@ -0,0 +1,175 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009, 2015 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef APMSensorsComponentController_H +#define APMSensorsComponentController_H + +#include + +#include "UASInterface.h" +#include "FactPanelController.h" +#include "QGCLoggingCategory.h" + +Q_DECLARE_LOGGING_CATEGORY(APMSensorsComponentControllerLog) + +/// Sensors Component MVC Controller for SensorsComponent.qml. +class APMSensorsComponentController : public FactPanelController +{ + Q_OBJECT + +public: + APMSensorsComponentController(void); + + Q_PROPERTY(bool fixedWing READ fixedWing CONSTANT) + + Q_PROPERTY(QQuickItem* statusLog MEMBER _statusLog) + Q_PROPERTY(QQuickItem* progressBar MEMBER _progressBar) + + Q_PROPERTY(QQuickItem* compassButton MEMBER _compassButton) + Q_PROPERTY(QQuickItem* accelButton MEMBER _accelButton) + Q_PROPERTY(QQuickItem* nextButton MEMBER _nextButton) + Q_PROPERTY(QQuickItem* cancelButton MEMBER _cancelButton) + Q_PROPERTY(QQuickItem* orientationCalAreaHelpText MEMBER _orientationCalAreaHelpText) + + Q_PROPERTY(bool showOrientationCalArea MEMBER _showOrientationCalArea NOTIFY showOrientationCalAreaChanged) + + Q_PROPERTY(bool orientationCalDownSideDone MEMBER _orientationCalDownSideDone NOTIFY orientationCalSidesDoneChanged) + Q_PROPERTY(bool orientationCalUpsideDownSideDone MEMBER _orientationCalUpsideDownSideDone NOTIFY orientationCalSidesDoneChanged) + Q_PROPERTY(bool orientationCalLeftSideDone MEMBER _orientationCalLeftSideDone NOTIFY orientationCalSidesDoneChanged) + Q_PROPERTY(bool orientationCalRightSideDone MEMBER _orientationCalRightSideDone NOTIFY orientationCalSidesDoneChanged) + Q_PROPERTY(bool orientationCalNoseDownSideDone MEMBER _orientationCalNoseDownSideDone NOTIFY orientationCalSidesDoneChanged) + Q_PROPERTY(bool orientationCalTailDownSideDone MEMBER _orientationCalTailDownSideDone NOTIFY orientationCalSidesDoneChanged) + + Q_PROPERTY(bool orientationCalDownSideVisible MEMBER _orientationCalDownSideVisible NOTIFY orientationCalSidesVisibleChanged) + Q_PROPERTY(bool orientationCalUpsideDownSideVisible MEMBER _orientationCalUpsideDownSideVisible NOTIFY orientationCalSidesVisibleChanged) + Q_PROPERTY(bool orientationCalLeftSideVisible MEMBER _orientationCalLeftSideVisible NOTIFY orientationCalSidesVisibleChanged) + Q_PROPERTY(bool orientationCalRightSideVisible MEMBER _orientationCalRightSideVisible NOTIFY orientationCalSidesVisibleChanged) + Q_PROPERTY(bool orientationCalNoseDownSideVisible MEMBER _orientationCalNoseDownSideVisible NOTIFY orientationCalSidesVisibleChanged) + Q_PROPERTY(bool orientationCalTailDownSideVisible MEMBER _orientationCalTailDownSideVisible NOTIFY orientationCalSidesVisibleChanged) + + Q_PROPERTY(bool orientationCalDownSideInProgress MEMBER _orientationCalDownSideInProgress NOTIFY orientationCalSidesInProgressChanged) + Q_PROPERTY(bool orientationCalUpsideDownSideInProgress MEMBER _orientationCalUpsideDownSideInProgress NOTIFY orientationCalSidesInProgressChanged) + Q_PROPERTY(bool orientationCalLeftSideInProgress MEMBER _orientationCalLeftSideInProgress NOTIFY orientationCalSidesInProgressChanged) + Q_PROPERTY(bool orientationCalRightSideInProgress MEMBER _orientationCalRightSideInProgress NOTIFY orientationCalSidesInProgressChanged) + Q_PROPERTY(bool orientationCalNoseDownSideInProgress MEMBER _orientationCalNoseDownSideInProgress NOTIFY orientationCalSidesInProgressChanged) + Q_PROPERTY(bool orientationCalTailDownSideInProgress MEMBER _orientationCalTailDownSideInProgress NOTIFY orientationCalSidesInProgressChanged) + + Q_PROPERTY(bool orientationCalDownSideRotate MEMBER _orientationCalDownSideRotate NOTIFY orientationCalSidesRotateChanged) + Q_PROPERTY(bool orientationCalUpsideDownSideRotate MEMBER _orientationCalUpsideDownSideRotate NOTIFY orientationCalSidesRotateChanged) + Q_PROPERTY(bool orientationCalLeftSideRotate MEMBER _orientationCalLeftSideRotate NOTIFY orientationCalSidesRotateChanged) + Q_PROPERTY(bool orientationCalRightSideRotate MEMBER _orientationCalRightSideRotate NOTIFY orientationCalSidesRotateChanged) + Q_PROPERTY(bool orientationCalNoseDownSideRotate MEMBER _orientationCalNoseDownSideRotate NOTIFY orientationCalSidesRotateChanged) + Q_PROPERTY(bool orientationCalTailDownSideRotate MEMBER _orientationCalTailDownSideRotate NOTIFY orientationCalSidesRotateChanged) + + Q_PROPERTY(bool waitingForCancel MEMBER _waitingForCancel NOTIFY waitingForCancelChanged) + + Q_INVOKABLE void calibrateCompass(void); + Q_INVOKABLE void calibrateGyro(void); + Q_INVOKABLE void calibrateAccel(void); + Q_INVOKABLE void calibrateLevel(void); + Q_INVOKABLE void calibrateAirspeed(void); + Q_INVOKABLE void cancelCalibration(void); + Q_INVOKABLE void nextClicked(void); + + bool fixedWing(void); + +signals: + void showGyroCalAreaChanged(void); + void showOrientationCalAreaChanged(void); + void orientationCalSidesDoneChanged(void); + void orientationCalSidesVisibleChanged(void); + void orientationCalSidesInProgressChanged(void); + void orientationCalSidesRotateChanged(void); + void resetStatusTextArea(void); + void waitingForCancelChanged(void); + void setCompassRotations(void); + +private slots: + void _handleUASTextMessage(int uasId, int compId, int severity, QString text); + +private: + void _startLogCalibration(void); + void _startVisualCalibration(void); + void _appendStatusLog(const QString& text); + void _refreshParams(void); + void _hideAllCalAreas(void); + void _resetInternalState(void); + + enum StopCalibrationCode { + StopCalibrationSuccess, + StopCalibrationFailed, + StopCalibrationCancelled + }; + void _stopCalibration(StopCalibrationCode code); + + void _updateAndEmitShowOrientationCalArea(bool show); + + QQuickItem* _statusLog; + QQuickItem* _progressBar; + QQuickItem* _compassButton; + QQuickItem* _accelButton; + QQuickItem* _nextButton; + QQuickItem* _cancelButton; + QQuickItem* _orientationCalAreaHelpText; + + bool _showGyroCalArea; + bool _showOrientationCalArea; + + bool _gyroCalInProgress; + bool _magCalInProgress; + bool _accelCalInProgress; + + bool _orientationCalDownSideDone; + bool _orientationCalUpsideDownSideDone; + bool _orientationCalLeftSideDone; + bool _orientationCalRightSideDone; + bool _orientationCalNoseDownSideDone; + bool _orientationCalTailDownSideDone; + + bool _orientationCalDownSideVisible; + bool _orientationCalUpsideDownSideVisible; + bool _orientationCalLeftSideVisible; + bool _orientationCalRightSideVisible; + bool _orientationCalNoseDownSideVisible; + bool _orientationCalTailDownSideVisible; + + bool _orientationCalDownSideInProgress; + bool _orientationCalUpsideDownSideInProgress; + bool _orientationCalLeftSideInProgress; + bool _orientationCalRightSideInProgress; + bool _orientationCalNoseDownSideInProgress; + bool _orientationCalTailDownSideInProgress; + + bool _orientationCalDownSideRotate; + bool _orientationCalUpsideDownSideRotate; + bool _orientationCalLeftSideRotate; + bool _orientationCalRightSideRotate; + bool _orientationCalNoseDownSideRotate; + bool _orientationCalTailDownSideRotate; + + bool _waitingForCancel; + + static const int _supportedFirmwareCalVersion = 2; +}; + +#endif diff --git a/src/AutoPilotPlugins/APM/APMSensorsComponentSummary.qml b/src/AutoPilotPlugins/APM/APMSensorsComponentSummary.qml new file mode 100644 index 0000000000000000000000000000000000000000..de5e5381874f736efd7a23aaba007bc6d2131f36 --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMSensorsComponentSummary.qml @@ -0,0 +1,47 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 + +import QGroundControl.FactSystem 1.0 +import QGroundControl.FactControls 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.Palette 1.0 + +/* + IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml +*/ + +FactPanel { + id: panel + anchors.fill: parent + color: qgcPal.windowShadeDark + + QGCPalette { id: qgcPal; colorGroupEnabled: enabled } + FactPanelController { id: controller; factPanel: panel } + + property Fact ins_accoffs_x: controller.getParameterFact(-1, "INS_ACCOFFS_X") + property Fact ins_accoffs_y: controller.getParameterFact(-1, "INS_ACCOFFS_Y") + property Fact ins_accoffs_z: controller.getParameterFact(-1, "INS_ACCOFFS_Z") + + property Fact compass_ofs_x: controller.getParameterFact(-1, "COMPASS_OFS_X") + property Fact compass_ofs_y: controller.getParameterFact(-1, "COMPASS_OFS_Y") + property Fact compass_ofs_z: controller.getParameterFact(-1, "COMPASS_OFS_Z") + + property bool accelCalNeeded: ins_accoffs_x.value == 0 && ins_accoffs_y.value == 0 && ins_accoffs_z.value == 0 + property bool compassCalNeeded: compass_ofs_x.value == 0 && compass_ofs_y.value == 0 && compass_ofs_y.value == 0 + + Column { + anchors.fill: parent + anchors.margins: 8 + + VehicleSummaryRow { + labelText: "Compass:" + valueText: compassCalNeeded ? "Setup required" : "Ready" + } + + VehicleSummaryRow { + labelText: "Accelerometer:" + valueText: accelCalNeeded ? "Setup required" : "Ready" + } + } +} diff --git a/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc b/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc index 3246a99367dde0a736d2b9e9a005a7cc2c5cf30a..fb646a506be1c1d3c30825a9beea052f3f360e1d 100644 --- a/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc +++ b/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc @@ -292,22 +292,34 @@ void APMFirmwarePlugin::adjustMavlinkMessage(mavlink_message_t* message) mavlink_msg_param_set_encode(message->sysid, message->compid, message, ¶mSet); } - if (message->msgid == MAVLINK_MSG_ID_STATUSTEXT) - { - if (!_firmwareVersion.isValid()) { + if (message->msgid == MAVLINK_MSG_ID_STATUSTEXT) { + mavlink_statustext_t statusText; + mavlink_msg_statustext_decode(message, &statusText); + + // APM user facing calibration messages come through as high severity, we need to parse them out + // and lower the severity on them so that they don't pop in the users face. + + if (!_firmwareVersion.isValid() || statusText.severity < MAV_SEVERITY_NOTICE) { QByteArray b; b.resize(MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN+1); mavlink_msg_statustext_get_text(message, b.data()); // Ensure NUL-termination b[b.length()-1] = '\0'; - QString text = QString(b); - qCDebug(APMFirmwarePluginLog) << text; - - // if don't know firmwareVersion yet, try and see this message contains it - if (text.contains(APM_COPTER_REXP) || text.contains(APM_PLANE_REXP) || text.contains(APM_ROVER_REXP)) { - // found version string - _firmwareVersion = APMFirmwareVersion(text); - _textSeverityAdjustmentNeeded = _isTextSeverityAdjustmentNeeded(_firmwareVersion); + QString messageText = QString(b); + qCDebug(APMFirmwarePluginLog) << messageText; + + if (!_firmwareVersion.isValid()) { + // if don't know firmwareVersion yet, try and see if this message contains it + if (messageText.contains(APM_COPTER_REXP) || messageText.contains(APM_PLANE_REXP) || messageText.contains(APM_ROVER_REXP)) { + // found version string + _firmwareVersion = APMFirmwareVersion(messageText); + _textSeverityAdjustmentNeeded = _isTextSeverityAdjustmentNeeded(_firmwareVersion); + } + } + + if (messageText.contains("Place vehicle") || messageText.contains("Calibration successful")) { + _adjustCalibrationMessageSeverity(message); + return; } } @@ -362,6 +374,14 @@ void APMFirmwarePlugin::_adjustSeverity(mavlink_message_t* message) const mavlink_msg_statustext_encode(message->sysid, message->compid, message, &statusText); } +void APMFirmwarePlugin::_adjustCalibrationMessageSeverity(mavlink_message_t* message) const +{ + mavlink_statustext_t statusText; + mavlink_msg_statustext_decode(message, &statusText); + statusText.severity = MAV_SEVERITY_INFO; + mavlink_msg_statustext_encode(message->sysid, message->compid, message, &statusText); +} + void APMFirmwarePlugin::initializeVehicle(Vehicle* vehicle) { // Streams are not started automatically on APM stack diff --git a/src/FirmwarePlugin/APM/APMFirmwarePlugin.h b/src/FirmwarePlugin/APM/APMFirmwarePlugin.h index 9836c75f336fb94fa2625df07f08f5363cd63218..a092f61cd3eb54a29c2830978c5176e34c738bd2 100644 --- a/src/FirmwarePlugin/APM/APMFirmwarePlugin.h +++ b/src/FirmwarePlugin/APM/APMFirmwarePlugin.h @@ -100,6 +100,7 @@ protected: private: void _adjustSeverity(mavlink_message_t* message) const; + void _adjustCalibrationMessageSeverity(mavlink_message_t* message) const; static bool _isTextSeverityAdjustmentNeeded(const APMFirmwareVersion& firmwareVersion); APMFirmwareVersion _firmwareVersion; diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index e75d1c3064a9510b3d1c8c08d0f916167f8a2e35..1b0cc0a265eb90b8063c9e34978a02b418d43a34 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -65,6 +65,7 @@ #include "APMFlightModesComponentController.h" #include "AirframeComponentController.h" #include "SensorsComponentController.h" +#include "APMSensorsComponentController.h" #include "PowerComponentController.h" #include "RadioComponentController.h" #include "ScreenToolsController.h" @@ -379,6 +380,7 @@ void QGCApplication::_initCommon(void) qmlRegisterType ("QGroundControl.Controllers", 1, 0, "APMFlightModesComponentController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "FlightModesComponentController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "AirframeComponentController"); + qmlRegisterType ("QGroundControl.Controllers", 1, 0, "APMSensorsComponentController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "SensorsComponentController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "PowerComponentController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "RadioComponentController");