Commit d1f25df3 authored by Don Gagne's avatar Don Gagne

Merge pull request #2501 from DonLakeFlyer/AutoTune

APM Auto tune, FactSystem bitmask support
parents 05c80dab 07cbfd02
......@@ -76,6 +76,7 @@
<file alias="QGroundControl/Controls/VehicleSummaryRow.qml">src/QmlControls/VehicleSummaryRow.qml</file>
<file alias="QGroundControl/Controls/ViewWidget.qml">src/ViewWidgets/ViewWidget.qml</file>
<file alias="QGroundControl/Controls/FactSliderPanel.qml">src/QmlControls/FactSliderPanel.qml</file>
<file alias="QGroundControl/FactControls/FactBitmask.qml">src/FactSystem/FactControls/FactBitmask.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/FactControls/FactComboBox.qml">src/FactSystem/FactControls/FactComboBox.qml</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
......
......@@ -48,6 +48,20 @@ QGCView {
property Fact _rateClimbP: controller.getParameterFact(-1, "ACCEL_Z_P")
property Fact _rateClimbI: controller.getParameterFact(-1, "ACCEL_Z_I")
property Fact _ch7Opt: controller.getParameterFact(-1, "CH7_OPT")
property Fact _ch8Opt: controller.getParameterFact(-1, "CH8_OPT")
property Fact _ch9Opt: controller.getParameterFact(-1, "CH9_OPT")
property Fact _ch10Opt: controller.getParameterFact(-1, "CH10_OPT")
property Fact _ch11Opt: controller.getParameterFact(-1, "CH11_OPT")
property Fact _ch12Opt: controller.getParameterFact(-1, "CH12_OPT")
readonly property int _firstOptionChannel: 7
readonly property int _lastOptionChannel: 12
property Fact _autoTuneAxes: controller.getParameterFact(-1, "AUTOTUNE_AXES")
property int _autoTuneSwitchChannelIndex: 0
readonly property int _autoTuneOption: 17
property real _margins: ScreenTools.defaultFontPixelHeight
property bool _loadComplete: false
......@@ -67,8 +81,47 @@ QGCView {
climb.value = _rateClimbP.value
rcFeel.value = _rcFeel.value
_loadComplete = true
calcAutoTuneChannel()
}
/// The AutoTune switch is stored in one of the RC#_FUNCTION parameters. We need to loop through those
/// to find them and setup the ui accordindly.
function calcAutoTuneChannel() {
_autoTuneSwitchChannelIndex = 0
for (var channel=_firstOptionChannel; channel<=_lastOptionChannel; channel++) {
var optionFact = controller.getParameterFact(-1, "CH" + channel + "_OPT")
if (optionFact.value == _autoTuneOption) {
_autoTuneSwitchChannelIndex = channel - _firstOptionChannel + 1
break
}
}
}
/// We need to clear AutoTune from any previous channel before setting it to a new one
function setChannelAutoTuneOption(channel) {
// First clear any previous settings for AutTune
for (var optionChannel=_firstOptionChannel; optionChannel<=_lastOptionChannel; optionChannel++) {
var optionFact = controller.getParameterFact(-1, "CH" + optionChannel + "_OPT")
if (optionFact.value == _autoTuneOption) {
optionFact.value = 0
}
}
// Now set the function into the new channel
if (channel != 0) {
var optionFact = controller.getParameterFact(-1, "CH" + channel + "_OPT")
optionFact.value = _autoTuneOption
}
}
Connections { target: _ch7Opt; onValueChanged: calcAutoTuneChannel() }
Connections { target: _ch8Opt; onValueChanged: calcAutoTuneChannel() }
Connections { target: _ch9Opt; onValueChanged: calcAutoTuneChannel() }
Connections { target: _ch10Opt; onValueChanged: calcAutoTuneChannel() }
Connections { target: _ch11Opt; onValueChanged: calcAutoTuneChannel() }
Connections { target: _ch12Opt; onValueChanged: calcAutoTuneChannel() }
QGCViewPanel {
id: panel
anchors.fill: parent
......@@ -77,7 +130,7 @@ QGCView {
clip: true
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
contentHeight: basicTuning.y + basicTuning.height
contentHeight: autoTuneRect.y + autoTuneRect.height
flickableDirection: Flickable.VerticalFlick
QGCLabel {
......@@ -87,7 +140,7 @@ QGCView {
}
Rectangle {
id: basicTuning
id: basicTuningRect
anchors.topMargin: _margins / 2
anchors.left: parent.left
anchors.right: parent.right
......@@ -229,6 +282,64 @@ QGCView {
}
}
} // Rectangle - Basic tuning
QGCLabel {
id: autoTuneLabel
anchors.topMargin: _margins
anchors.top: basicTuningRect.bottom
text: "AutoTune"
font.weight: Font.DemiBold
}
Rectangle {
id: autoTuneRect
anchors.topMargin: _margins / 2
anchors.left: parent.left
anchors.top: autoTuneLabel.bottom
width: autoTuneColumn.x + autoTuneColumn.width + _margins
height: autoTuneColumn.y + autoTuneColumn.height + _margins
color: palette.windowShade
Column {
id: autoTuneColumn
anchors.margins: _margins
anchors.left: parent.left
anchors.top: parent.top
spacing: _margins
Row {
spacing: _margins
QGCLabel { text: "Axes to AutoTune:" }
FactBitmask { fact: _autoTuneAxes }
}
Row {
spacing: _margins
QGCLabel {
anchors.baseline: autoTuneChannelCombo.baseline
text: "Channel for AutoTune switch:"
}
QGCComboBox {
id: autoTuneChannelCombo
width: ScreenTools.defaultFontPixelWidth * 14
model: ["None", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12" ]
currentIndex: _autoTuneSwitchChannelIndex
onActivated: {
var channel = index
if (channel > 0) {
channel += 6
}
setChannelAutoTuneOption(channel)
}
}
}
}
} // Rectangle - AutoTune
} // Flickable
} // QGCViewPanel
} // QGCView
......@@ -223,6 +223,26 @@ QVariantList Fact::enumValues(void) const
}
}
QStringList Fact::bitmaskStrings(void) const
{
if (_metaData) {
return _metaData->bitmaskStrings();
} else {
qWarning() << "Meta data pointer missing";
return QStringList();
}
}
QVariantList Fact::bitmaskValues(void) const
{
if (_metaData) {
return _metaData->bitmaskValues();
} else {
qWarning() << "Meta data pointer missing";
return QVariantList();
}
}
QString Fact::_variantToString(const QVariant& variant) const
{
QString valueString;
......
......@@ -47,6 +47,8 @@ public:
const Fact& operator=(const Fact& other);
Q_PROPERTY(int componentId READ componentId CONSTANT)
Q_PROPERTY(QStringList bitmaskStrings READ bitmaskStrings NOTIFY bitmaskStringsChanged)
Q_PROPERTY(QVariantList bitmaskValues READ bitmaskValues NOTIFY bitmaskValuesChanged)
Q_PROPERTY(int decimalPlaces READ decimalPlaces CONSTANT)
Q_PROPERTY(QVariant defaultValue READ cookedDefaultValue CONSTANT)
Q_PROPERTY(QString defaultValueString READ cookedDefaultValueString CONSTANT)
......@@ -74,7 +76,7 @@ public:
/// Convert and validate value
/// @param convertOnly true: validate type conversion only, false: validate against meta data as well
Q_INVOKABLE QString validate(const QString& cookedValue, bool convertOnly);
QVariant cookedValue (void) const; /// Value after translation
QVariant rawValue (void) const { return _rawValue; } /// value prior to translation, careful
int componentId (void) const;
......@@ -83,6 +85,8 @@ public:
QVariant cookedDefaultValue (void) const;
bool defaultValueAvailable (void) const;
QString cookedDefaultValueString(void) const;
QStringList bitmaskStrings (void) const;
QVariantList bitmaskValues (void) const;
int enumIndex (void); // This is not const, since an unknown value can modify the enum lists
QStringList enumStrings (void) const;
QString enumStringValue (void); // This is not const, since an unknown value can modify the enum lists
......@@ -125,6 +129,8 @@ public:
void _setName(const QString& name) { _name = name; }
signals:
void bitmaskStringsChanged(void);
void bitmaskValuesChanged(void);
void enumStringsChanged(void);
void enumValuesChanged(void);
......
import QtQuick 2.5
import QtQuick.Controls 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
Row {
spacing: ScreenTools.defaultFontPixelWidth
property Fact fact: Fact { }
Repeater {
model: fact.bitmaskStrings
QGCCheckBox {
text: modelData
checked: fact.value & fact.bitmaskValues[index]
onClicked: {
if (checked) {
fact.value |= fact.bitmaskValues[index]
} else {
fact.value &= ~fact.bitmaskValues[index]
}
}
}
}
}
......@@ -18,7 +18,7 @@ QGCComboBox {
if (indexModel) {
fact.value = index
} else {
fact.enumIndex = index
fact.value = fact.enumValues[index]
}
}
}
Module QGroundControl.FactControls
FactPanel 1.0 FactPanel.qml
FactLabel 1.0 FactLabel.qml
FactTextField 1.0 FactTextField.qml
FactCheckBox 1.0 FactCheckBox.qml
FactComboBox 1.0 FactComboBox.qml
\ No newline at end of file
FactBitmask 1.0 FactBitmask.qml
FactCheckBox 1.0 FactCheckBox.qml
FactComboBox 1.0 FactComboBox.qml
FactLabel 1.0 FactLabel.qml
FactPanel 1.0 FactPanel.qml
FactTextField 1.0 FactTextField.qml
......@@ -83,6 +83,8 @@ const FactMetaData& FactMetaData::operator=(const FactMetaData& other)
_decimalPlaces = other._decimalPlaces;
_rawDefaultValue = other._rawDefaultValue;
_defaultValueAvailable = other._defaultValueAvailable;
_bitmaskStrings = other._bitmaskStrings;
_bitmaskValues = other._bitmaskValues;
_enumStrings = other._enumStrings;
_enumValues = other._enumValues;
_group = other._group;
......@@ -306,6 +308,24 @@ bool FactMetaData::convertAndValidateCooked(const QVariant& cookedValue, bool co
return convertOk && errorString.isEmpty();
}
void FactMetaData::setBitmaskInfo(const QStringList& strings, const QVariantList& values)
{
if (strings.count() != values.count()) {
qWarning() << "Count mismatch strings:values" << strings.count() << values.count();
return;
}
_bitmaskStrings = strings;
_bitmaskValues = values;
_setBuiltInTranslator();
}
void FactMetaData::addBitmaskInfo(const QString& name, const QVariant& value)
{
_bitmaskStrings << name;
_bitmaskValues << value;
}
void FactMetaData::setEnumInfo(const QStringList& strings, const QVariantList& values)
{
if (strings.count() != values.count()) {
......@@ -318,6 +338,12 @@ void FactMetaData::setEnumInfo(const QStringList& strings, const QVariantList& v
_setBuiltInTranslator();
}
void FactMetaData::addEnumInfo(const QString& name, const QVariant& value)
{
_enumStrings << name;
_enumValues << value;
}
void FactMetaData::setTranslators(Translator rawTranslator, Translator cookedTranslator)
{
_rawTranslator = rawTranslator;
......@@ -342,12 +368,6 @@ void FactMetaData::_setBuiltInTranslator(void)
}
}
void FactMetaData::addEnumInfo(const QString& name, const QVariant& value)
{
_enumStrings << name;
_enumValues << value;
}
QVariant FactMetaData::_degreesToRadians(const QVariant& degrees)
{
return QVariant(degrees.toDouble() * (M_PI / 180.0));
......
......@@ -64,6 +64,8 @@ public:
QVariant rawDefaultValue (void) const;
QVariant cookedDefaultValue (void) const { return _rawTranslator(rawDefaultValue()); }
bool defaultValueAvailable (void) const { return _defaultValueAvailable; }
QStringList bitmaskStrings (void) const { return _bitmaskStrings; }
QVariantList bitmaskValues (void) const { return _bitmaskValues; }
QStringList enumStrings (void) const { return _enumStrings; }
QVariantList enumValues (void) const { return _enumValues; }
QString group (void) const { return _group; }
......@@ -83,11 +85,15 @@ public:
Translator rawTranslator (void) const { return _rawTranslator; }
Translator cookedTranslator (void) const { return _cookedTranslator; }
/// Used to add new values to the bitmask lists after the meta data has been loaded
void addBitmaskInfo(const QString& name, const QVariant& value);
/// Used to add new values to the enum lists after the meta data has been loaded
void addEnumInfo(const QString& name, const QVariant& value);
void setDecimalPlaces (int decimalPlaces) { _decimalPlaces = decimalPlaces; }
void setRawDefaultValue (const QVariant& rawDefaultValue);
void setBitmaskInfo (const QStringList& strings, const QVariantList& values);
void setEnumInfo (const QStringList& strings, const QVariantList& values);
void setGroup (const QString& group) { _group = group; }
void setLongDescription (const QString& longDescription) { _longDescription = longDescription;}
......@@ -128,6 +134,8 @@ private:
int _decimalPlaces;
QVariant _rawDefaultValue;
bool _defaultValueAvailable;
QStringList _bitmaskStrings;
QVariantList _bitmaskValues;
QStringList _enumStrings;
QVariantList _enumValues;
QString _group;
......
......@@ -34,6 +34,7 @@
#include <QDebug>
QGC_LOGGING_CATEGORY(APMParameterMetaDataLog, "APMParameterMetaDataLog")
QGC_LOGGING_CATEGORY(APMParameterMetaDataVerboseLog, "APMParameterMetaDataVerboseLog")
bool APMParameterMetaData::_parameterMetaDataLoaded = false;
QMap<QString, ParameterNametoFactMetaDataMap> APMParameterMetaData::_vehicleTypeToParametersMap;
......@@ -215,7 +216,7 @@ void APMParameterMetaData::_loadParameterFactMetaData()
// so not setting currentCategory
xmlState.push(XmlStateFoundParameters);
} else {
qCDebug(APMParameterMetaDataLog) << "not interested in this block of parameters, skipping:" << nameValue;
qCDebug(APMParameterMetaDataVerboseLog) << "not interested in this block of parameters, skipping:" << nameValue;
if (skipXMLBlock(xml, "parameters")) {
qCWarning(APMParameterMetaDataLog) << "something wrong with the xml, skip of the xml failed";
return;
......@@ -248,7 +249,7 @@ void APMParameterMetaData::_loadParameterFactMetaData()
QString longDescription = xml.attributes().value("docmentation").toString();
QString userLevel = xml.attributes().value("user").toString();
qCDebug(APMParameterMetaDataLog) << "Found parameter name:" << name
qCDebug(APMParameterMetaDataVerboseLog) << "Found parameter name:" << name
<< "short Desc:" << shortDescription
<< "longDescription:" << longDescription
<< "user level: " << userLevel
......@@ -261,7 +262,7 @@ void APMParameterMetaData::_loadParameterFactMetaData()
qCWarning(APMParameterMetaDataLog) << "Duplicate parameter found:" << name;
badMetaData = true;
} else {
qCDebug(APMParameterMetaDataLog) << "inserting metadata for field" << name;
qCDebug(APMParameterMetaDataVerboseLog) << "inserting metadata for field" << name;
_vehicleTypeToParametersMap[currentCategory][name] = rawMetaData;
rawMetaData->name = name;
rawMetaData->group = group;
......@@ -291,17 +292,17 @@ void APMParameterMetaData::_loadParameterFactMetaData()
if (elementName == "param" && xmlState.top() == XmlStateFoundParameter) {
// Done loading this parameter
// Reset for next parameter
qCDebug(APMParameterMetaDataLog) << "done loading parameter";
qCDebug(APMParameterMetaDataVerboseLog) << "done loading parameter";
rawMetaData = NULL;
badMetaData = false;
xmlState.pop();
} else if (elementName == "parameters") {
qCDebug(APMParameterMetaDataLog) << "end of parameters for category: " << currentCategory;
qCDebug(APMParameterMetaDataVerboseLog) << "end of parameters for category: " << currentCategory;
correctGroupMemberships(_vehicleTypeToParametersMap[currentCategory], groupMembers);
groupMembers.clear();
xmlState.pop();
} else if (elementName == "vehicles") {
qCDebug(APMParameterMetaDataLog) << "vehicles end here, libraries will follow";
qCDebug(APMParameterMetaDataVerboseLog) << "vehicles end here, libraries will follow";
xmlState.pop();
}
}
......@@ -345,10 +346,10 @@ bool APMParameterMetaData::parseParameterAttributes(QXmlStreamReader& xml, APMFa
QString range = xml.readElementText().trimmed();
QStringList rangeList = range.split(' ');
if (rangeList.count() != 2) {
qCDebug(APMParameterMetaDataLog) << "space seperator didn't work',trying 'to' separator";
qCDebug(APMParameterMetaDataVerboseLog) << "space seperator didn't work',trying 'to' separator";
rangeList = range.split("to");
if (rangeList.count() != 2) {
qCDebug(APMParameterMetaDataLog) << " 'to' seperaator didn't work', trying '-' as seperator";
qCDebug(APMParameterMetaDataVerboseLog) << " 'to' seperaator didn't work', trying '-' as seperator";
rangeList = range.split('-');
if (rangeList.count() != 2) {
qCDebug(APMParameterMetaDataLog) << "something wrong with range, all three separators have failed" << range;
......@@ -368,24 +369,46 @@ bool APMParameterMetaData::parseParameterAttributes(QXmlStreamReader& xml, APMFa
if(rawMetaData->max.contains(' ')) {
rawMetaData->max = rawMetaData->max.split(' ').first();
}
qCDebug(APMParameterMetaDataLog) << "read field parameter " << "min: " << rawMetaData->min
qCDebug(APMParameterMetaDataVerboseLog) << "read field parameter " << "min: " << rawMetaData->min
<< "max: " << rawMetaData->max;
}
} else if (attributeName == "Increment") {
QString increment = xml.readElementText();
qCDebug(APMParameterMetaDataLog) << "read Increment: " << increment;
qCDebug(APMParameterMetaDataVerboseLog) << "read Increment: " << increment;
rawMetaData->incrementSize = increment;
} else if (attributeName == "Units") {
QString units = xml.readElementText();
qCDebug(APMParameterMetaDataLog) << "read Units: " << units;
qCDebug(APMParameterMetaDataVerboseLog) << "read Units: " << units;
rawMetaData->units = units;
} else if (attributeName == "Bitmask") {
bool parseError = false;
QString bitmaskString = xml.readElementText();
qCDebug(APMParameterMetaDataVerboseLog) << "read Bitmask: " << bitmaskString;
QStringList bitmaskList = bitmaskString.split(",");
if (bitmaskList.count() > 0) {
foreach (const QString& bitmask, bitmaskList) {
QStringList pair = bitmask.split(":");
if (pair.count() == 2) {
rawMetaData->bitmask << QPair<QString, QString>(pair[0], pair[1]);
} else {
qCDebug(APMParameterMetaDataLog) << "parse error: bitmask:" << bitmaskString << "pair count:" << pair.count();
parseError = true;
break;
}
}
}
if (parseError) {
rawMetaData->bitmask.clear();
}
}
} else if (elementName == "values") {
// doing nothing individual value will follow anyway. May be used for sanity checking.
} else if (elementName == "value") {
QString valueValue = xml.attributes().value("code").toString();
QString valueName = xml.readElementText();
qCDebug(APMParameterMetaDataLog) << "read value parameter " << "value desc: "
qCDebug(APMParameterMetaDataVerboseLog) << "read value parameter " << "value desc: "
<< valueName << "code: " << valueValue;
values << QPair<QString,QString>(valueValue, valueName);
rawMetaData->values = values;
......@@ -488,6 +511,45 @@ void APMParameterMetaData::addMetaDataToFact(Fact* fact, MAV_TYPE vehicleType)
}
}
if (rawMetaData->bitmask.count() > 0) {
QStringList bitmaskStrings;
QVariantList bitmaskValues;
for (int i=0; i<rawMetaData->bitmask.count(); i++) {
QVariant bitmaskValue;
QString errorString;
QPair<QString, QString> bitmaskPair = rawMetaData->bitmask[i];
bool ok = false;
unsigned int bitSet = bitmaskPair.first.toUInt(&ok);
bitSet = 1 << bitSet;
if (!ok) {
qCDebug(APMParameterMetaDataLog) << "Invalid bitmask value, name:" << metaData->name()
<< " type:" << metaData->type() << " value:" << bitmaskPair.first
<< " error:" << errorString;
bitmaskStrings.clear();
bitmaskValues.clear();
break;
}
if (metaData->convertAndValidateRaw(bitSet, false /* validate */, bitmaskValue, errorString)) {
bitmaskValues << bitmaskValue;
bitmaskStrings << bitmaskPair.second;
} else {
qCDebug(APMParameterMetaDataLog) << "Invalid bitmask value, name:" << metaData->name()
<< " type:" << metaData->type() << " value:" << bitmaskPair.first
<< " error:" << errorString;
bitmaskStrings.clear();
bitmaskValues.clear();
break;
}
}
if (bitmaskStrings.count() != 0) {
metaData->setBitmaskInfo(bitmaskStrings, bitmaskValues);
}
}
// FixMe:: not handling increment size as their is no place for it in FactMetaData and no ui
fact->setMetaData(metaData);
}
......@@ -46,12 +46,14 @@ public:
QString incrementSize;
QString units;
QList<QPair<QString, QString> > values;
QList<QPair<QString, QString> > bitmask;
};
/// @file
/// @author Don Gagne <don@thegagnes.com>
Q_DECLARE_LOGGING_CATEGORY(APMParameterMetaDataLog)
Q_DECLARE_LOGGING_CATEGORY(APMParameterMetaDataVerboseLog)
/// Collection of Parameter Facts for PX4 AutoPilot
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment