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.
### 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.
* ArduCopter: Handle 3.7 parameter name change from CH#_OPT to RC#_OPTION.
* Improved support for flashing/connecting to ChibiOS bootloaders boards.
......
......@@ -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 \
......
......@@ -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
/****************************************************************************
*
* (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 @@
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef APMAirframeComponentController_H
#define APMAirframeComponentController_H
#pragma once
#include <QObject>
#include <QQuickItem>
......@@ -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
<?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);
static void loadAirframeFactMetaData(void);
private:
static bool _airframeMetaDataLoaded; ///< true: parameter meta data already loaded
static QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData
};
#endif // APMAirframeLoader_H
......@@ -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 <QSerialPortInfo>
......@@ -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
......
......@@ -15,7 +15,6 @@
#include "Vehicle.h"
class APMAirframeComponent;
class APMAirframeLoader;