diff --git a/ChangeLog.md b/ChangeLog.md index a348a47..79d347d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -9,6 +9,7 @@ Note: This file only contains high level features or important fixes. * ArduPilot: Copter - Update support to 3.5+ * ArduPilot: Plane - Update support to 3.8+ * ArduPilot: Rover - Update support to 3.4+ +* ArduPilot: Rework Airframe setup ui * Plan/Pattern: Support named presets to simplify commonly used settings setup. Currently only supported by Survey. * ArduCopter: Handle 3.7 parameter name change from CH#_OPT to RC#_OPTION. * Improved support for flashing/connecting to ChibiOS bootloaders boards. diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index a683fc6..67da3fd 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -984,9 +984,7 @@ APMFirmwarePlugin { HEADERS += \ src/AutoPilotPlugins/APM/APMAirframeComponent.h \ - src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h \ src/AutoPilotPlugins/APM/APMAirframeComponentController.h \ - src/AutoPilotPlugins/APM/APMAirframeLoader.h \ src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h \ src/AutoPilotPlugins/APM/APMCameraComponent.h \ src/AutoPilotPlugins/APM/APMCompassCal.h \ @@ -1011,9 +1009,7 @@ APMFirmwarePlugin { SOURCES += \ src/AutoPilotPlugins/APM/APMAirframeComponent.cc \ - src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.cc \ src/AutoPilotPlugins/APM/APMAirframeComponentController.cc \ - src/AutoPilotPlugins/APM/APMAirframeLoader.cc \ src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc \ src/AutoPilotPlugins/APM/APMCameraComponent.cc \ src/AutoPilotPlugins/APM/APMCompassCal.cc \ diff --git a/src/AutoPilotPlugins/APM/APMAirframeComponent.qml b/src/AutoPilotPlugins/APM/APMAirframeComponent.qml index e29e7fd..6547c19 100644 --- a/src/AutoPilotPlugins/APM/APMAirframeComponent.qml +++ b/src/AutoPilotPlugins/APM/APMAirframeComponent.qml @@ -22,90 +22,155 @@ import QGroundControl.ScreenTools 1.0 SetupPage { id: airframePage - pageComponent: _useOldFrameParam ? oldFramePageComponent: newFramePageComponent - - property real _margins: ScreenTools.defaultFontPixelWidth - property bool _useOldFrameParam: controller.parameterExists(-1, "FRAME") - property Fact _oldFrameParam: controller.getParameterFact(-1, "FRAME", false) - property Fact _newFrameParam: controller.getParameterFact(-1, "FRAME_CLASS", false) - property Fact _frameTypeParam: controller.getParameterFact(-1, "FRAME_TYPE", false) - - - APMAirframeComponentController { - id: controller - factPanel: airframePage.viewPanel - } - - ExclusiveGroup { - id: airframeTypeExclusive - } + pageComponent: pageComponent Component { - id: oldFramePageComponent - - Column { - width: availableWidth - height: 1000 - spacing: _margins - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - spacing: _margins - - QGCLabel { - font.pointSize: ScreenTools.mediumFontPointSize - wrapMode: Text.WordWrap - text: qsTr("Please select your airframe type") - Layout.fillWidth: true + id: pageComponent + + ColumnLayout { + id: mainColumn + width: availableWidth + + property real _minW: ScreenTools.defaultFontPixelWidth * 20 + property real _boxWidth: _minW + property real _boxSpace: ScreenTools.defaultFontPixelWidth + property real _margins: ScreenTools.defaultFontPixelWidth + property Fact _frameClass: controller.getParameterFact(-1, "FRAME_CLASS") + property Fact _frameType: controller.getParameterFact(-1, "FRAME_TYPE") + + readonly property real spacerHeight: ScreenTools.defaultFontPixelHeight + + onWidthChanged: computeDimensions() + Component.onCompleted: computeDimensions() + + function computeDimensions() { + var sw = 0 + var rw = 0 + var idx = Math.floor(mainColumn.width / (_minW + ScreenTools.defaultFontPixelWidth)) + if(idx < 1) { + _boxWidth = mainColumn.width + _boxSpace = 0 + } else { + _boxSpace = 0 + if(idx > 1) { + _boxSpace = ScreenTools.defaultFontPixelWidth + sw = _boxSpace * (idx - 1) + } + rw = mainColumn.width - sw + _boxWidth = rw / idx } } - Repeater { - model: controller.airframeTypesModel + APMAirframeComponentController { + id: controller + factPanel: airframePage.viewPanel + } - QGCRadioButton { - text: object.name - checked: controller.currentAirframeType == object - exclusiveGroup: airframeTypeExclusive + QGCLabel { + id: helpText + Layout.fillWidth: true + text: (_frameClass.rawValue === 0 ? + qsTr("Airframe is currently not set.") : + qsTr("Currently set to frame class '%1' and frame type '%2'.").arg(_frameClass.enumStringValue).arg(_frameType.enumStringValue)) + + qsTr(" To change this configuration, select the desired frame class below and frame type.") + font.family: ScreenTools.demiboldFontFamily + wrapMode: Text.WordWrap + } - onCheckedChanged: { - if (checked) { - controller.currentAirframeType = object - } - } - } + Item { + id: lastSpacer + height: parent.spacerHeight + width: 10 } - } // Column - } // Component - oldFramePageComponent - Component { - id: newFramePageComponent + Flow { + id: flowView + Layout.fillWidth: true + spacing: _boxSpace - Grid { - width: availableWidth - spacing: _margins - columns: 2 + ExclusiveGroup { + id: airframeTypeExclusive + } - QGCLabel { - text: qsTr("Frame Class:") - } + Repeater { + model: controller.frameClassModel - FactComboBox { - fact: _newFrameParam - indexModel: false - width: ScreenTools.defaultFontPixelWidth * 15 - } + // Outer summary item rectangle + Rectangle { + id: outerRect + width: _boxWidth + height: ScreenTools.defaultFontPixelHeight * 14 + color: qgcPal.window - QGCLabel { - text: qsTr("Frame Type:") - } + readonly property real titleHeight: ScreenTools.defaultFontPixelHeight * 1.75 + readonly property real innerMargin: ScreenTools.defaultFontPixelWidth - FactComboBox { - fact: _frameTypeParam - indexModel: false - width: ScreenTools.defaultFontPixelWidth * 15 - } - } - } + MouseArea { + anchors.fill: parent + onClicked: airframeCheckBox.checked = true + } + + QGCLabel { + id: title + text: object.name + } + + Rectangle { + anchors.topMargin: ScreenTools.defaultFontPixelHeight / 2 + anchors.top: title.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + color: airframeCheckBox.checked ? qgcPal.buttonHighlight : qgcPal.windowShade + + ColumnLayout { + anchors.margins: innerMargin + anchors.fill: parent + spacing: innerMargin + + Image { + id: image + Layout.fillWidth: true + Layout.fillHeight: true + fillMode: Image.PreserveAspectFit + smooth: true + mipmap: true + source: object.imageResource + } + + QGCCheckBox { + // Although this item is invisible we still use it to manage state + id: airframeCheckBox + checked: object.frameClass === _frameClass.rawValue + exclusiveGroup: airframeTypeExclusive + visible: false + + onCheckedChanged: { + if (checked) { + _frameClass.rawValue = object.frameClass + } + } + } + + QGCLabel { + text: qsTr("Frame Type") + font.pointSize: ScreenTools.smallFontPointSize + color: qgcPal.buttonHighlightText + visible: airframeCheckBox.checked && object.frameTypeSupported + } + + FactComboBox { + id: combo + Layout.fillWidth: true + fact: _frameType + indexModel: false + visible: airframeCheckBox.checked && object.frameTypeSupported + } + } + } + } + } // Repeater - summary boxes + } // Flow - summary boxes + } // Column + } // Component } // SetupPage diff --git a/src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.cc b/src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.cc deleted file mode 100644 index 7d04a35..0000000 --- a/src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.cc +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/// @file -/// @author Don Gagne - -#include "APMAirframeComponentAirframes.h" -#include "APMAirframeComponentController.h" - -QMap APMAirframeComponentAirframes::rgAirframeTypes; - -QMap& APMAirframeComponentAirframes::get() { - return rgAirframeTypes; -} - -void APMAirframeComponentAirframes::insert(const QString& group, int groupId, const QString& image,const QString& name, const QString& file) -{ - AirframeType_t *g; - if (!rgAirframeTypes.contains(group)) { - g = new AirframeType_t; - g->name = group; - g->type = groupId; - g->imageResource = image.isEmpty() ? QString() : QStringLiteral("qrc:/qmlimages/") + image; - rgAirframeTypes.insert(group, g); - } else { - g = rgAirframeTypes.value(group); - } - - if (!name.isEmpty() && !file.isEmpty()) - g->rgAirframeInfo.append(new APMAirframe(name, file, g->type)); -} - -void APMAirframeComponentAirframes::clear() { - QList valueList = get().values(); - foreach(AirframeType_t *pType, valueList) { - qDeleteAll(pType->rgAirframeInfo); - delete pType; - } - rgAirframeTypes.clear(); -} diff --git a/src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h b/src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h deleted file mode 100644 index 5a914b2..0000000 --- a/src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/// @file -/// @author Don Gagne - -#ifndef APMAirframeComponentAirframes_H -#define APMAirframeComponentAirframes_H - -#include -#include -#include -#include - -#include "UASInterface.h" -#include "AutoPilotPlugin.h" - -class APMAirframe; - -/// MVC Controller for AirframeComponent.qml. -class APMAirframeComponentAirframes -{ -public: - typedef struct { - QString name; - QString imageResource; - int type; - QList rgAirframeInfo; - } AirframeType_t; - typedef QMap AirframeTypeMap; - - static AirframeTypeMap& get(); - static void clear(); - static void insert(const QString& group, int groupId, const QString& image,const QString& name = QString(), const QString& file = QString()); - -protected: - static AirframeTypeMap rgAirframeTypes; - -private: -}; - -#endif diff --git a/src/AutoPilotPlugins/APM/APMAirframeComponentController.cc b/src/AutoPilotPlugins/APM/APMAirframeComponentController.cc index d26c398..8f80a4a 100644 --- a/src/AutoPilotPlugins/APM/APMAirframeComponentController.cc +++ b/src/AutoPilotPlugins/APM/APMAirframeComponentController.cc @@ -7,12 +7,7 @@ * ****************************************************************************/ - -/// @file -/// @author Don Gagne - #include "APMAirframeComponentController.h" -#include "APMAirframeComponentAirframes.h" #include "QGCMAVLink.h" #include "MultiVehicleManager.h" #include "QGCApplication.h" @@ -26,71 +21,113 @@ #include #include -bool APMAirframeComponentController::_typesRegistered = false; - -const char* APMAirframeComponentController::_oldFrameParam = "FRAME"; -const char* APMAirframeComponentController::_newFrameParam = "FRAME_CLASS"; -APMAirframeComponentController::APMAirframeComponentController(void) : - _airframeTypesModel(new QmlObjectListModel(this)) -{ - if (!_typesRegistered) { - _typesRegistered = true; - qmlRegisterUncreatableType("QGroundControl.Controllers", 1, 0, "APMAirframeType", QStringLiteral("Can only reference APMAirframeType")); - } - _fillAirFrames(); - - Fact* frame = NULL; - if (parameterExists(FactSystem::defaultComponentId, _oldFrameParam)) { - frame = getParameterFact(FactSystem::defaultComponentId, _oldFrameParam); - } else if (parameterExists(FactSystem::defaultComponentId, _newFrameParam)){ - frame = getParameterFact(FactSystem::defaultComponentId, _newFrameParam); +// These should match the FRAME_CLASS parameter enum meta data +#define FRAME_CLASS_UNDEFINED 0 +#define FRAME_CLASS_QUAD 1 +#define FRAME_CLASS_HEX 2 +#define FRAME_CLASS_OCTA 3 +#define FRAME_CLASS_OCTAQUAD 4 +#define FRAME_CLASS_Y6 5 +#define FRAME_CLASS_HELI 6 +#define FRAME_CLASS_TRI 7 +#define FRAME_CLASS_SINGLECOPTER 8 +#define FRAME_CLASS_COAXCOPTER 9 +#define FRAME_CLASS_BICOPTER 10 +#define FRAME_CLASS_HELI_DUAL 11 +#define FRAME_CLASS_DODECAHEXA 12 +#define FRAME_CLASS_HELIQUAD 13 + +// These should match the FRAME_TYPE parameter enum meta data +#define FRAME_TYPE_PLUS 0 +#define FRAME_TYPE_X 1 +#define FRAME_TYPE_V 2 +#define FRAME_TYPE_H 3 +#define FRAME_TYPE_V_TAIL 4 +#define FRAME_TYPE_A_TAIL 5 +#define FRAME_TYPE_Y6B 10 +#define FRAME_TYPE_Y6F 11 +#define FRAME_TYPE_BETAFLIGHTX 12 +#define FRAME_TYPE_DJIX 13 +#define FRAME_TYPE_CLOCKWISEX 14 + +typedef struct { + int frameClass; + int frameType; + const char* imageResource; +} FrameToImageInfo_t; + +static const FrameToImageInfo_t s_rgFrameToImage[] = { + { FRAME_CLASS_QUAD, FRAME_TYPE_PLUS, "QuadRotorPlus" }, + { FRAME_CLASS_QUAD, FRAME_TYPE_X, "QuadRotorX" }, + { FRAME_CLASS_QUAD, FRAME_TYPE_V, "QuadRotorWide" }, + { FRAME_CLASS_QUAD, FRAME_TYPE_H, "QuadRotorH" }, + { FRAME_CLASS_QUAD, FRAME_TYPE_V_TAIL, "QuadRotorVTail" }, + { FRAME_CLASS_QUAD, FRAME_TYPE_A_TAIL, "QuadRotorATail" }, + { FRAME_CLASS_HEX, FRAME_TYPE_PLUS, "HexaRotorPlus" }, + { FRAME_CLASS_HEX, FRAME_TYPE_X, "HexaRotorX" }, + { FRAME_CLASS_OCTA, FRAME_TYPE_PLUS, "OctoRotorPlus" }, + { FRAME_CLASS_OCTA, FRAME_TYPE_X, "OctoRotorX" }, + { FRAME_CLASS_OCTAQUAD, FRAME_TYPE_PLUS, "OctoRotorPlusCoaxial" }, + { FRAME_CLASS_OCTAQUAD, FRAME_TYPE_X, "OctoRotorXCoaxial" }, + { FRAME_CLASS_Y6, FRAME_TYPE_Y6B, "Y6B" }, + { FRAME_CLASS_Y6, FRAME_TYPE_Y6F, "AirframeUnknown" }, + { FRAME_CLASS_Y6, -1, "Y6A" }, + { FRAME_CLASS_HELI, -1, "Helicopter" }, + { FRAME_CLASS_TRI, -1, "YPlus" }, +}; + +static QString s_findImageResource(int frameClass, int frameType) +{ + for (size_t i=0; iframeClass == frameClass && pFrameToImageInfo->frameType == frameType) { + return pFrameToImageInfo->imageResource; + } else if (pFrameToImageInfo->frameClass == frameClass && pFrameToImageInfo->frameType == -1) { + return pFrameToImageInfo->imageResource; + } } - if (frame) { - connect(frame, &Fact::rawValueChanged, this, &APMAirframeComponentController::_factFrameChanged); - _factFrameChanged(frame->rawValue()); - } + return QStringLiteral("AirframeUnknown"); } -APMAirframeComponentController::~APMAirframeComponentController() +APMAirframeComponentController::APMAirframeComponentController(void) + : _frameClassFact (getParameterFact(FactSystem::defaultComponentId, QStringLiteral("FRAME_CLASS"))) + , _frameTypeFact (getParameterFact(FactSystem::defaultComponentId, QStringLiteral("FRAME_TYPE"))) + , _frameClassModel (new QmlObjectListModel(this)) { - + _fillFrameClasses(); } -void APMAirframeComponentController::_factFrameChanged(QVariant value) +APMAirframeComponentController::~APMAirframeComponentController() { - FrameId v = (FrameId) value.toInt(); - - for(int i = 0, size = _airframeTypesModel->count(); i < size; i++ ) { - APMAirframeType *airframeType = qobject_cast(_airframeTypesModel->get(i)); - Q_ASSERT(airframeType); - if (airframeType->type() == v) { - _currentAirframeType = airframeType; - break; - } - } - emit currentAirframeTypeChanged(_currentAirframeType); + } -void APMAirframeComponentController::_fillAirFrames() +void APMAirframeComponentController::_fillFrameClasses() { - for (int tindex = 0; tindex < APMAirframeComponentAirframes::get().count(); tindex++) { - const APMAirframeComponentAirframes::AirframeType_t* pType = APMAirframeComponentAirframes::get().values().at(tindex); + QList frameTypeNotSupported; - APMAirframeType* airframeType = new APMAirframeType(pType->name, pType->imageResource, pType->type, this); - Q_CHECK_PTR(airframeType); + frameTypeNotSupported << FRAME_CLASS_HELI + << FRAME_CLASS_SINGLECOPTER + << FRAME_CLASS_COAXCOPTER + << FRAME_CLASS_BICOPTER + << FRAME_CLASS_HELI_DUAL + << FRAME_CLASS_HELIQUAD; - for (int index = 0; index < pType->rgAirframeInfo.count(); index++) { - const APMAirframe* pInfo = pType->rgAirframeInfo.at(index); - Q_CHECK_PTR(pInfo); + for (int i=1; i<_frameClassFact->enumStrings().count(); i++) { + QString frameClassName = _frameClassFact->enumStrings()[i]; + int frameClass = _frameClassFact->enumValues()[i].toInt(); + int defaultFrameType; - airframeType->addAirframe(pInfo->name(), pInfo->params(), pInfo->type()); + if (frameTypeNotSupported.contains(frameClass)) { + defaultFrameType = -1; + } else { + defaultFrameType = FRAME_TYPE_X; } - _airframeTypesModel->append(airframeType); + _frameClassModel->append(new APMFrameClass(frameClassName, frameClass, _frameTypeFact, defaultFrameType, _frameClassModel)); } - - emit loadAirframesCompleted(); } void APMAirframeComponentController::_loadParametersFromDownloadFile(const QString& downloadedParamFile) @@ -120,86 +157,6 @@ void APMAirframeComponentController::_loadParametersFromDownloadFile(const QStri _vehicle->parameterManager()->refreshAllParameters(); } -APMAirframeType::APMAirframeType(const QString& name, const QString& imageResource, int type, QObject* parent) : - QObject(parent), - _name(name), - _imageResource(imageResource), - _type(type), - _dirty(false) -{ -} - -APMAirframeType::~APMAirframeType() -{ -} - -void APMAirframeType::addAirframe(const QString& name, const QString& file, int type) -{ - APMAirframe* airframe = new APMAirframe(name, file, type); - Q_CHECK_PTR(airframe); - - _airframes.append(QVariant::fromValue(airframe)); -} - -APMAirframe::APMAirframe(const QString& name, const QString& paramsFile, int type, QObject* parent) : - QObject(parent), - _name(name), - _paramsFile(paramsFile), - _type(type) -{ -} - -QString APMAirframe::name() const -{ - return _name; -} - -QString APMAirframe::params() const -{ - return _paramsFile; -} - -int APMAirframe::type() const -{ - return _type; -} - -APMAirframe::~APMAirframe() -{ -} - -QString APMAirframeType::imageResource() const -{ - return _imageResource; -} - -QString APMAirframeType::name() const -{ - return _name; -} - -int APMAirframeType::type() const -{ - return _type; -} - -APMAirframeType *APMAirframeComponentController::currentAirframeType() const -{ - return _currentAirframeType; -} - -QString APMAirframeComponentController::currentAirframeTypeName() const -{ - return _vehicle->vehicleTypeName(); -} - -void APMAirframeComponentController::setCurrentAirframeType(APMAirframeType *t) -{ - Fact *param = getParameterFact(-1, QStringLiteral("FRAME")); - Q_ASSERT(param); - param->setRawValue(t->type()); -} - void APMAirframeComponentController::loadParameters(const QString& paramFile) { qgcApp()->setOverrideCursor(Qt::WaitCursor); @@ -258,3 +215,25 @@ void APMAirframeComponentController::_paramFileDownloadError(QString errorMsg) qgcApp()->showMessage(tr("Param file download failed: %1").arg(errorMsg)); qgcApp()->restoreOverrideCursor(); } + +APMFrameClass::APMFrameClass(const QString& name, int frameClass, Fact* frameTypeFact, int defaultFrameType, QObject* parent) + : QObject (parent) + , _name (name) + , _frameClass (frameClass) + , _defaultFrameType (defaultFrameType) + , _frameTypeSupported (defaultFrameType != -1) + , _frameTypeFact (frameTypeFact) +{ + connect(frameTypeFact, &Fact::rawValueChanged, this, &APMFrameClass::imageResourceChanged); + connect(frameTypeFact, &Fact::rawValueChanged, this, &APMFrameClass::frameTypeChanged); +} + +APMFrameClass::~APMFrameClass() +{ + +} + +QString APMFrameClass::imageResource(void) +{ + return QStringLiteral("/qmlimages/Airframe/%1").arg(s_findImageResource(_frameClass, _frameTypeFact->rawValue().toInt())); +} diff --git a/src/AutoPilotPlugins/APM/APMAirframeComponentController.h b/src/AutoPilotPlugins/APM/APMAirframeComponentController.h index 47e3835..456b8bd 100644 --- a/src/AutoPilotPlugins/APM/APMAirframeComponentController.h +++ b/src/AutoPilotPlugins/APM/APMAirframeComponentController.h @@ -7,12 +7,7 @@ * ****************************************************************************/ - -/// @file -/// @author Don Gagne - -#ifndef APMAirframeComponentController_H -#define APMAirframeComponentController_H +#pragma once #include #include @@ -22,7 +17,6 @@ #include "UASInterface.h" #include "AutoPilotPlugin.h" #include "FactPanelController.h" -#include "APMAirframeComponentAirframes.h" class APMAirframeModel; class APMAirframeType; @@ -33,98 +27,56 @@ class APMAirframeComponentController : public FactPanelController Q_OBJECT public: - enum FrameId{FRAME_TYPE_PLUS = 0, - FRAME_TYPE_X = 1, - FRAME_TYPE_V = 2, - FRAME_TYPE_H = 3, - FRAME_TYPE_NEWY6 = 10}; - Q_ENUM(FrameId) - APMAirframeComponentController(void); ~APMAirframeComponentController(); - Q_PROPERTY(QmlObjectListModel* airframeTypesModel MEMBER _airframeTypesModel CONSTANT) - Q_PROPERTY(APMAirframeType* currentAirframeType READ currentAirframeType WRITE setCurrentAirframeType NOTIFY currentAirframeTypeChanged) + Q_PROPERTY(QmlObjectListModel* frameClassModel MEMBER _frameClassModel CONSTANT) Q_INVOKABLE void loadParameters(const QString& paramFile); - int currentAirframeIndex(void); - void setCurrentAirframeIndex(int newIndex); - -signals: - void loadAirframesCompleted(); - void currentAirframeTypeChanged(APMAirframeType* airframeType); - -public slots: - APMAirframeType *currentAirframeType() const; - Q_INVOKABLE QString currentAirframeTypeName() const; - void setCurrentAirframeType(APMAirframeType *t); - private slots: - void _fillAirFrames(void); - void _factFrameChanged(QVariant v); void _githubJsonDownloadFinished(QString remoteFile, QString localFile); void _githubJsonDownloadError(QString errorMsg); void _paramFileDownloadFinished(QString remoteFile, QString localFile); void _paramFileDownloadError(QString errorMsg); private: + void _fillFrameClasses(void); void _loadParametersFromDownloadFile(const QString& downloadedParamFile); - APMAirframeType *_currentAirframeType; - QmlObjectListModel *_airframeTypesModel; - - static bool _typesRegistered; - static const char* _oldFrameParam; - static const char* _newFrameParam; + Fact* _frameClassFact; + Fact* _frameTypeFact; + QmlObjectListModel* _frameClassModel; }; -class APMAirframe : public QObject +class APMFrameClass : public QObject { Q_OBJECT public: - APMAirframe(const QString& name, const QString& paramsFile, int type, QObject* parent = NULL); - ~APMAirframe(); + APMFrameClass(const QString& name, int frameClass, Fact* frameTypeFact, int defaultFrameType, QObject* parent = nullptr); + ~APMFrameClass(); - Q_PROPERTY(QString name MEMBER _name CONSTANT) - Q_PROPERTY(int type MEMBER _type CONSTANT) - Q_PROPERTY(QString params MEMBER _paramsFile CONSTANT) - - QString name() const; - QString params() const; - int type() const; + Q_PROPERTY(QString name MEMBER _name CONSTANT) + Q_PROPERTY(int frameClass MEMBER _frameClass CONSTANT) + Q_PROPERTY(int frameType READ frameType NOTIFY frameTypeChanged) + Q_PROPERTY(int defaultFrameType MEMBER _defaultFrameType CONSTANT) + Q_PROPERTY(QString imageResource READ imageResource NOTIFY imageResourceChanged) + Q_PROPERTY(bool frameTypeSupported MEMBER _frameTypeSupported CONSTANT) + + int frameType (void) { return _frameTypeFact->rawValue().toInt(); }; + QString imageResource (void); -private: QString _name; - QString _paramsFile; - int _type; -}; + QString _imageResource; + int _frameClass; + int _defaultFrameType; + bool _frameTypeSupported; -class APMAirframeType : public QObject -{ - Q_OBJECT - -public: - APMAirframeType(const QString& name, const QString& imageResource, int type, QObject* parent = NULL); - ~APMAirframeType(); - - Q_PROPERTY(QString name MEMBER _name CONSTANT) - Q_PROPERTY(QString imageResource MEMBER _imageResource CONSTANT) - Q_PROPERTY(QVariantList airframes MEMBER _airframes CONSTANT) - Q_PROPERTY(int type MEMBER _type CONSTANT) - Q_PROPERTY(bool dirty MEMBER _dirty CONSTANT) - void addAirframe(const QString& name, const QString& paramsFile, int type); +signals: + void imageResourceChanged(void); + void frameTypeChanged(); - QString name() const; - QString imageResource() const; - int type() const; private: - QString _name; - QString _imageResource; - QVariantList _airframes; - int _type; - bool _dirty; + Fact* _frameTypeFact; }; - -#endif diff --git a/src/AutoPilotPlugins/APM/APMAirframeFactMetaData.xml b/src/AutoPilotPlugins/APM/APMAirframeFactMetaData.xml deleted file mode 100644 index 8552c06..0000000 --- a/src/AutoPilotPlugins/APM/APMAirframeFactMetaData.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/AutoPilotPlugins/APM/APMAirframeLoader.cc b/src/AutoPilotPlugins/APM/APMAirframeLoader.cc deleted file mode 100644 index df2a41d..0000000 --- a/src/AutoPilotPlugins/APM/APMAirframeLoader.cc +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/// @file -/// @author Don Gagne - -#include "APMAirframeLoader.h" -#include "QGCApplication.h" -#include "QGCLoggingCategory.h" -#include "APMAirframeComponentAirframes.h" - -#include -#include -#include -#include - -QGC_LOGGING_CATEGORY(APMAirframeLoaderLog, "APMAirframeLoaderLog") - -bool APMAirframeLoader::_airframeMetaDataLoaded = false; - -APMAirframeLoader::APMAirframeLoader(AutoPilotPlugin* autopilot, UASInterface* uas, QObject* parent) -{ - Q_UNUSED(autopilot); - Q_UNUSED(uas); - Q_UNUSED(parent); - Q_ASSERT(uas); -} - -/// Load Airframe Fact meta data -void APMAirframeLoader::loadAirframeFactMetaData(void) -{ - if (_airframeMetaDataLoaded) { - return; - } - - qCDebug(APMAirframeLoaderLog) << "Loading APM airframe fact meta data"; - - Q_ASSERT(APMAirframeComponentAirframes::get().count() == 0); - - QString airframeFilename(QStringLiteral(":/AutoPilotPlugins/APM/APMAirframeFactMetaData.xml")); - - qCDebug(APMAirframeLoaderLog) << "Loading meta data file:" << airframeFilename; - - QFile xmlFile(airframeFilename); - Q_ASSERT(xmlFile.exists()); - - bool success = xmlFile.open(QIODevice::ReadOnly); - Q_UNUSED(success); - Q_ASSERT(success); - - QXmlStreamReader xml(xmlFile.readAll()); - xmlFile.close(); - if (xml.hasError()) { - qCWarning(APMAirframeLoaderLog) << "Badly formed XML" << xml.errorString(); - return; - } - - QString airframeGroup; - QString image; - int groupId = 0; - while (!xml.atEnd()) { - if (xml.isStartElement()) { - QString elementName = xml.name().toString(); - QXmlStreamAttributes attr = xml.attributes(); - if (elementName == QLatin1Literal("airframe_group")) { - airframeGroup = attr.value(QStringLiteral("name")).toString(); - image = attr.value(QStringLiteral("image")).toString(); - groupId = attr.value(QStringLiteral("id")).toInt(); - APMAirframeComponentAirframes::insert(airframeGroup, groupId, image); - } else if (elementName == QLatin1Literal("airframe")) { - QString name = attr.value(QStringLiteral("name")).toString(); - QString file = attr.value(QStringLiteral("file")).toString(); - APMAirframeComponentAirframes::insert(airframeGroup, groupId, image, name, file); - } - } - xml.readNext(); - } - - _airframeMetaDataLoaded = true; -} diff --git a/src/AutoPilotPlugins/APM/APMAirframeLoader.h b/src/AutoPilotPlugins/APM/APMAirframeLoader.h deleted file mode 100644 index 76cec12..0000000 --- a/src/AutoPilotPlugins/APM/APMAirframeLoader.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#ifndef APMAirframeLoader_H -#define APMAirframeLoader_H - -#include -#include -#include -#include - -#include "ParameterManager.h" -#include "FactSystem.h" -#include "UASInterface.h" -#include "AutoPilotPlugin.h" - -/// @file APMAirframeLoader.h -/// @author Lorenz Meier - -Q_DECLARE_LOGGING_CATEGORY(APMAirframeLoaderLog) - -/// Collection of Parameter Facts for PX4 AutoPilot - -class APMAirframeLoader : QObject -{ - Q_OBJECT - -public: - /// @param uas Uas which this set of facts is associated with - APMAirframeLoader(AutoPilotPlugin* autpilot,UASInterface* uas, QObject* parent = NULL); - - static void loadAirframeFactMetaData(void); - -private: - static bool _airframeMetaDataLoaded; ///< true: parameter meta data already loaded - static QMap _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData -}; - -#endif // APMAirframeLoader_H diff --git a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc index abc156e..ee194b3 100644 --- a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc +++ b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc @@ -15,8 +15,6 @@ #include "FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h" #include "VehicleComponent.h" #include "APMAirframeComponent.h" -#include "APMAirframeComponentAirframes.h" -#include "APMAirframeLoader.h" #include "APMFlightModesComponent.h" #include "APMRadioComponent.h" #include "APMSafetyComponent.h" @@ -30,6 +28,7 @@ #include "ESP8266Component.h" #include "APMHeliComponent.h" #include "QGCApplication.h" +#include "ParameterManager.h" #if !defined(NO_SERIAL_LINK) && !defined(__android__) #include @@ -50,12 +49,9 @@ APMAutoPilotPlugin::APMAutoPilotPlugin(Vehicle* vehicle, QObject* parent) , _safetyComponent (NULL) , _sensorsComponent (NULL) , _tuningComponent (NULL) - , _airframeFacts (new APMAirframeLoader(this, vehicle->uas(), this)) , _esp8266Component (NULL) , _heliComponent (NULL) { - APMAirframeLoader::loadAirframeFactMetaData(); - #if !defined(NO_SERIAL_LINK) && !defined(__android__) connect(vehicle->parameterManager(), &ParameterManager::parametersReadyChanged, this, &APMAutoPilotPlugin::_checkForBadCubeBlack); #endif diff --git a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h index 5c6a5ac..cc1f21d 100644 --- a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h +++ b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h @@ -15,7 +15,6 @@ #include "Vehicle.h" class APMAirframeComponent; -class APMAirframeLoader; class APMFlightModesComponent; class APMRadioComponent; class APMTuningComponent; @@ -55,7 +54,6 @@ protected: APMSafetyComponent* _safetyComponent; APMSensorsComponent* _sensorsComponent; APMTuningComponent* _tuningComponent; - APMAirframeLoader* _airframeFacts; ESP8266Component* _esp8266Component; APMHeliComponent* _heliComponent; diff --git a/src/AutoPilotPlugins/APM/APMPowerComponent.qml b/src/AutoPilotPlugins/APM/APMPowerComponent.qml index 7bb93fc..2e70356 100644 --- a/src/AutoPilotPlugins/APM/APMPowerComponent.qml +++ b/src/AutoPilotPlugins/APM/APMPowerComponent.qml @@ -45,6 +45,8 @@ SetupPage { property bool _batt2ParamsAvailable: controller.parameterExists(-1, "BATT2_CAPACITY") property bool _showBatt1Reboot: _batt1MonitorEnabled && !_batt1ParamsAvailable property bool _showBatt2Reboot: _batt2MonitorEnabled && !_batt2ParamsAvailable + property bool _escCalibrationAvailable: controller.parameterExists(-1, "ESC_CALIBRATION") + property Fact _escCalibration: controller.getParameterFact(-1, "ESC_CALIBRATION", false /* reportMissing */) property string _restartRequired: qsTr("Requires vehicle reboot") @@ -217,6 +219,61 @@ SetupPage { } } } + + Column { + spacing: _margins / 2 + visible: _escCalibrationAvailable + + QGCLabel { + text: qsTr("ESC Calibration") + font.family: ScreenTools.demiboldFontFamily + } + + Rectangle { + width: escCalibrationHolder.x + escCalibrationHolder.width + _margins + height: escCalibrationHolder.y + escCalibrationHolder.height + _margins + color: ggcPal.windowShade + + Column { + id: escCalibrationHolder + x: _margins + y: _margins + spacing: _margins + + Column { + spacing: _margins + + QGCLabel { + text: qsTr("WARNING: Remove props prior to calibration!") + color: qgcPal.warningText + } + + Row { + spacing: _margins + + QGCButton { + text: qsTr("Calibrate") + enabled: _escCalibration.rawValue === 0 + onClicked: _escCalibration.rawValue = 3 + } + + Column { + enabled: _escCalibration.rawValue === 3 + QGCLabel { text: _escCalibration.rawValue === 3 ? qsTr("Now perform these steps:") : qsTr("Click Calibrate to start, then:") } + QGCLabel { text: qsTr("- Disconnect USB and battery so flight controller powers down") } + QGCLabel { text: qsTr("- Connect the battery") } + QGCLabel { text: qsTr("- The arming tone will be played (if the vehicle has a buzzer attached)") } + QGCLabel { text: qsTr("- If using a flight controller with a safety button press it until it displays solid red") } + QGCLabel { text: qsTr("- You will hear a musical tone then two beeps") } + QGCLabel { text: qsTr("- A few seconds later you should hear a number of beeps (one for each battery cell you’re using)") } + QGCLabel { text: qsTr("- And finally a single long beep indicating the end points have been set and the ESC is calibrated") } + QGCLabel { text: qsTr("- Disconnect the battery and power up again normally") } + } + } + } + } + } + } } // Flow } // Component - powerPageComponent diff --git a/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc b/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc index f1da4d4..b4ce2e4 100644 --- a/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc +++ b/src/FirmwarePlugin/APM/APMFirmwarePlugin.cc @@ -889,9 +889,9 @@ void APMFirmwarePlugin::guidedModeGotoLocation(Vehicle* vehicle, const QGeoCoord vehicle->missionManager()->writeArduPilotGuidedMissionItem(coordWithAltitude, false /* altChangeOnly */); } -void APMFirmwarePlugin::guidedModeRTL(Vehicle* vehicle) +void APMFirmwarePlugin::guidedModeRTL(Vehicle* vehicle, bool smartRTL) { - _setFlightModeAndValidate(vehicle, rtlFlightMode()); + _setFlightModeAndValidate(vehicle, smartRTL ? smartRTLFlightMode() : rtlFlightMode()); } void APMFirmwarePlugin::guidedModeChangeAltitude(Vehicle* vehicle, double altitudeChange) diff --git a/src/FirmwarePlugin/APM/APMFirmwarePlugin.h b/src/FirmwarePlugin/APM/APMFirmwarePlugin.h index ddf754e..b7cbfbb 100644 --- a/src/FirmwarePlugin/APM/APMFirmwarePlugin.h +++ b/src/FirmwarePlugin/APM/APMFirmwarePlugin.h @@ -86,9 +86,10 @@ public: bool isGuidedMode (const Vehicle* vehicle) const override; QString gotoFlightMode (void) const override { return QStringLiteral("Guided"); } QString rtlFlightMode (void) const override { return QString("RTL"); } + QString smartRTLFlightMode (void) const override { return QString("Smart RTL"); } QString missionFlightMode (void) const override { return QString("Auto"); } void pauseVehicle (Vehicle* vehicle) override; - void guidedModeRTL (Vehicle* vehicle) override; + void guidedModeRTL (Vehicle* vehicle, bool smartRTL) override; void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeChange) override; bool adjustIncomingMavlinkMessage (Vehicle* vehicle, mavlink_message_t* message) override; void adjustOutgoingMavlinkMessage (Vehicle* vehicle, LinkInterface* outgoingLink, mavlink_message_t* message) override; diff --git a/src/FirmwarePlugin/APM/APMResources.qrc b/src/FirmwarePlugin/APM/APMResources.qrc index f7bf054..7be5deb 100644 --- a/src/FirmwarePlugin/APM/APMResources.qrc +++ b/src/FirmwarePlugin/APM/APMResources.qrc @@ -37,9 +37,6 @@ MavCmdInfoSub.json MavCmdInfoVTOL.json - - ../../AutoPilotPlugins/APM/APMAirframeFactMetaData.xml - APMParameterFactMetaData.Plane.3.8.xml APMParameterFactMetaData.Plane.3.9.xml diff --git a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc index a60aef3..e60752d 100644 --- a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc +++ b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc @@ -23,26 +23,25 @@ APMCopterMode::APMCopterMode(uint32_t mode, bool settable) : APMCustomMode(mode, settable) { QMap enumToString; - enumToString.insert(STABILIZE, "Stabilize"); - enumToString.insert(ACRO, "Acro"); - enumToString.insert(ALT_HOLD, "Altitude Hold"); - enumToString.insert(AUTO, "Auto"); - enumToString.insert(GUIDED, "Guided"); - enumToString.insert(LOITER, "Loiter"); - enumToString.insert(RTL, "RTL"); - enumToString.insert(CIRCLE, "Circle"); - enumToString.insert(LAND, "Land"); - enumToString.insert(DRIFT, "Drift"); - enumToString.insert(SPORT, "Sport"); - enumToString.insert(FLIP, "Flip"); - enumToString.insert(AUTOTUNE, "Autotune"); - enumToString.insert(POS_HOLD, "Position Hold"); - enumToString.insert(BRAKE, "Brake"); - enumToString.insert(THROW, "Throw"); - enumToString.insert(AVOID_ADSB,"Avoid ADSB"); - enumToString.insert(GUIDED_NOGPS,"Guided No GPS"); - enumToString.insert(SAFE_RTL,"Smart RTL"); - + enumToString.insert(STABILIZE, "Stabilize"); + enumToString.insert(ACRO, "Acro"); + enumToString.insert(ALT_HOLD, "Altitude Hold"); + enumToString.insert(AUTO, "Auto"); + enumToString.insert(GUIDED, "Guided"); + enumToString.insert(LOITER, "Loiter"); + enumToString.insert(RTL, "RTL"); + enumToString.insert(CIRCLE, "Circle"); + enumToString.insert(LAND, "Land"); + enumToString.insert(DRIFT, "Drift"); + enumToString.insert(SPORT, "Sport"); + enumToString.insert(FLIP, "Flip"); + enumToString.insert(AUTOTUNE, "Autotune"); + enumToString.insert(POS_HOLD, "Position Hold"); + enumToString.insert(BRAKE, "Brake"); + enumToString.insert(THROW, "Throw"); + enumToString.insert(AVOID_ADSB, "Avoid ADSB"); + enumToString.insert(GUIDED_NOGPS, "Guided No GPS"); + enumToString.insert(SAFE_RTL, "Smart RTL"); setEnumToStringMapping(enumToString); } diff --git a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h index 6bdc9f6..563baf7 100644 --- a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h +++ b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h @@ -65,8 +65,9 @@ public: QString pauseFlightMode (void) const override { return QString("Brake"); } QString landFlightMode (void) const override { return QString("Land"); } QString takeControlFlightMode (void) const override { return QString("Loiter"); } - bool vehicleYawsToNextWaypointInMission (const Vehicle* vehicle) const final; - QString autoDisarmParameter (Vehicle* vehicle) final { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); } + bool vehicleYawsToNextWaypointInMission (const Vehicle* vehicle) const override; + QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); } + bool supportsSmartRTL (void) const override { return true; } private: static bool _remapParamNameIntialized; diff --git a/src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.h b/src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.h index 3175fb2..0e2d452 100644 --- a/src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.h +++ b/src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.h @@ -47,10 +47,11 @@ public: // Overrides from FirmwarePlugin QString pauseFlightMode (void) const override { return QString("Hold"); } - void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeChange) override; - int remapParamNameHigestMinorVersionNumber (int majorVersionNumber) const override; - const FirmwarePlugin::remapParamNameMajorVersionMap_t& paramNameRemapMajorVersionMap(void) const override { return _remapParamName; } - bool supportsNegativeThrust (void) override; + void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeChange) final; + int remapParamNameHigestMinorVersionNumber (int majorVersionNumber) const final; + const FirmwarePlugin::remapParamNameMajorVersionMap_t& paramNameRemapMajorVersionMap(void) const final { return _remapParamName; } + bool supportsNegativeThrust (void) final; + bool supportsSmartRTL (void) const override { return true; } QString offlineEditingParamFile (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral(":/FirmwarePlugin/APM/Rover.OfflineEditing.params"); } private: diff --git a/src/FirmwarePlugin/FirmwarePlugin.cc b/src/FirmwarePlugin/FirmwarePlugin.cc index 1790a4a..00c4076 100644 --- a/src/FirmwarePlugin/FirmwarePlugin.cc +++ b/src/FirmwarePlugin/FirmwarePlugin.cc @@ -240,10 +240,11 @@ void FirmwarePlugin::pauseVehicle(Vehicle* vehicle) qgcApp()->showMessage(guided_mode_not_supported_by_vehicle); } -void FirmwarePlugin::guidedModeRTL(Vehicle* vehicle) +void FirmwarePlugin::guidedModeRTL(Vehicle* vehicle, bool smartRTL) { // Not supported by generic vehicle Q_UNUSED(vehicle); + Q_UNUSED(smartRTL); qgcApp()->showMessage(guided_mode_not_supported_by_vehicle); } diff --git a/src/FirmwarePlugin/FirmwarePlugin.h b/src/FirmwarePlugin/FirmwarePlugin.h index df1ebba..3fb7ca8 100644 --- a/src/FirmwarePlugin/FirmwarePlugin.h +++ b/src/FirmwarePlugin/FirmwarePlugin.h @@ -105,6 +105,11 @@ public: /// Returns the flight mode for RTL virtual QString rtlFlightMode(void) const { return QString(); } + /// Returns the flight mode for Smart RTL + virtual QString smartRTLFlightMode(void) const { return QString(); } + + virtual bool supportsSmartRTL(void) const { return false; } + /// Returns the flight mode for Land virtual QString landFlightMode(void) const { return QString(); } @@ -125,7 +130,7 @@ public: virtual void pauseVehicle(Vehicle* vehicle); /// Command vehicle to return to launch - virtual void guidedModeRTL(Vehicle* vehicle); + virtual void guidedModeRTL(Vehicle* vehicle, bool smartRTL); /// Command vehicle to land at current location virtual void guidedModeLand(Vehicle* vehicle); diff --git a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc index 5373488..63b7054 100644 --- a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc +++ b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc @@ -351,8 +351,9 @@ void PX4FirmwarePlugin::pauseVehicle(Vehicle* vehicle) NAN); } -void PX4FirmwarePlugin::guidedModeRTL(Vehicle* vehicle) +void PX4FirmwarePlugin::guidedModeRTL(Vehicle* vehicle, bool smartRTL) { + Q_UNUSED(smartRTL); _setFlightModeAndValidate(vehicle, _rtlFlightMode); } diff --git a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h index edee888..3e7f794 100644 --- a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h +++ b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h @@ -44,7 +44,7 @@ public: QString takeControlFlightMode (void) const override { return _manualFlightMode; } QString gotoFlightMode (void) const override { return _holdFlightMode; } void pauseVehicle (Vehicle* vehicle) override; - void guidedModeRTL (Vehicle* vehicle) override; + void guidedModeRTL (Vehicle* vehicle, bool smartRTL) override; void guidedModeLand (Vehicle* vehicle) override; void guidedModeTakeoff (Vehicle* vehicle, double takeoffAltRel) override; void guidedModeGotoLocation (Vehicle* vehicle, const QGeoCoordinate& gotoCoord) override; diff --git a/src/FlightDisplay/GuidedActionConfirm.qml b/src/FlightDisplay/GuidedActionConfirm.qml index 177e194..dcb74ca 100644 --- a/src/FlightDisplay/GuidedActionConfirm.qml +++ b/src/FlightDisplay/GuidedActionConfirm.qml @@ -35,6 +35,8 @@ Rectangle { property var actionData property bool hideTrigger: false property var mapIndicator + property alias optionText: optionCheckBox.text + property alias optionChecked: optionCheckBox.checked property real _margins: ScreenTools.defaultFontPixelWidth property bool _emergencyAction: action === guidedController.actionEmergencyStop @@ -101,6 +103,13 @@ Rectangle { wrapMode: Text.WordWrap } + QGCCheckBox { + id: optionCheckBox + anchors.horizontalCenter: parent.horizontalCenter + text: "" + visible: text !== "" + } + // Action confirmation control SliderSwitch { id: slider @@ -115,7 +124,7 @@ Rectangle { altitudeSlider.visible = false } hideTrigger = false - guidedController.executeAction(_root.action, _root.actionData, altitudeChange) + guidedController.executeAction(_root.action, _root.actionData, altitudeChange, _root.optionChecked) if (mapIndicator) { mapIndicator.actionConfirmed() mapIndicator = undefined diff --git a/src/FlightDisplay/GuidedActionsController.qml b/src/FlightDisplay/GuidedActionsController.qml index c099ed6..953ab6e 100644 --- a/src/FlightDisplay/GuidedActionsController.qml +++ b/src/FlightDisplay/GuidedActionsController.qml @@ -203,7 +203,7 @@ Item { on_FlightModeChanged: { _vehiclePaused = _activeVehicle ? _flightMode === _activeVehicle.pauseFlightMode : false - _vehicleInRTLMode = _activeVehicle ? _flightMode === _activeVehicle.rtlFlightMode : false + _vehicleInRTLMode = _activeVehicle ? _flightMode === _activeVehicle.rtlFlightMode || _flightMode === _activeVehicle.smartRTLFlightMode : false _vehicleInLandMode = _activeVehicle ? _flightMode === _activeVehicle.landFlightMode : false _vehicleInMissionMode = _activeVehicle ? _flightMode === _activeVehicle.missionFlightMode : false // Must be last to get correct signalling for showStartMission popups } @@ -216,6 +216,7 @@ Item { confirmDialog.actionData = actionData confirmDialog.hideTrigger = true confirmDialog.mapIndicator = mapIndicator + confirmDialog.optionText = "" _actionData = actionData switch (actionCode) { case actionArm: @@ -279,6 +280,10 @@ Item { case actionRTL: confirmDialog.title = rtlTitle confirmDialog.message = rtlMessage + if (_activeVehicle.supportsSmartRTL) { + confirmDialog.optionText = qsTr("Smart RTL") + confirmDialog.optionChecked = false + } confirmDialog.hideTrigger = Qt.binding(function() { return !showRTL }) break; case actionChangeAlt: @@ -339,12 +344,12 @@ Item { } // Executes the specified action - function executeAction(actionCode, actionData, actionAltitudeChange) { + function executeAction(actionCode, actionData, actionAltitudeChange, optionChecked) { var i; var rgVehicle; switch (actionCode) { case actionRTL: - _activeVehicle.guidedModeRTL() + _activeVehicle.guidedModeRTL(optionChecked) break case actionLand: _activeVehicle.guidedModeLand() diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc index e02d602..35e0db7 100644 --- a/src/Vehicle/Vehicle.cc +++ b/src/Vehicle/Vehicle.cc @@ -2975,13 +2975,13 @@ QString Vehicle::gotoFlightMode() const return _firmwarePlugin->gotoFlightMode(); } -void Vehicle::guidedModeRTL(void) +void Vehicle::guidedModeRTL(bool smartRTL) { if (!guidedModeSupported()) { qgcApp()->showMessage(guided_mode_not_supported_by_vehicle); return; } - _firmwarePlugin->guidedModeRTL(this); + _firmwarePlugin->guidedModeRTL(this, smartRTL); } void Vehicle::guidedModeLand(void) @@ -3602,6 +3602,16 @@ QString Vehicle::rtlFlightMode(void) const return _firmwarePlugin->rtlFlightMode(); } +QString Vehicle::smartRTLFlightMode(void) const +{ + return _firmwarePlugin->smartRTLFlightMode(); +} + +bool Vehicle::supportsSmartRTL(void) const +{ + return _firmwarePlugin->supportsSmartRTL(); +} + QString Vehicle::landFlightMode(void) const { return _firmwarePlugin->landFlightMode(); diff --git a/src/Vehicle/Vehicle.h b/src/Vehicle/Vehicle.h index c370698..a71e6a5 100644 --- a/src/Vehicle/Vehicle.h +++ b/src/Vehicle/Vehicle.h @@ -600,6 +600,8 @@ public: Q_PROPERTY(QString missionFlightMode READ missionFlightMode CONSTANT) Q_PROPERTY(QString pauseFlightMode READ pauseFlightMode CONSTANT) Q_PROPERTY(QString rtlFlightMode READ rtlFlightMode CONSTANT) + Q_PROPERTY(QString smartRTLFlightMode READ smartRTLFlightMode CONSTANT) + Q_PROPERTY(bool supportsSmartRTL READ supportsSmartRTL CONSTANT) Q_PROPERTY(QString landFlightMode READ landFlightMode CONSTANT) Q_PROPERTY(QString takeControlFlightMode READ takeControlFlightMode CONSTANT) Q_PROPERTY(QString firmwareTypeString READ firmwareTypeString NOTIFY firmwareTypeChanged) @@ -698,7 +700,7 @@ public: Q_INVOKABLE void disconnectInactiveVehicle(void); /// Command vehicle to return to launch - Q_INVOKABLE void guidedModeRTL(void); + Q_INVOKABLE void guidedModeRTL(bool smartRTL); /// Command vehicle to land at current location Q_INVOKABLE void guidedModeLand(void); @@ -919,6 +921,8 @@ public: QString missionFlightMode () const; QString pauseFlightMode () const; QString rtlFlightMode () const; + QString smartRTLFlightMode () const; + bool supportsSmartRTL () const; QString landFlightMode () const; QString takeControlFlightMode () const; double defaultCruiseSpeed () const { return _defaultCruiseSpeed; }