Commit 57d0292d authored by DonLakeFlyer's avatar DonLakeFlyer

parent a32d84f8
...@@ -6,6 +6,7 @@ Note: This file only contains high level features or important fixes. ...@@ -6,6 +6,7 @@ Note: This file only contains high level features or important fixes.
### 3.6.0 - Daily Build ### 3.6.0 - Daily Build
* ArduPilot: Rework Airframe setup ui
* Plan/Pattern: Support named presets to simplify commonly used settings setup. Currently only supported by Survey. * 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. * ArduCopter: Handle 3.7 parameter name change from CH#_OPT to RC#_OPTION.
* Improved support for flashing/connecting to ChibiOS bootloaders boards. * Improved support for flashing/connecting to ChibiOS bootloaders boards.
......
...@@ -984,9 +984,7 @@ APMFirmwarePlugin { ...@@ -984,9 +984,7 @@ APMFirmwarePlugin {
HEADERS += \ HEADERS += \
src/AutoPilotPlugins/APM/APMAirframeComponent.h \ src/AutoPilotPlugins/APM/APMAirframeComponent.h \
src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h \
src/AutoPilotPlugins/APM/APMAirframeComponentController.h \ src/AutoPilotPlugins/APM/APMAirframeComponentController.h \
src/AutoPilotPlugins/APM/APMAirframeLoader.h \
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h \ src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h \
src/AutoPilotPlugins/APM/APMCameraComponent.h \ src/AutoPilotPlugins/APM/APMCameraComponent.h \
src/AutoPilotPlugins/APM/APMCompassCal.h \ src/AutoPilotPlugins/APM/APMCompassCal.h \
...@@ -1011,9 +1009,7 @@ APMFirmwarePlugin { ...@@ -1011,9 +1009,7 @@ APMFirmwarePlugin {
SOURCES += \ SOURCES += \
src/AutoPilotPlugins/APM/APMAirframeComponent.cc \ src/AutoPilotPlugins/APM/APMAirframeComponent.cc \
src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.cc \
src/AutoPilotPlugins/APM/APMAirframeComponentController.cc \ src/AutoPilotPlugins/APM/APMAirframeComponentController.cc \
src/AutoPilotPlugins/APM/APMAirframeLoader.cc \
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc \ src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc \
src/AutoPilotPlugins/APM/APMCameraComponent.cc \ src/AutoPilotPlugins/APM/APMCameraComponent.cc \
src/AutoPilotPlugins/APM/APMCompassCal.cc \ src/AutoPilotPlugins/APM/APMCompassCal.cc \
......
...@@ -22,90 +22,155 @@ import QGroundControl.ScreenTools 1.0 ...@@ -22,90 +22,155 @@ import QGroundControl.ScreenTools 1.0
SetupPage { SetupPage {
id: airframePage id: airframePage
pageComponent: _useOldFrameParam ? oldFramePageComponent: newFramePageComponent pageComponent: pageComponent
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
}
Component { Component {
id: oldFramePageComponent id: pageComponent
Column { ColumnLayout {
width: availableWidth id: mainColumn
height: 1000 width: availableWidth
spacing: _margins
property real _minW: ScreenTools.defaultFontPixelWidth * 20
RowLayout { property real _boxWidth: _minW
anchors.left: parent.left property real _boxSpace: ScreenTools.defaultFontPixelWidth
anchors.right: parent.right property real _margins: ScreenTools.defaultFontPixelWidth
spacing: _margins property Fact _frameClass: controller.getParameterFact(-1, "FRAME_CLASS")
property Fact _frameType: controller.getParameterFact(-1, "FRAME_TYPE")
QGCLabel {
font.pointSize: ScreenTools.mediumFontPointSize readonly property real spacerHeight: ScreenTools.defaultFontPixelHeight
wrapMode: Text.WordWrap
text: qsTr("Please select your airframe type") onWidthChanged: computeDimensions()
Layout.fillWidth: true 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 { APMAirframeComponentController {
model: controller.airframeTypesModel id: controller
factPanel: airframePage.viewPanel
}
QGCRadioButton { QGCLabel {
text: object.name id: helpText
checked: controller.currentAirframeType == object Layout.fillWidth: true
exclusiveGroup: airframeTypeExclusive 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: { Item {
if (checked) { id: lastSpacer
controller.currentAirframeType = object height: parent.spacerHeight
} width: 10
}
}
} }
} // Column
} // Component - oldFramePageComponent
Component { Flow {
id: newFramePageComponent id: flowView
Layout.fillWidth: true
spacing: _boxSpace
Grid { ExclusiveGroup {
width: availableWidth id: airframeTypeExclusive
spacing: _margins }
columns: 2
QGCLabel { Repeater {
text: qsTr("Frame Class:") model: controller.frameClassModel
}
FactComboBox { // Outer summary item rectangle
fact: _newFrameParam Rectangle {
indexModel: false id: outerRect
width: ScreenTools.defaultFontPixelWidth * 15 width: _boxWidth
} height: ScreenTools.defaultFontPixelHeight * 14
color: qgcPal.window
QGCLabel { readonly property real titleHeight: ScreenTools.defaultFontPixelHeight * 1.75
text: qsTr("Frame Type:") readonly property real innerMargin: ScreenTools.defaultFontPixelWidth
}
FactComboBox { MouseArea {
fact: _frameTypeParam anchors.fill: parent
indexModel: false onClicked: airframeCheckBox.checked = true
width: ScreenTools.defaultFontPixelWidth * 15 }
}
} 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 } // SetupPage
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "APMAirframeComponentAirframes.h"
#include "APMAirframeComponentController.h"
QMap<QString, APMAirframeComponentAirframes::AirframeType_t*> APMAirframeComponentAirframes::rgAirframeTypes;
QMap<QString, APMAirframeComponentAirframes::AirframeType_t*>& 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<AirframeType_t*> valueList = get().values();
foreach(AirframeType_t *pType, valueList) {
qDeleteAll(pType->rgAirframeInfo);
delete pType;
}
rgAirframeTypes.clear();
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef APMAirframeComponentAirframes_H
#define APMAirframeComponentAirframes_H
#include <QObject>
#include <QQuickItem>
#include <QList>
#include <QMap>
#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<APMAirframe*> rgAirframeInfo;
} AirframeType_t;
typedef QMap<QString, AirframeType_t*> 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
...@@ -7,12 +7,7 @@ ...@@ -7,12 +7,7 @@
* *
****************************************************************************/ ****************************************************************************/
#pragma once
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef APMAirframeComponentController_H
#define APMAirframeComponentController_H
#include <QObject> #include <QObject>
#include <QQuickItem> #include <QQuickItem>
...@@ -22,7 +17,6 @@ ...@@ -22,7 +17,6 @@
#include "UASInterface.h" #include "UASInterface.h"
#include "AutoPilotPlugin.h" #include "AutoPilotPlugin.h"
#include "FactPanelController.h" #include "FactPanelController.h"
#include "APMAirframeComponentAirframes.h"
class APMAirframeModel; class APMAirframeModel;
class APMAirframeType; class APMAirframeType;
...@@ -33,98 +27,56 @@ class APMAirframeComponentController : public FactPanelController ...@@ -33,98 +27,56 @@ class APMAirframeComponentController : public FactPanelController
Q_OBJECT Q_OBJECT
public: 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(void);
~APMAirframeComponentController(); ~APMAirframeComponentController();
Q_PROPERTY(QmlObjectListModel* airframeTypesModel MEMBER _airframeTypesModel CONSTANT) Q_PROPERTY(QmlObjectListModel* frameClassModel MEMBER _frameClassModel CONSTANT)
Q_PROPERTY(APMAirframeType* currentAirframeType READ currentAirframeType WRITE setCurrentAirframeType NOTIFY currentAirframeTypeChanged)
Q_INVOKABLE void loadParameters(const QString& paramFile); 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: private slots:
void _fillAirFrames(void);
void _factFrameChanged(QVariant v);
void _githubJsonDownloadFinished(QString remoteFile, QString localFile); void _githubJsonDownloadFinished(QString remoteFile, QString localFile);
void _githubJsonDownloadError(QString errorMsg); void _githubJsonDownloadError(QString errorMsg);
void _paramFileDownloadFinished(QString remoteFile, QString localFile); void _paramFileDownloadFinished(QString remoteFile, QString localFile);
void _paramFileDownloadError(QString errorMsg); void _paramFileDownloadError(QString errorMsg);
private: private:
void _fillFrameClasses(void);
void _loadParametersFromDownloadFile(const QString& downloadedParamFile); void _loadParametersFromDownloadFile(const QString& downloadedParamFile);
APMAirframeType *_currentAirframeType; Fact* _frameClassFact;
QmlObjectListModel *_airframeTypesModel; Fact* _frameTypeFact;
QmlObjectListModel* _frameClassModel;
static bool _typesRegistered;
static const char* _oldFrameParam;
static const char* _newFrameParam;
}; };
class APMAirframe : public QObject class APMFrameClass : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
APMAirframe(const QString& name, const QString& paramsFile, int type, QObject* parent = NULL); APMFrameClass(const QString& name, int frameClass, Fact* frameTypeFact, int defaultFrameType, QObject* parent = nullptr);
~APMAirframe(); ~APMFrameClass();
Q_PROPERTY(QString name MEMBER _name CONSTANT) Q_PROPERTY(QString name MEMBER _name CONSTANT)
Q_PROPERTY(int type MEMBER _type CONSTANT) Q_PROPERTY(int frameClass MEMBER _frameClass CONSTANT)
Q_PROPERTY(QString params MEMBER _paramsFile CONSTANT) Q_PROPERTY(int frameType READ frameType NOTIFY frameTypeChanged)
Q_PROPERTY(int defaultFrameType MEMBER _defaultFrameType CONSTANT)
QString name() const; Q_PROPERTY(QString imageResource READ imageResource NOTIFY imageResourceChanged)
QString params() const; Q_PROPERTY(bool frameTypeSupported MEMBER _frameTypeSupported CONSTANT)
int type() const;
int frameType (void) { return _frameTypeFact->rawValue().toInt(); };
QString imageResource (void);
private:
QString _name; QString _name;
QString _paramsFile; QString _imageResource;
int _type; int _frameClass;
}; int _defaultFrameType;
bool _frameTypeSupported;
class APMAirframeType : public QObject signals:
{ void imageResourceChanged(void);
Q_OBJECT void frameTypeChanged();
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);
QString name() const;
QString imageResource() const;
int type() const;
private: private:
QString _name; Fact* _frameTypeFact;
QString _imageResource;
QVariantList _airframes;
int _type;
bool _dirty;
}; };
#endif
<?xml version='1.0' encoding='UTF-8'?>
<airframes>
<version>1</version>
<airframe_group image="AirframeQuadRotorPlus.png" name="Plus Style: Quad, Hexa, Octo, Heli" id="0">
<airframe name="3DR Aero M" file="3DR_AERO_M.param"/>
<airframe name="3DR Aero RTF" file="3DR_Aero_RTF.param"/>
<airframe name="3DR Rover" file="3DR_Rover.param"/>
<airframe name="3DR Tarot" file="3DR_Tarot.bgsc"/>
<airframe name="Parrot Bebop" file="Parrot_Bebop.param"/>
<airframe name="Storm32" file="SToRM32-MAVLink.param"/>
</airframe_group>
<airframe_group image="AirframeQuadRotorX.png" name="X Style, Y6A Style: Quad, Hexa, Octo, X8, Tri, Y6A" id="1">
<airframe name="3DR X8-M RTF" file="3DR_X8-M_RTF.param"/>
<airframe name="3DR Y6A" file="3DR_Y6A_RTF.param"/>
<airframe name="3DR X8+ RTF" file="3DR_X8+_RTF.param"/>
<airframe name="3DR QUAD X4 RTF" file="3DR_QUAD_X4_RTF.param"/>
<airframe name="3DR X8" file="3DR_X8_RTF.param"/>
</airframe_group>
<airframe_group image="AirframeQuadRotorH.png" name="V (3DR Iris)" id="2">
<airframe name="Iris with GoPro" file="Iris with Front Mount Go Pro.param"/>
<airframe name="Iris with Tarot" file="Iris with Tarot Gimbal.param"/>
<airframe name="3DR Iris+" file="3DR_Iris+.param"/>
<airframe name="Iris" file="Iris.param"/>
</airframe_group>
<airframe_group image="AirframeQuadRotorH.png" name="V Tail" id="4">
</airframe_group>
<airframe_group image="AirframeQuadRotorH.png" name="A Tail" id="5">
</airframe_group>
<airframe_group name="H: X and H differ in prop rotation" id="3">
</airframe_group>
<airframe_group name="Y6B Frame (3DR TriCopter): Y6B and Y6A differ in prop rotation" id="10">
<airframe name="3DR Y6B" file="3DR_Y6B_RTF.param"/>
</airframe_group>
<airframes>
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "APMAirframeLoader.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "APMAirframeComponentAirframes.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
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;
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* 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 <QObject>
#include <QMap>
#include <QXmlStreamReader>
#include <QLoggingCategory>
#include "ParameterManager.h"
#include "FactSystem.h"
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
/// @file APMAirframeLoader.h
/// @author Lorenz Meier <lm@qgroundcontrol.org>
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);