From 88a46f9062e10f983a3dfb30f230a0c712e219bf Mon Sep 17 00:00:00 2001 From: Laura Sebesta Date: Sun, 25 Mar 2012 12:21:58 -0400 Subject: [PATCH] Merge GroundVehicle into latest `next` --- .../src/plugins/config/airframe.ui | 664 +++- .../cfg_vehicletypes/configccpmwidget.cpp | 1810 +++++++++++ .../cfg_vehicletypes/configccpmwidget.h | 160 + .../configfixedwingwidget.cpp | 699 +++++ .../configgroundvehiclewidget.cpp | 751 +++++ .../configmultirotorwidget.cpp | 1195 +++++++ .../src/plugins/config/config.pro | 13 +- .../plugins/config/configairframewidget.cpp | 2221 ------------- .../src/plugins/config/configgadgetwidget.cpp | 4 +- .../config/configvehicletypewidget.cpp | 2751 +++++++++++++++++ ...ramewidget.h => configvehicletypewidget.h} | 43 +- .../uavobjectdefinition/actuatorsettings.xml | 66 +- shared/uavobjectdefinition/systemsettings.xml | 2 +- 13 files changed, 8075 insertions(+), 2304 deletions(-) create mode 100644 ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp create mode 100644 ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.h create mode 100644 ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configfixedwingwidget.cpp create mode 100644 ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configgroundvehiclewidget.cpp create mode 100644 ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configmultirotorwidget.cpp delete mode 100644 ground/openpilotgcs/src/plugins/config/configairframewidget.cpp create mode 100644 ground/openpilotgcs/src/plugins/config/configvehicletypewidget.cpp rename ground/openpilotgcs/src/plugins/config/{configairframewidget.h => configvehicletypewidget.h} (71%) diff --git a/ground/openpilotgcs/src/plugins/config/airframe.ui b/ground/openpilotgcs/src/plugins/config/airframe.ui index 00268ff57..7f61b0fae 100644 --- a/ground/openpilotgcs/src/plugins/config/airframe.ui +++ b/ground/openpilotgcs/src/plugins/config/airframe.ui @@ -173,7 +173,7 @@ QGroupBox::title { - + Select output channel for the engine @@ -193,7 +193,7 @@ QGroupBox::title { - + Select output channel for the first aileron (or elevon) @@ -216,7 +216,7 @@ QGroupBox::title { - + false @@ -239,7 +239,7 @@ QGroupBox::title { - + Select output channel for the first elevator @@ -262,12 +262,12 @@ QGroupBox::title { - + false - Select output channel for a secondry elevator + Select output channel for a secondary elevator @@ -279,7 +279,7 @@ QGroupBox::title { - + Select output channel for the first rudder @@ -293,7 +293,7 @@ QGroupBox::title { - + Select output channel for a secondary rudder @@ -390,7 +390,7 @@ margin:1px; - + 50 @@ -446,7 +446,7 @@ margin:1px; - + 50 @@ -533,6 +533,12 @@ margin:1px; + + + 200 + 16777215 + + Reset @@ -681,7 +687,13 @@ margin:1px; - + + + + 30 + 0 + + 100 @@ -692,6 +704,12 @@ margin:1px; + + + 35 + 0 + + Weight of Roll mixing in percent. Typical values are 100% for + configuration and 50% for X configuration on quads. @@ -729,7 +747,13 @@ margin:1px; - + + + + 0 + 0 + + 100 @@ -740,6 +764,12 @@ margin:1px; + + + 35 + 0 + + Weight of Pitch mixing in percent. Typical values are 100% for + configuration and 50% for X configuration on quads. @@ -777,7 +807,13 @@ margin:1px; - + + + + 0 + 0 + + 50 @@ -788,6 +824,12 @@ margin:1px; + + + 40 + 0 + + Weight of Yaw mixing in percent. Typical value is 50% for + or X configuration on quads. @@ -923,6 +965,12 @@ margin:1px; 0 + + + 200 + 16777215 + + Reset @@ -992,7 +1040,7 @@ margin:1px; - + false @@ -1046,7 +1094,7 @@ margin:1px; 3 - + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); color: rgb(255, 255, 255); @@ -1060,7 +1108,7 @@ margin:1px; - + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -1081,7 +1129,7 @@ margin:1px; - + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -1102,7 +1150,7 @@ margin:1px; - + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -1123,7 +1171,7 @@ margin:1px; - + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -1170,7 +1218,7 @@ margin:1px; - + false @@ -1200,7 +1248,7 @@ margin:1px; - + false @@ -1224,7 +1272,7 @@ margin:1px; - + false @@ -1248,7 +1296,7 @@ margin:1px; - + false @@ -1334,6 +1382,520 @@ margin:1px; + + + true + + + false + + + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Airplane type: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 75 + true + + + + Channel Assignment + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 100 + + + + Output channel asignmets + + + + + + + 77 + 0 + + + + Engine + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Select output channel for the engine + + + + + + + + 60 + 0 + + + + Aileron 1 + + + + + + + Select output channel for the first aileron (or elevon) + + + + + + + false + + + + 60 + 0 + + + + Aileron 2 + + + + + + + false + + + Select output channel for the second aileron (or elevon) + + + + + + + + 0 + 0 + + + + Motor + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Select output channel for the first motor + + + + + + + false + + + + 47 + 0 + + + + Motor 2 + + + + + + + false + + + Select output channel for a second motor + + + + + + + Front Steering + + + + + + + Select output channel for the first steering actuator + + + + + + + Rear Steering + + + + + + + Select output channel for a second steering actuator + + + + + + + + + + true + + + + 0 + 0 + + + + Differential Steering Mix + + + + + + + + + + + 65 + 0 + + + + Left % + + + + + + + 100 + + + 50 + + + Qt::Vertical + + + + + + + 50 + + + + + + + + + + + + 50 + 0 + + + + Right % + + + + + + + 100 + + + 50 + + + Qt::Vertical + + + + + + + 50 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 100 + + + + Front throttle curve + + + + + + + 0 + 0 + + + + + 100 + 100 + + + + + 200 + 200 + + + + + 10 + 10 + + + + + + + + + 200 + 16777215 + + + + Reset + + + + + + + Val: 0.00 + + + + + + + + + + Rear throttle curve + + + + + + + 0 + 0 + + + + + 100 + 100 + + + + + 200 + 200 + + + + + + + + Reset + + + + + + + Val: 0.00 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 75 + true + + + + Mixer OK + + + + + + + + + @@ -1990,7 +2552,7 @@ margin:1px; - + 30 @@ -2095,7 +2657,7 @@ Do it after accel time is setup. - + 1000 @@ -2329,7 +2891,7 @@ p, li { white-space: pre-wrap; } ConfigccpmWidget QWidget -
configccpmwidget.h
+
cfg_vehicletypes/configccpmwidget.h
1
@@ -2340,7 +2902,7 @@ p, li { white-space: pre-wrap; } feedForwardSlider valueChanged(int) - feedForwardValue + feedForwardSliderValue setNum(int) @@ -2356,7 +2918,7 @@ p, li { white-space: pre-wrap; } maxAccelSlider valueChanged(int) - label_33 + maxAccelSliderValue setNum(int) @@ -2372,7 +2934,7 @@ p, li { white-space: pre-wrap; } elevonSlider1 valueChanged(int) - label_18 + elevonSliderLabel1 setNum(int) @@ -2388,12 +2950,12 @@ p, li { white-space: pre-wrap; } elevonSlider2 valueChanged(int) - label_25 + elevonSliderLabel2 setNum(int) - 124 - 126 + 362 + 299 124 @@ -2401,10 +2963,42 @@ p, li { white-space: pre-wrap; } + + differentialSteeringSlider1 + valueChanged(int) + gvDiffSteering1Label + setNum(int) + + + 124 + 126 + + + 315 + 391 + + + + + differentialSteeringSlider2 + valueChanged(int) + gvDiffSteering2Label + setNum(int) + + + 124 + 126 + + + 390 + 391 + + + mrPitchMixLevel valueChanged(int) - label_44 + mrPitchMixValue setNum(int) @@ -2420,7 +3014,7 @@ p, li { white-space: pre-wrap; } mrRollMixLevel valueChanged(int) - label_43 + mrRollMixValue setNum(int) @@ -2436,7 +3030,7 @@ p, li { white-space: pre-wrap; } mrYawMixLevel valueChanged(int) - label_45 + mrYawMixValue setNum(int) diff --git a/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp new file mode 100644 index 000000000..6d7a974c2 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp @@ -0,0 +1,1810 @@ +/** + ****************************************************************************** + * + * @file configccpmwidget.cpp + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief ccpm configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "configccpmwidget.h" +#include "mixersettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mixersettings.h" +#include "systemsettings.h" +#include "actuatorcommand.h" + +#define Pi 3.14159265358979323846 + + +ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) +{ + int i; + + m_ccpm = new Ui_ccpmWidget(); + m_ccpm->setupUi(this); + SwashLvlConfigurationInProgress=0; + SwashLvlState=0; + SwashLvlServoInterlock=0; + updatingFromHardware=FALSE; + updatingToHardware=FALSE; + + // Now connect the widget to the ManualControlCommand / Channel UAVObject + //ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + //UAVObjectManager *objManager = pm->getObject(); + + // Initialization of the swashplaye widget + m_ccpm->SwashplateImage->setScene(new QGraphicsScene(this)); + + m_ccpm->SwashLvlSwashplateImage->setScene(m_ccpm->SwashplateImage->scene()); + m_ccpm->SwashLvlSwashplateImage->setSceneRect(-50,-50,500,500); + //m_ccpm->SwashLvlSwashplateImage->scale(.85,.85); + + //m_ccpm->SwashplateImage->setSceneRect(SwashplateImg->boundingRect()); + m_ccpm->SwashplateImage->setSceneRect(-50,-30,500,500); + //m_ccpm->SwashplateImage->scale(.85,.85); + + QSvgRenderer *renderer = new QSvgRenderer(); + renderer->load(QString(":/configgadget/images/ccpm_setup.svg")); + + + SwashplateImg = new QGraphicsSvgItem(); + SwashplateImg->setSharedRenderer(renderer); + SwashplateImg->setElementId("Swashplate"); + SwashplateImg->setObjectName("Swashplate"); + //SwashplateImg->setScale(0.75); + m_ccpm->SwashplateImage->scene()->addItem(SwashplateImg); + + QFont serifFont("Times", 24, QFont::Bold); + QPen pen; // creates a default pen + + pen.setStyle(Qt::DotLine); + pen.setWidth(2); + pen.setBrush(Qt::gray); + pen.setCapStyle(Qt::RoundCap); + pen.setJoinStyle(Qt::RoundJoin); + + + QBrush brush(Qt::darkBlue); + QPen pen2; // creates a default pen + + //pen2.setStyle(Qt::DotLine); + pen2.setWidth(1); + pen2.setBrush(Qt::blue); + //pen2.setCapStyle(Qt::RoundCap); + //pen2.setJoinStyle(Qt::RoundJoin); + + + //brush.setStyle(Qt::RadialGradientPattern); + + QList ServoNames; + ServoNames << "ServoW" << "ServoX" << "ServoY" << "ServoZ" ; + + for (i=0;iSwashLvlSwashplateImage->scene()->addLine(0,0,100*i,i*i*100,pen); + + Servos[i] = new QGraphicsSvgItem(); + Servos[i]->setSharedRenderer(renderer); + Servos[i]->setElementId(ServoNames.at(i)); + m_ccpm->SwashplateImage->scene()->addItem(Servos[i]); + + ServosText[i] = new QGraphicsTextItem(); + ServosText[i]->setDefaultTextColor(Qt::yellow); + ServosText[i]->setPlainText(QString("-")); + ServosText[i]->setFont(serifFont); + + ServosTextCircles[i] = new QGraphicsEllipseItem(1,1,30,30); + ServosTextCircles[i]->setBrush(brush); + ServosTextCircles[i]->setPen(pen2); + m_ccpm->SwashplateImage->scene()->addItem(ServosTextCircles[i]); + m_ccpm->SwashplateImage->scene()->addItem(ServosText[i]); + + + + SwashLvlSpinBoxes[i] = new QSpinBox(m_ccpm->SwashLvlSwashplateImage); // use QGraphicsView + m_ccpm->SwashLvlSwashplateImage->scene()->addWidget(SwashLvlSpinBoxes[i]); + SwashLvlSpinBoxes[i]->setMaximum(10000); + SwashLvlSpinBoxes[i]->setMinimum(0); + SwashLvlSpinBoxes[i]->setValue(0); + + } + + m_ccpm->PitchCurve->setMin(-1); + + resetMixer(m_ccpm->PitchCurve, 5); + resetMixer(m_ccpm->ThrottleCurve, 5); + + MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); + Q_ASSERT(mixerSettings); + UAVObjectField * curve2source = mixerSettings->getField("Curve2Source"); + Q_ASSERT(curve2source); + + QStringList channels; + channels << "Channel1" << "Channel2" << "Channel3" << "Channel4" << + "Channel5" << "Channel6" << "Channel7" << "Channel8" << "None"; + m_ccpm->ccpmEngineChannel->addItems(channels); + m_ccpm->ccpmEngineChannel->setCurrentIndex(8); + m_ccpm->ccpmTailChannel->addItems(channels); + m_ccpm->ccpmTailChannel->setCurrentIndex(8); + m_ccpm->ccpmServoWChannel->addItems(channels); + m_ccpm->ccpmServoWChannel->setCurrentIndex(8); + m_ccpm->ccpmServoXChannel->addItems(channels); + m_ccpm->ccpmServoXChannel->setCurrentIndex(8); + m_ccpm->ccpmServoYChannel->addItems(channels); + m_ccpm->ccpmServoYChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->addItems(channels); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + + QStringList Types; + Types << QString::fromUtf8("CCPM 2 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 90º") << + QString::fromUtf8("CCPM 4 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 120º") << + QString::fromUtf8("CCPM 3 Servo 140º") << QString::fromUtf8("FP 2 Servo 90º") << + QString::fromUtf8("Custom - User Angles") << QString::fromUtf8("Custom - Advanced Settings"); + m_ccpm->ccpmType->addItems(Types); + m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1); + requestccpmUpdate(); + UpdateCurveSettings(); + + //disable changing number of points in curves until UAVObjects have more than 5 + m_ccpm->NumCurvePoints->setEnabled(0); + + UpdateType(); + + //connect(m_ccpm->saveccpmToSD, SIGNAL(clicked()), this, SLOT(saveccpmUpdate())); + //connect(m_ccpm->saveccpmToRAM, SIGNAL(clicked()), this, SLOT(sendccpmUpdate())); + //connect(m_ccpm->getccpmCurrent, SIGNAL(clicked()), this, SLOT(requestccpmUpdate())); + connect(m_ccpm->ccpmGenerateCurve, SIGNAL(clicked()), this, SLOT(GenerateCurve())); + connect(m_ccpm->NumCurvePoints, SIGNAL(valueChanged(int)), this, SLOT(UpdateCurveSettings())); + connect(m_ccpm->CurveToGenerate, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings())); + connect(m_ccpm->CurveType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings())); + connect(m_ccpm->ccpmAngleW, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmAngleX, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmAngleY, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmAngleZ, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmCorrectionAngle, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmServoWChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmServoXChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmServoYChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmServoZChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); + connect(m_ccpm->ccpmEngineChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer())); + connect(m_ccpm->ccpmTailChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer())); + connect(m_ccpm->ccpmRevoSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); + connect(m_ccpm->ccpmREVOspinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); + connect(m_ccpm->ccpmCollectiveSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); + connect(m_ccpm->ccpmCollectivespinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); + connect(m_ccpm->ccpmType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType())); + connect(m_ccpm->ccpmSingleServo, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType())); + connect(m_ccpm->CurveSettings, SIGNAL(cellChanged (int, int)), this, SLOT(UpdateCurveWidgets())); + connect(m_ccpm->TabObject, SIGNAL(currentChanged ( QWidget * )), this, SLOT(UpdateType())); + +// connect(m_ccpm->SwashLvlSwashplateImage, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateRedraw())); + + + connect(m_ccpm->PitchCurve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updatePitchCurveValue(QList,double))); + connect(m_ccpm->ThrottleCurve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateThrottleCurveValue(QList,double))); + + connect(m_ccpm->SwashLvlStartButton, SIGNAL(clicked()), this, SLOT(SwashLvlStartButtonPressed())); + connect(m_ccpm->SwashLvlNextButton, SIGNAL(clicked()), this, SLOT(SwashLvlNextButtonPressed())); + connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed())); + connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed())); + + connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); + connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); + + + + ccpmSwashplateRedraw(); +} + +ConfigccpmWidget::~ConfigccpmWidget() +{ + // Do nothing +} + +void ConfigccpmWidget::UpdateType() +{ + int TypeInt,SingleServoIndex,NumServosDefined; + QString TypeText; + double AdjustmentAngle=0; + + UpdateCCPMOptionsFromUI(); + SetUIComponentVisibilities(); + + TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; + TypeText = m_ccpm->ccpmType->currentText(); + SingleServoIndex = m_ccpm->ccpmSingleServo->currentIndex(); + + //set visibility of user settings + m_ccpm->ccpmAdvancedSettingsTable->setEnabled(TypeInt==0); + m_ccpm->ccpmAdvancedSettingsTable->clearFocus();; + + m_ccpm->ccpmAngleW->setEnabled(TypeInt==1); + m_ccpm->ccpmAngleX->setEnabled(TypeInt==1); + m_ccpm->ccpmAngleY->setEnabled(TypeInt==1); + m_ccpm->ccpmAngleZ->setEnabled(TypeInt==1); + m_ccpm->ccpmCorrectionAngle->setEnabled(TypeInt!=0); + + m_ccpm->ccpmServoWChannel->setEnabled(TypeInt>0); + m_ccpm->ccpmServoXChannel->setEnabled(TypeInt>0); + m_ccpm->ccpmServoYChannel->setEnabled(TypeInt>0); + m_ccpm->ccpmServoZChannel->setEnabled(TypeInt>0); + m_ccpm->ccpmSingleServo->setEnabled(TypeInt>1); + + m_ccpm->ccpmEngineChannel->setEnabled(TypeInt>0); + m_ccpm->ccpmTailChannel->setEnabled(TypeInt>0); + m_ccpm->ccpmCollectiveSlider->setEnabled(TypeInt>0); + m_ccpm->ccpmCollectivespinBox->setEnabled(TypeInt>0); + m_ccpm->ccpmRevoSlider->setEnabled(TypeInt>0); + m_ccpm->ccpmREVOspinBox->setEnabled(TypeInt>0); + + AdjustmentAngle=SingleServoIndex*90; + + m_ccpm->CurveToGenerate->setEnabled(1); + m_ccpm->CurveSettings->setColumnHidden(1,0); + m_ccpm->PitchCurve->setVisible(1); + //m_ccpm->customThrottleCurve2Value->setVisible(1); + //m_ccpm->label_41->setVisible(1); + + NumServosDefined=4; + //set values for pre defined heli types + if (TypeText.compare(QString::fromUtf8("CCPM 2 Servo 90º"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); + m_ccpm->ccpmAngleY->setValue(0); + m_ccpm->ccpmAngleZ->setValue(0); + m_ccpm->ccpmAngleY->setEnabled(0); + m_ccpm->ccpmAngleZ->setEnabled(0); + m_ccpm->ccpmServoYChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + m_ccpm->ccpmServoYChannel->setEnabled(0); + m_ccpm->ccpmServoZChannel->setEnabled(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=2; + + } + if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 90º"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); + m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360)); + m_ccpm->ccpmAngleZ->setValue(0); + m_ccpm->ccpmAngleZ->setEnabled(0); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->setEnabled(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=3; + + } + if (TypeText.compare(QString::fromUtf8("CCPM 4 Servo 90º"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); + m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360)); + m_ccpm->ccpmAngleZ->setValue(fmod(AdjustmentAngle + 270,360)); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + m_ccpm->ccpmSingleServo->setEnabled(0); + m_ccpm->ccpmSingleServo->setCurrentIndex(0); + NumServosDefined=4; + + } + if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 120º"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 120,360)); + m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 240,360)); + m_ccpm->ccpmAngleZ->setValue(0); + m_ccpm->ccpmAngleZ->setEnabled(0); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->setEnabled(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=3; + + } + if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 140º"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 140,360)); + m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 220,360)); + m_ccpm->ccpmAngleZ->setValue(0); + m_ccpm->ccpmAngleZ->setEnabled(0); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->setEnabled(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=3; + + } + if (TypeText.compare(QString::fromUtf8("FP 2 Servo 90º"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); + m_ccpm->ccpmAngleY->setValue(0); + m_ccpm->ccpmAngleZ->setValue(0); + m_ccpm->ccpmAngleY->setEnabled(0); + m_ccpm->ccpmAngleZ->setEnabled(0); + m_ccpm->ccpmServoYChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + m_ccpm->ccpmServoYChannel->setEnabled(0); + m_ccpm->ccpmServoZChannel->setEnabled(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + + m_ccpm->ccpmCollectivespinBox->setEnabled(0); + m_ccpm->ccpmCollectiveSlider->setEnabled(0); + m_ccpm->ccpmCollectivespinBox->setValue(0); + m_ccpm->ccpmCollectiveSlider->setValue(0); + m_ccpm->CurveToGenerate->setCurrentIndex(0); + m_ccpm->CurveToGenerate->setEnabled(0); + m_ccpm->CurveSettings->setColumnHidden(1,1); + m_ccpm->PitchCurve->setVisible(0); + //m_ccpm->customThrottleCurve2Value->setVisible(0); + //m_ccpm->label_41->setVisible(0); + NumServosDefined=2; + } + + //set the visibility of the swashplate servo selection boxes + m_ccpm->ccpmServoWLabel->setVisible(NumServosDefined>=1); + m_ccpm->ccpmServoXLabel->setVisible(NumServosDefined>=2); + m_ccpm->ccpmServoYLabel->setVisible(NumServosDefined>=3); + m_ccpm->ccpmServoZLabel->setVisible(NumServosDefined>=4); + m_ccpm->ccpmServoWChannel->setVisible(NumServosDefined>=1); + m_ccpm->ccpmServoXChannel->setVisible(NumServosDefined>=2); + m_ccpm->ccpmServoYChannel->setVisible(NumServosDefined>=3); + m_ccpm->ccpmServoZChannel->setVisible(NumServosDefined>=4); + + //set the visibility of the swashplate angle selection boxes + m_ccpm->ccpmServoWLabel_2->setVisible(NumServosDefined>=1); + m_ccpm->ccpmServoXLabel_2->setVisible(NumServosDefined>=2); + m_ccpm->ccpmServoYLabel_2->setVisible(NumServosDefined>=3); + m_ccpm->ccpmServoZLabel_2->setVisible(NumServosDefined>=4); + m_ccpm->ccpmAngleW->setVisible(NumServosDefined>=1); + m_ccpm->ccpmAngleX->setVisible(NumServosDefined>=2); + m_ccpm->ccpmAngleY->setVisible(NumServosDefined>=3); + m_ccpm->ccpmAngleZ->setVisible(NumServosDefined>=4); + + + m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); + for (int i=0;i<6;i++) { + m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- + m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); + } + + + + + //update UI + ccpmSwashplateUpdate(); + +} + +/** + Resets a mixer curve + */ +void ConfigccpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements) +{ + mixer->initLinearCurve(numElements,(double)1); +} + +void ConfigccpmWidget::UpdateCurveWidgets() +{ + int NumCurvePoints,i,Changed; + QList curveValues; + QList OldCurveValues; + double ThisValue; + //get the user settings + NumCurvePoints=m_ccpm->NumCurvePoints->value(); + + curveValues.clear(); + Changed=0; + OldCurveValues=m_ccpm->ThrottleCurve->getCurve(); + for (i=0; iCurveSettings->item(i, 0 )->text().toDouble(); + curveValues.append(ThisValue); + if (ThisValue!=OldCurveValues.at(i))Changed=1; + } + // Setup all Throttle1 curves for all types of airframes + if (Changed==1)m_ccpm->ThrottleCurve->setCurve(curveValues); + + curveValues.clear(); + Changed=0; + OldCurveValues=m_ccpm->PitchCurve->getCurve(); + for (i=0; iCurveSettings->item(i, 1 )->text().toDouble(); + curveValues.append(ThisValue); + if (ThisValue!=OldCurveValues.at(i))Changed=1; + } + // Setup all Throttle1 curves for all types of airframes + if (Changed==1)m_ccpm->PitchCurve->setCurve(curveValues); +} + +void ConfigccpmWidget::updatePitchCurveValue(QList curveValues0,double Value0) +{ + Q_UNUSED(curveValues0); + Q_UNUSED(Value0); + + int NumCurvePoints,i; + double CurrentValue; + QList internalCurveValues; + //get the user settings + NumCurvePoints=m_ccpm->NumCurvePoints->value(); + internalCurveValues=m_ccpm->PitchCurve->getCurve(); + + for (i=0; iCurveSettings->item(i, 1 )->text().toDouble(); + if (CurrentValue!=internalCurveValues[i]) + { + m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",internalCurveValues.at(i))); + } + + } + +} + +void ConfigccpmWidget::updateThrottleCurveValue(QList curveValues0,double Value0) +{ + Q_UNUSED(curveValues0); + Q_UNUSED(Value0); + + int NumCurvePoints,i; + double CurrentValue; + QList internalCurveValues; + //get the user settings + NumCurvePoints=m_ccpm->NumCurvePoints->value(); + internalCurveValues=m_ccpm->ThrottleCurve->getCurve(); + + for (i=0; iCurveSettings->item(i, 1 )->text().toDouble(); + if (CurrentValue!=internalCurveValues[i]) + { + m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",internalCurveValues.at(i))); + } + + } + +} + + +void ConfigccpmWidget::UpdateCurveSettings() +{ + int NumCurvePoints,i; + double scale; + QString CurveType; + QStringList vertHeaders; + + //get the user settings + NumCurvePoints=m_ccpm->NumCurvePoints->value(); + CurveType=m_ccpm->CurveType->currentText(); + + vertHeaders << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" ; + for (i=0;iCurveSettings->setVerticalHeaderLabels( vertHeaders ); + + if (m_ccpm->CurveToGenerate->currentIndex()==0) + { + m_ccpm->CurveValue1->setMinimum(0.0); + m_ccpm->CurveValue2->setMinimum(0.0); + m_ccpm->CurveValue3->setMinimum(0.0); + } + else + { + m_ccpm->CurveValue1->setMinimum(-1.0); + m_ccpm->CurveValue2->setMinimum(-1.0); + m_ccpm->CurveValue3->setMinimum(0.0); + } + m_ccpm->CurveValue1->setMaximum(1.0); + m_ccpm->CurveValue2->setMaximum(1.0); + m_ccpm->CurveValue3->setMaximum(100.0); + m_ccpm->CurveValue1->setSingleStep(0.1); + m_ccpm->CurveValue2->setSingleStep(0.1); + m_ccpm->CurveValue3->setSingleStep(1.0); + m_ccpm->CurveValue1->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);; + m_ccpm->CurveValue2->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue); + m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue); + + if ( CurveType.compare("Flat")==0) + { + m_ccpm->CurveLabel1->setText("Value"); + m_ccpm->CurveLabel1->setVisible(true); + m_ccpm->CurveValue1->setVisible(true); + m_ccpm->CurveLabel2->setVisible(false); + m_ccpm->CurveValue2->setVisible(false); + m_ccpm->CurveLabel3->setVisible(false); + m_ccpm->CurveValue3->setVisible(false); + m_ccpm->ccpmGenerateCurve->setVisible(true); + m_ccpm->CurveToGenerate->setVisible(true); + } + if ( CurveType.compare("Linear")==0) + { + m_ccpm->CurveLabel1->setText("Min"); + m_ccpm->CurveLabel1->setVisible(true); + m_ccpm->CurveValue1->setVisible(true); + m_ccpm->CurveLabel2->setText("Max"); + m_ccpm->CurveLabel2->setVisible(true); + m_ccpm->CurveValue2->setVisible(true); + m_ccpm->CurveLabel3->setVisible(false); + m_ccpm->CurveValue3->setVisible(false); + m_ccpm->ccpmGenerateCurve->setVisible(true); + m_ccpm->CurveToGenerate->setVisible(true); + } + if ( CurveType.compare("Step")==0) + { + m_ccpm->CurveLabel1->setText("Min"); + m_ccpm->CurveLabel1->setVisible(true); + m_ccpm->CurveValue1->setVisible(true); + m_ccpm->CurveLabel2->setText("Max"); + m_ccpm->CurveLabel2->setVisible(true); + m_ccpm->CurveValue2->setVisible(true); + m_ccpm->CurveLabel3->setText("Step at"); + m_ccpm->CurveLabel3->setVisible(true); + m_ccpm->CurveValue3->setVisible(true); + m_ccpm->ccpmGenerateCurve->setVisible(true); + m_ccpm->CurveToGenerate->setVisible(true); + } + if ( CurveType.compare("Exp")==0) + { + m_ccpm->CurveLabel1->setText("Min"); + m_ccpm->CurveLabel1->setVisible(true); + m_ccpm->CurveValue1->setVisible(true); + m_ccpm->CurveLabel2->setText("Max"); + m_ccpm->CurveLabel2->setVisible(true); + m_ccpm->CurveValue2->setVisible(true); + m_ccpm->CurveLabel3->setText("Strength"); + m_ccpm->CurveLabel3->setVisible(true); + m_ccpm->CurveValue3->setVisible(true); + m_ccpm->CurveValue3->setMinimum(1.0); + m_ccpm->CurveValue3->setMaximum(100.0); + m_ccpm->CurveValue3->setSingleStep(1.0); + m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);; + m_ccpm->ccpmGenerateCurve->setVisible(true); + m_ccpm->CurveToGenerate->setVisible(true); + } + if ( CurveType.compare("Log")==0) + { + m_ccpm->CurveLabel1->setText("Min"); + m_ccpm->CurveLabel1->setVisible(true); + m_ccpm->CurveValue1->setVisible(true); + m_ccpm->CurveLabel2->setText("Max"); + m_ccpm->CurveLabel2->setVisible(true); + m_ccpm->CurveValue2->setVisible(true); + m_ccpm->CurveLabel3->setText("Strength"); + m_ccpm->CurveLabel3->setVisible(true); + m_ccpm->CurveValue3->setVisible(true); + m_ccpm->CurveValue3->setMinimum(1.0); + m_ccpm->CurveValue3->setMaximum(100.0); + m_ccpm->CurveValue3->setSingleStep(1.0); + m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);; + m_ccpm->ccpmGenerateCurve->setVisible(true); + m_ccpm->CurveToGenerate->setVisible(true); + } + if ( CurveType.compare("Custom")==0) + { + m_ccpm->CurveLabel1->setVisible(false); + m_ccpm->CurveValue1->setVisible(false); + m_ccpm->CurveLabel2->setVisible(false); + m_ccpm->CurveValue2->setVisible(false); + m_ccpm->CurveLabel3->setVisible(false); + m_ccpm->CurveValue3->setVisible(false); + m_ccpm->ccpmGenerateCurve->setVisible(false); + m_ccpm->CurveToGenerate->setVisible(false); + } +UpdateCurveWidgets(); + +} +void ConfigccpmWidget::GenerateCurve() +{ + int NumCurvePoints,CurveToGenerate,i; + double value1, value2, value3, scale; + QString CurveType; + QTableWidgetItem *item; + double newValue; + + + //get the user settings + NumCurvePoints=m_ccpm->NumCurvePoints->value(); + value1=m_ccpm->CurveValue1->value(); + value2=m_ccpm->CurveValue2->value(); + value3=m_ccpm->CurveValue3->value(); + CurveToGenerate=m_ccpm->CurveToGenerate->currentIndex(); + CurveType=m_ccpm->CurveType->currentText(); + + + + for (i=0;iCurveSettings->item(i, CurveToGenerate ); + + if ( CurveType.compare("Flat")==0) + { + //item->setText( tr( "%1" ).arg( value1 ) ); + item->setText(QString().sprintf("%.3f",value1)); + } + if ( CurveType.compare("Linear")==0) + { + newValue =value1 +(scale*(value2-value1)); + //item->setText( tr( "%1" ).arg(value1 +(scale*(value2-value1))) ); + item->setText(QString().sprintf("%.3f",newValue)); + } + if ( CurveType.compare("Step")==0) + { + if (scale*100setText( tr( "%1" ).arg(value1) ); + item->setText(QString().sprintf("%.3f",value1)); + } + else + { + //item->setText( tr( "%1" ).arg(value2) ); + item->setText(QString().sprintf("%.3f",value2)); + } + } + if ( CurveType.compare("Exp")==0) + { + newValue =value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1)); + //item->setText( tr( "%1" ).arg(value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1))) ); + item->setText(QString().sprintf("%.3f",newValue)); + } + if ( CurveType.compare("Log")==0) + { + newValue = value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1)); + //item->setText( tr( "%1" ).arg(value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1))) ); + item->setText(QString().sprintf("%.3f",newValue)); + } + } + for (i=NumCurvePoints;i<10;i++) + { + item =m_ccpm->CurveSettings->item(i, CurveToGenerate ); + item->setText( tr( "" ) ); + } + UpdateCurveWidgets(); + +} + +void ConfigccpmWidget::ccpmSwashplateRedraw() +{ + double angle[CCPM_MAX_SWASH_SERVOS],CorrectionAngle,x,y,w,h,radius,CenterX,CenterY; + int used[CCPM_MAX_SWASH_SERVOS],defined[CCPM_MAX_SWASH_SERVOS],i; + QRectF bounds; + QRect size; + double scale,xscale,yscale; + + + size = m_ccpm->SwashplateImage->rect(); + xscale=size.width(); + yscale=size.height(); + scale=xscale; + if (yscaleSwashplateImage->resetTransform (); + m_ccpm->SwashplateImage->scale(scale,scale); + + size = m_ccpm->SwashLvlSwashplateImage->rect(); + xscale=size.width(); + yscale=size.height(); + scale=xscale; + if (yscaleSwashLvlSwashplateImage->resetTransform (); + m_ccpm->SwashLvlSwashplateImage->scale(scale,scale); + + CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value(); + + CenterX=200; + CenterY=200; + + bounds=SwashplateImg->boundingRect(); + + SwashplateImg->setPos(CenterX-bounds.width()/2,CenterY-bounds.height()/2); + + defined[0]=(m_ccpm->ccpmServoWChannel->isEnabled()); + defined[1]=(m_ccpm->ccpmServoXChannel->isEnabled()); + defined[2]=(m_ccpm->ccpmServoYChannel->isEnabled()); + defined[3]=(m_ccpm->ccpmServoZChannel->isEnabled()); + used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled())); + used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled())); + used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled())); + used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled())); + angle[0]=(CorrectionAngle+180+m_ccpm->ccpmAngleW->value())*Pi/180.00; + angle[1]=(CorrectionAngle+180+m_ccpm->ccpmAngleX->value())*Pi/180.00; + angle[2]=(CorrectionAngle+180+m_ccpm->ccpmAngleY->value())*Pi/180.00; + angle[3]=(CorrectionAngle+180+m_ccpm->ccpmAngleZ->value())*Pi/180.00; + + + for (i=0;isetPos(x, y); + Servos[i]->setVisible(used[i]!=0); + + radius=150; + bounds=ServosText[i]->boundingRect(); + x=CenterX-(radius*sin(angle[i]))-bounds.width()/2; + y=CenterY+(radius*cos(angle[i]))-bounds.height()/2; + + ServosText[i]->setPos(x, y); + ServosText[i]->setVisible(used[i]!=0); + + if (bounds.width()>bounds.height()) + { + bounds.setHeight(bounds.width()); + } + else + { + bounds.setWidth(bounds.height()); + } + x=CenterX-(radius*sin(angle[i]))-bounds.width()/2; + y=CenterY+(radius*cos(angle[i]))-bounds.height()/2; + + ServosTextCircles[i]->setRect(bounds); + ServosTextCircles[i]->setPos(x, y); + ServosTextCircles[i]->setVisible(used[i]!=0); + + w=SwashLvlSpinBoxes[i]->width()/2; + h=SwashLvlSpinBoxes[i]->height()/2; + radius = (215.00+w+h); + x=CenterX-(radius*sin(angle[i]))-w; + y=CenterY+(radius*cos(angle[i]))-h; + SwashLvlSpinBoxes[i]->move(m_ccpm->SwashLvlSwashplateImage->mapFromScene (x, y)); + SwashLvlSpinBoxes[i]->setVisible(used[i]!=0); + + radius=220; + x=CenterX-(radius*sin(angle[i])); + y=CenterY+(radius*cos(angle[i])); + ServoLines[i]->setLine(CenterX,CenterY,x,y); + ServoLines[i]->setVisible(defined[i]!=0); + } + + //m_ccpm->SwashplateImage->centerOn (CenterX, CenterY); + + //m_ccpm->SwashplateImage->fitInView(SwashplateImg, Qt::KeepAspectRatio); +} + +void ConfigccpmWidget::ccpmSwashplateUpdate() +{ + ccpmSwashplateRedraw(); + SetUIComponentVisibilities(); + UpdateMixer(); +} + +void ConfigccpmWidget::ccpmChannelCheck() +{ + if((m_ccpm->ccpmServoWChannel->currentIndex()==8)&&(m_ccpm->ccpmServoWChannel->isEnabled())) + { + m_ccpm->ccpmServoWLabel->setText("Servo W"); + } + else + { + m_ccpm->ccpmServoWLabel->setText("Servo W"); + } + if((m_ccpm->ccpmServoXChannel->currentIndex()==8)&&(m_ccpm->ccpmServoXChannel->isEnabled())) + { + m_ccpm->ccpmServoXLabel->setText("Servo X"); + } + else + { + m_ccpm->ccpmServoXLabel->setText("Servo X"); + } + if((m_ccpm->ccpmServoYChannel->currentIndex()==8)&&(m_ccpm->ccpmServoYChannel->isEnabled())) + { + m_ccpm->ccpmServoYLabel->setText("Servo Y"); + } + else + { + m_ccpm->ccpmServoYLabel->setText("Servo Y"); + } + if((m_ccpm->ccpmServoZChannel->currentIndex()==8)&&(m_ccpm->ccpmServoZChannel->isEnabled())) + { + m_ccpm->ccpmServoZLabel->setText("Servo Z"); + } + else + { + m_ccpm->ccpmServoZLabel->setText("Servo Z"); + } + + if((m_ccpm->ccpmEngineChannel->currentIndex()==8)&&(m_ccpm->ccpmEngineChannel->isEnabled())) + { + m_ccpm->ccpmEngineLabel->setText("Engine"); + } + else + { + m_ccpm->ccpmEngineLabel->setText("Engine"); + } + + if((m_ccpm->ccpmTailChannel->currentIndex()==8)&&(m_ccpm->ccpmTailChannel->isEnabled())) + { + m_ccpm->ccpmTailLabel->setText("Tail Rotor"); + } + else + { + m_ccpm->ccpmTailLabel->setText("Tail Rotor"); + } + +} + +void ConfigccpmWidget::UpdateMixer() +{ + bool useCCPM; + bool useCyclic; + int i,j,ThisEnable[6]; + float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6]; + QString Channel; + + ccpmChannelCheck(); + UpdateCCPMOptionsFromUI(); + + useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState); + useCyclic = GUIConfigData.heli.ccpmLinkRollState; + + CollectiveConstant = (float)GUIConfigData.heli.SliderValue0 / 100.00; + + if (useCCPM) + {//cyclic = 1 - collective + PitchConstant = 1-CollectiveConstant; + RollConstant = PitchConstant; + } + else + { + PitchConstant = (float)GUIConfigData.heli.SliderValue1 / 100.00;; + if (useCyclic) + { + RollConstant = PitchConstant; + } + else + { + RollConstant = (float)GUIConfigData.heli.SliderValue2 / 100.00;; + } + } + + if (GUIConfigData.heli.SwasplateType>0) + {//not advanced settings + //get the channel data from the ui + MixerChannelData[0] = m_ccpm->ccpmEngineChannel->currentIndex(); + MixerChannelData[1] = m_ccpm->ccpmTailChannel->currentIndex(); + MixerChannelData[2] = m_ccpm->ccpmServoWChannel->currentIndex(); + MixerChannelData[3] = m_ccpm->ccpmServoXChannel->currentIndex(); + MixerChannelData[4] = m_ccpm->ccpmServoYChannel->currentIndex(); + MixerChannelData[5] = m_ccpm->ccpmServoZChannel->currentIndex(); + + //get the angle data from the ui + ThisAngle[2] = m_ccpm->ccpmAngleW->value(); + ThisAngle[3] = m_ccpm->ccpmAngleX->value(); + ThisAngle[4] = m_ccpm->ccpmAngleY->value(); + ThisAngle[5] = m_ccpm->ccpmAngleZ->value(); + + //get the angle data from the ui + ThisEnable[2] = m_ccpm->ccpmServoWChannel->isEnabled(); + ThisEnable[3] = m_ccpm->ccpmServoXChannel->isEnabled(); + ThisEnable[4] = m_ccpm->ccpmServoYChannel->isEnabled(); + ThisEnable[5] = m_ccpm->ccpmServoZChannel->isEnabled(); + + ServosText[0]->setPlainText(QString("%1").arg( MixerChannelData[2]+1 )); + ServosText[1]->setPlainText(QString("%1").arg( MixerChannelData[3]+1 )); + ServosText[2]->setPlainText(QString("%1").arg( MixerChannelData[4]+1 )); + ServosText[3]->setPlainText(QString("%1").arg( MixerChannelData[5]+1 )); + + + //go through the user data and update the mixer matrix + for (i=0;i<6;i++) + { + if ((MixerChannelData[i]<8)&&((ThisEnable[i])||(i<2))) + { + m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->setText(QString("%1").arg( MixerChannelData[i]+1 )); + //config the vector + if (i==0) + {//motor-engine + m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(127));//ThrottleCurve1 + m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg(0));//ThrottleCurve2 + m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg(0));//Roll + m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg(0));//Pitch + m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw + } + if (i==1) + {//tailrotor + m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1 + m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg(0));//ThrottleCurve2 + m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg(0));//Roll + m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg(0));//Pitch + m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(127));//Yaw + } + if (i>1) + {//Swashplate + m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1 + m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg((int)(127.0*CollectiveConstant)));//ThrottleCurve2 + m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(RollConstant)*sin((180+GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll + m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(PitchConstant)*cos((GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch + m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw + + } + } + else + { + for (j=0;j<6;j++) m_ccpm->ccpmAdvancedSettingsTable->item(i,j)->setText(QString("-")); + } + + } + } + else + {//advanced settings + for (i=0;i<6;i++) + { + Channel =m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->text(); + if (Channel == "-") Channel = QString("9"); + MixerChannelData[i]= Channel.toInt(); + } + } + + + +} + +/************************** + * ccpm settings + **************************/ +/* + Get the state of the UI check boxes and change the visibility of sliders + typedef struct { + uint SwasplateType:3; + uint FirstServoIndex:2; + uint CorrectionAngle:9; + uint ccpmCollectivePassthroughState:1; + uint ccpmLinkCyclicState:1; + uint ccpmLinkRollState:1; + uint CollectiveChannel:3; + uint padding:12; + } __attribute__((packed)) heliGUISettingsStruct; + + */ +void ConfigccpmWidget::UpdateCCPMOptionsFromUI() +{ + bool useCCPM; + bool useCyclic; + + if (updatingFromHardware) return; + //get the user options + //swashplate config + GUIConfigData.heli.SwasplateType = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; + GUIConfigData.heli.FirstServoIndex = m_ccpm->ccpmSingleServo->currentIndex(); + + //ccpm mixing options + GUIConfigData.heli.ccpmCollectivePassthroughState = m_ccpm->ccpmCollectivePassthrough->isChecked(); + GUIConfigData.heli.ccpmLinkCyclicState = m_ccpm->ccpmLinkCyclic->isChecked(); + GUIConfigData.heli.ccpmLinkRollState = m_ccpm->ccpmLinkRoll->isChecked(); + useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState); + useCyclic = GUIConfigData.heli.ccpmLinkRollState; + + //correction angle + GUIConfigData.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value(); + + //update sliders + if (useCCPM) + { + GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveSlider->value(); + } + else + { + GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveScale->value(); + } + if (useCyclic) + { + GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmCyclicScale->value(); + } + else + { + GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value(); + } + GUIConfigData.heli.SliderValue2 = m_ccpm->ccpmRollScale->value(); + + //servo assignments + GUIConfigData.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex(); + GUIConfigData.heli.ServoIndexX = m_ccpm->ccpmServoXChannel->currentIndex(); + GUIConfigData.heli.ServoIndexY = m_ccpm->ccpmServoYChannel->currentIndex(); + GUIConfigData.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex(); + +} +void ConfigccpmWidget::UpdateCCPMUIFromOptions() +{ + //swashplate config + m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - (GUIConfigData.heli.SwasplateType +1)); + m_ccpm->ccpmSingleServo->setCurrentIndex(GUIConfigData.heli.FirstServoIndex); + + //ccpm mixing options + m_ccpm->ccpmCollectivePassthrough->setChecked(GUIConfigData.heli.ccpmCollectivePassthroughState); + m_ccpm->ccpmLinkCyclic->setChecked(GUIConfigData.heli.ccpmLinkCyclicState); + m_ccpm->ccpmLinkRoll->setChecked(GUIConfigData.heli.ccpmLinkRollState); + + //correction angle + m_ccpm->ccpmCorrectionAngle->setValue(GUIConfigData.heli.CorrectionAngle); + + //update sliders + m_ccpm->ccpmCollectiveScale->setValue(GUIConfigData.heli.SliderValue0); + m_ccpm->ccpmCollectiveScaleBox->setValue(GUIConfigData.heli.SliderValue0); + m_ccpm->ccpmCyclicScale->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmCyclicScaleBox->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmPitchScale->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmPitchScaleBox->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmRollScale->setValue(GUIConfigData.heli.SliderValue2); + m_ccpm->ccpmRollScaleBox->setValue(GUIConfigData.heli.SliderValue2); + m_ccpm->ccpmCollectiveSlider->setValue(GUIConfigData.heli.SliderValue0); + m_ccpm->ccpmCollectivespinBox->setValue(GUIConfigData.heli.SliderValue0); + + //servo assignments + m_ccpm->ccpmServoWChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexW); + m_ccpm->ccpmServoXChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexX); + m_ccpm->ccpmServoYChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexY); + m_ccpm->ccpmServoZChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexZ); + +} + + +void ConfigccpmWidget::SetUIComponentVisibilities() +{ + UpdateCCPMOptionsFromUI(); + //set which sliders are user... + m_ccpm->ccpmRevoMixingBox->setVisible(0); + + m_ccpm->ccpmPitchMixingBox->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState); + m_ccpm->ccpmCollectiveScalingBox->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState); + + m_ccpm->ccpmLinkCyclic->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState); + + m_ccpm->ccpmCyclicScalingBox->setVisible((GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState) && GUIConfigData.heli.ccpmLinkRollState); + if (!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState) + { + m_ccpm->ccpmPitchScalingBox->setVisible(0); + m_ccpm->ccpmRollScalingBox->setVisible(0); + m_ccpm->ccpmLinkRoll->setVisible(0); + + } + else + { + m_ccpm->ccpmPitchScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState); + m_ccpm->ccpmRollScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState); + m_ccpm->ccpmLinkRoll->setVisible(1); + } + +} +/** + Request the current value of the SystemSettings which holds the ccpm type + */ +void ConfigccpmWidget::requestccpmUpdate() +{ +#define MaxAngleError 2 + int MixerDataFromHeli[8][5]; + quint8 MixerOutputType[8]; + int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],ServoCurve2[4]; + int NumServos=0; + + if (SwashLvlConfigurationInProgress)return; + if (updatingToHardware)return; + updatingFromHardware=TRUE; + + unsigned int i,j; + + SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager()); + Q_ASSERT(systemSettings); + SystemSettings::DataFields systemSettingsData = systemSettings->getData(); + + Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM == + (sizeof(GUIConfigData.UAVObject) / sizeof(GUIConfigData.UAVObject[0]))); + + for(i = 0; i < SystemSettings::GUICONFIGDATA_NUMELEM; i++) + GUIConfigData.UAVObject[i]=systemSettingsData.GUIConfigData[i]; + + UpdateCCPMUIFromOptions(); + + // Get existing mixer settings + MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); + MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); + + //go through the user data and update the mixer matrix + for (j=0;j<5;j++) + { + MixerDataFromHeli[0][j] = mixerSettingsData.Mixer1Vector[j]; + MixerDataFromHeli[1][j] = mixerSettingsData.Mixer2Vector[j]; + MixerDataFromHeli[2][j] = mixerSettingsData.Mixer3Vector[j]; + MixerDataFromHeli[3][j] = mixerSettingsData.Mixer4Vector[j]; + MixerDataFromHeli[4][j] = mixerSettingsData.Mixer5Vector[j]; + MixerDataFromHeli[5][j] = mixerSettingsData.Mixer6Vector[j]; + MixerDataFromHeli[6][j] = mixerSettingsData.Mixer7Vector[j]; + MixerDataFromHeli[7][j] = mixerSettingsData.Mixer8Vector[j]; + } + + MixerOutputType[0] = mixerSettingsData.Mixer1Type; + MixerOutputType[1] = mixerSettingsData.Mixer2Type; + MixerOutputType[2] = mixerSettingsData.Mixer3Type; + MixerOutputType[3] = mixerSettingsData.Mixer4Type; + MixerOutputType[4] = mixerSettingsData.Mixer5Type; + MixerOutputType[5] = mixerSettingsData.Mixer6Type; + MixerOutputType[6] = mixerSettingsData.Mixer7Type; + MixerOutputType[7] = mixerSettingsData.Mixer8Type; + + EngineChannel =-1; + TailRotorChannel =-1; + for (j=0;j<5;j++) + { + ServoChannels[j]=8; + ServoCurve2[j]=0; + ServoAngles[j]=0; + SortAngles[j]=j; + } + + NumServos=0; + //process the data from Heli and try to figure out the settings... + for (i=0;i<8;i++) + { + //check if this is the engine... Throttle only + if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_MOTOR)&& + (MixerDataFromHeli[i][0]>0)&&//ThrottleCurve1 + (MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2 + (MixerDataFromHeli[i][2]==0)&&//Roll + (MixerDataFromHeli[i][3]==0)&&//Pitch + (MixerDataFromHeli[i][4]==0))//Yaw + { + EngineChannel = i; + m_ccpm->ccpmEngineChannel->setCurrentIndex(i); + + } + //check if this is the tail rotor... REVO and YAW + if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&& + //(MixerDataFromHeli[i][0]!=0)&&//ThrottleCurve1 + (MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2 + (MixerDataFromHeli[i][2]==0)&&//Roll + (MixerDataFromHeli[i][3]==0)&&//Pitch + (MixerDataFromHeli[i][4]!=0))//Yaw + { + TailRotorChannel = i; + m_ccpm->ccpmTailChannel->setCurrentIndex(i); + m_ccpm->ccpmRevoSlider->setValue((MixerDataFromHeli[i][0]*100)/127); + m_ccpm->ccpmREVOspinBox->setValue((MixerDataFromHeli[i][0]*100)/127); + } + //check if this is a swashplate servo... Throttle is zero + if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&& + (MixerDataFromHeli[i][0]==0)&&//ThrottleCurve1 + //(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2 + //(MixerDataFromHeli[i][2]==0)&&//Roll + //(MixerDataFromHeli[i][3]==0)&&//Pitch + (MixerDataFromHeli[i][4]==0))//Yaw + { + ServoChannels[NumServos] = i;//record the channel for this servo + ServoCurve2[NumServos]=MixerDataFromHeli[i][1];//record the ThrottleCurve2 contribution to this servo + ServoAngles[NumServos]=NumServos*45;//make this 0 for the final version + + NumServos++; + } + + } + + //get the settings for the curve from the mixer settings + for (i=0;i<5;i++) + { + m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f", + mixerSettingsData.ThrottleCurve1[i])); + m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f", + mixerSettingsData.ThrottleCurve2[i])); + } + + updatingFromHardware=FALSE; + UpdateCCPMUIFromOptions(); + ccpmSwashplateUpdate(); +} + + +/** + Sends the config to the board (ccpm type) + */ +void ConfigccpmWidget::sendccpmUpdate() +{ + int i,j; + + if (SwashLvlConfigurationInProgress)return; + updatingToHardware=TRUE; + //ShowDisclaimer(1); + + UpdateCCPMOptionsFromUI(); + + // Store the data required to reconstruct + SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager()); + Q_ASSERT(systemSettings); + SystemSettings::DataFields systemSettingsData = systemSettings->getData(); + systemSettingsData.GUIConfigData[0] = GUIConfigData.UAVObject[0]; + systemSettingsData.GUIConfigData[1] = GUIConfigData.UAVObject[1]; + systemSettings->setData(systemSettingsData); + systemSettings->updated(); + + MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); + Q_ASSERT(mixerSettings); + MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); + + UpdateMixer(); + + // Set up some helper pointers + qint8 * mixers[8] = {mixerSettingsData.Mixer1Vector, + mixerSettingsData.Mixer2Vector, + mixerSettingsData.Mixer3Vector, + mixerSettingsData.Mixer4Vector, + mixerSettingsData.Mixer5Vector, + mixerSettingsData.Mixer6Vector, + mixerSettingsData.Mixer7Vector, + mixerSettingsData.Mixer8Vector + }; + + quint8 * mixerTypes[8] = { + &mixerSettingsData.Mixer1Type, + &mixerSettingsData.Mixer2Type, + &mixerSettingsData.Mixer3Type, + &mixerSettingsData.Mixer4Type, + &mixerSettingsData.Mixer5Type, + &mixerSettingsData.Mixer6Type, + &mixerSettingsData.Mixer7Type, + &mixerSettingsData.Mixer8Type + }; + + //go through the user data and update the mixer matrix + for (i=0;i<6;i++) + { + if (MixerChannelData[i]<8) + { + //set the mixer type + *(mixerTypes[MixerChannelData[i]]) = i==0 ? + MixerSettings::MIXER1TYPE_MOTOR : + MixerSettings::MIXER1TYPE_SERVO; + + //config the vector + for (j=0;j<5;j++) + mixers[MixerChannelData[i]][j] = m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt(); + } + } + + //get the user data for the curve into the mixer settings + for (i=0;i<5;i++) + mixerSettingsData.ThrottleCurve1[i] = m_ccpm->CurveSettings->item(i, 0)->text().toDouble(); + + for (i=0;i<5;i++) + mixerSettingsData.ThrottleCurve2[i] = m_ccpm->CurveSettings->item(i, 1)->text().toDouble(); + + //mapping of collective input to curve 2... + //MixerSettings.Curve2Source = Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5 + //check if we are using throttle or directly from a channel... + if (GUIConfigData.heli.ccpmCollectivePassthroughState) + mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_COLLECTIVE; + else + mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_THROTTLE; + + mixerSettings->setData(mixerSettingsData); + mixerSettings->updated(); + updatingToHardware=FALSE; + +} + +/** + Send ccpm type to the board and request saving to SD card + */ +void ConfigccpmWidget::saveccpmUpdate() +{ + if (SwashLvlConfigurationInProgress)return; + ShowDisclaimer(0); + // Send update so that the latest value is saved + sendccpmUpdate(); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + saveObjectToSD(obj); +} + +void ConfigccpmWidget::resizeEvent(QResizeEvent* event) +{ + Q_UNUSED(event); + // Make the custom table columns autostretch: + m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); + for (int i=0;i<6;i++) { + m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- + m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); + } + ccpmSwashplateRedraw(); + +} +void ConfigccpmWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); + for (int i=0;i<6;i++) { + m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- + m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); + } + ccpmSwashplateRedraw(); +} + + +void ConfigccpmWidget::SwashLvlStartButtonPressed() +{ + QMessageBox msgBox; + int i; + msgBox.setText("

Swashplate Leveling Routine

"); + msgBox.setInformativeText("You are about to start the Swashplate levelling routine.

This process will start by downloading the current configuration from the GCS to the OP hardware and will adjust your configuration at various stages.

The final state of your system should match the current configuration in the GCS config gadget.

Please ensure all ccpm settings in the GCS are correct before continuing.

If this process is interrupted, then the state of your OP board may not match the GCS configuration.

After completing this process, please check all settings before attempting to fly.

Please disconnect your motor to ensure it will not spin up.


Do you wish to proceed?"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Cancel); + msgBox.setIcon(QMessageBox::Information); + int ret = msgBox.exec(); + + UAVObjectField* MinField; + UAVObjectField* NeutralField; + UAVObjectField* MaxField; + UAVDataObject* obj; + ExtensionSystem::PluginManager *pm; + UAVObjectManager *objManager; + + switch (ret) { + case QMessageBox::Yes: + // Yes was clicked + SwashLvlState=0; + //remove Flight control of ActuatorCommand + enableSwashplateLevellingControl(true); + + m_ccpm->SwashLvlStartButton->setEnabled(false); + m_ccpm->SwashLvlNextButton->setEnabled(true); + m_ccpm->SwashLvlCancelButton->setEnabled(true); + m_ccpm->SwashLvlFinishButton->setEnabled(false); + //clear status check boxes + m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Unchecked); + m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Unchecked); + m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Unchecked); + m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Unchecked); + + + //download the current settings to the OP hw + sendccpmUpdate(); + + //change control mode to gcs control / disarmed + //set throttle to 0 + + + //save off the old ActuatorSettings for the swashplate servos + pm = ExtensionSystem::PluginManager::instance(); + objManager = pm->getObject(); + + + // Get the channel assignements: + obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + // obj->requestUpdate(); + MinField = obj->getField(QString("ChannelMin")); + NeutralField = obj->getField(QString("ChannelNeutral")); + MaxField = obj->getField(QString("ChannelMax")); + + //channel assignments + oldSwashLvlConfiguration.ServoChannels[0]=m_ccpm->ccpmServoWChannel->currentIndex(); + oldSwashLvlConfiguration.ServoChannels[1]=m_ccpm->ccpmServoXChannel->currentIndex(); + oldSwashLvlConfiguration.ServoChannels[2]=m_ccpm->ccpmServoYChannel->currentIndex(); + oldSwashLvlConfiguration.ServoChannels[3]=m_ccpm->ccpmServoZChannel->currentIndex(); + //if servos are used + oldSwashLvlConfiguration.Used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled())); + oldSwashLvlConfiguration.Used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled())); + oldSwashLvlConfiguration.Used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled())); + oldSwashLvlConfiguration.Used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled())); + //min,neutral,max values for the servos + for (i=0;igetValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt(); + oldSwashLvlConfiguration.Neutral[i]=NeutralField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt(); + oldSwashLvlConfiguration.Max[i]=MaxField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt(); + } + + //copy to new Actuator settings. + memcpy((void*)&newSwashLvlConfiguration,(void*)&oldSwashLvlConfiguration,sizeof(SwashplateServoSettingsStruct)); + + //goto the first step + SwashLvlNextButtonPressed(); + break; + case QMessageBox::Cancel: + // Cancel was clicked + SwashLvlState=0; + //restore Flight control of ActuatorCommand + enableSwashplateLevellingControl(false); + + m_ccpm->SwashLvlStartButton->setEnabled(true); + m_ccpm->SwashLvlNextButton->setEnabled(false); + m_ccpm->SwashLvlCancelButton->setEnabled(false); + m_ccpm->SwashLvlFinishButton->setEnabled(false); + break; + default: + // should never be reached + break; + } + + +} +void ConfigccpmWidget::SwashLvlNextButtonPressed() +{ + //ShowDisclaimer(2); + SwashLvlState++; + int i; + + + + + switch (SwashLvlState) + { + case 0: + break; + case 1: //Neutral levelling + m_ccpm->SwashLvlStepList->setCurrentRow(0); + //set spin boxes and swashplate servos to Neutral values + setSwashplateLevel(50); + //disable position slider + m_ccpm->SwashLvlPositionSlider->setEnabled(false); + m_ccpm->SwashLvlPositionSpinBox->setEnabled(false); + //set position slider to 50% + m_ccpm->SwashLvlPositionSlider->setValue(50); + m_ccpm->SwashLvlPositionSpinBox->setValue(50); + //connect spinbox signals to slots and ebnable them + for (i=0;isetEnabled(true); + } + //issue user instructions + m_ccpm->SwashLvlStepInstruction->setHtml("

Neutral levelling

Using adjustment of:

  • servo horns
  • link lengths and
  • Neutral timing spinboxes to the right

ensure that the swashplate is in the center of desired travel range and is level."); + break; + case 2: //Max levelling + //check Neutral status as complete + m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Checked); + m_ccpm->SwashLvlStepList->setCurrentRow(1); + //set spin boxes and swashplate servos to Max values + setSwashplateLevel(100); + //set position slider to 100% + m_ccpm->SwashLvlPositionSlider->setValue(100); + m_ccpm->SwashLvlPositionSpinBox->setValue(100); + //issue user instructions + m_ccpm->SwashLvlStepInstruction->setText("

Max levelling

Using adjustment of:

  • Max timing spinboxes to the right ONLY

ensure that the swashplate is at the top of desired travel range and is level."); + break; + case 3: //Min levelling + //check Max status as complete + m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Checked); + m_ccpm->SwashLvlStepList->setCurrentRow(2); + //set spin boxes and swashplate servos to Min values + setSwashplateLevel(0); + //set position slider to 0% + m_ccpm->SwashLvlPositionSlider->setValue(0); + m_ccpm->SwashLvlPositionSpinBox->setValue(0); + //issue user instructions + m_ccpm->SwashLvlStepInstruction->setText("

Min levelling

Using adjustment of:

  • Min timing spinboxes to the right ONLY

ensure that the swashplate is at the bottom of desired travel range and is level."); + break; + case 4: //levelling verification + //check Min status as complete + m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Checked); + m_ccpm->SwashLvlStepList->setCurrentRow(3); + //enable position slider + m_ccpm->SwashLvlPositionSlider->setEnabled(true); + m_ccpm->SwashLvlPositionSpinBox->setEnabled(true); + //make heli respond to slider movement + connect(m_ccpm->SwashLvlPositionSlider, SIGNAL(valueChanged(int)), this, SLOT(setSwashplateLevel(int))); + //disable spin boxes + for (i=0;isetEnabled(false); + } + + //issue user instructions + m_ccpm->SwashLvlStepInstruction->setText("

levelling verification

Adjust the slider to the right over it's full range and observe the swashplate motion. It should remain level over the entire range of travel."); + break; + case 5: //levelling complete + //check verify status as complete + m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Checked); + //issue user instructions + m_ccpm->SwashLvlStepInstruction->setText("

levelling complete

Press the Finish button to save these settings to the SD card

Press the cancel button to return to the pre-levelling settings"); + //disable position slider + m_ccpm->SwashLvlPositionSlider->setEnabled(false); + m_ccpm->SwashLvlPositionSpinBox->setEnabled(false); + //disconnect levelling slots from signals + disconnect(m_ccpm->SwashLvlPositionSlider, SIGNAL(valueChanged(int)), this, SLOT(setSwashplateLevel(int))); + for (i=0;iSwashLvlStartButton->setEnabled(false); + m_ccpm->SwashLvlNextButton->setEnabled(false); + m_ccpm->SwashLvlCancelButton->setEnabled(true); + m_ccpm->SwashLvlFinishButton->setEnabled(true); + + default: + //restore collective/cyclic setting + //restore pitch curve + //clear spin boxes + //change control mode to gcs control (OFF) / disarmed + //issue user confirmation + break; + } +} +void ConfigccpmWidget::SwashLvlCancelButtonPressed() +{ + int i; + SwashLvlState=0; + + UAVObjectField* MinField; + UAVObjectField* NeutralField; + UAVObjectField* MaxField; + + m_ccpm->SwashLvlStartButton->setEnabled(true); + m_ccpm->SwashLvlNextButton->setEnabled(false); + m_ccpm->SwashLvlCancelButton->setEnabled(false); + m_ccpm->SwashLvlFinishButton->setEnabled(false); + + m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Unchecked); + m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Unchecked); + m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Unchecked); + m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Unchecked); + + //restore old Actuator Settings + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + //update settings to match our changes. + MinField = obj->getField(QString("ChannelMin")); + NeutralField = obj->getField(QString("ChannelNeutral")); + MaxField = obj->getField(QString("ChannelMax")); + + //min,neutral,max values for the servos + for (i=0;isetValue(oldSwashLvlConfiguration.Min[i],oldSwashLvlConfiguration.ServoChannels[i]); + NeutralField->setValue(oldSwashLvlConfiguration.Neutral[i],oldSwashLvlConfiguration.ServoChannels[i]); + MaxField->setValue(oldSwashLvlConfiguration.Max[i],oldSwashLvlConfiguration.ServoChannels[i]); + } + + obj->updated(); + + + //restore Flight control of ActuatorCommand + enableSwashplateLevellingControl(false); + + m_ccpm->SwashLvlStepInstruction->setText("

Levelling Cancelled

Previous settings have been restored."); + +} + + +void ConfigccpmWidget::SwashLvlFinishButtonPressed() +{ + int i; + + UAVObjectField* MinField; + UAVObjectField* NeutralField; + UAVObjectField* MaxField; + + m_ccpm->SwashLvlStartButton->setEnabled(true); + m_ccpm->SwashLvlNextButton->setEnabled(false); + m_ccpm->SwashLvlCancelButton->setEnabled(false); + m_ccpm->SwashLvlFinishButton->setEnabled(false); + + //save new Actuator Settings to memory and SD card + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + //update settings to match our changes. + MinField = obj->getField(QString("ChannelMin")); + NeutralField = obj->getField(QString("ChannelNeutral")); + MaxField = obj->getField(QString("ChannelMax")); + + //min,neutral,max values for the servos + for (i=0;isetValue(newSwashLvlConfiguration.Min[i],newSwashLvlConfiguration.ServoChannels[i]); + NeutralField->setValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]); + MaxField->setValue(newSwashLvlConfiguration.Max[i],newSwashLvlConfiguration.ServoChannels[i]); + } + + obj->updated(); + saveObjectToSD(obj); + + //restore Flight control of ActuatorCommand + enableSwashplateLevellingControl(false); + + m_ccpm->SwashLvlStepInstruction->setText("

Levelling Completed

New settings have been saved to the SD card"); + + ShowDisclaimer(0); + //ShowDisclaimer(2); + +} + +int ConfigccpmWidget::ShowDisclaimer(int messageID) +{ + QMessageBox msgBox; + msgBox.setText("

Warning!!!

"); + int ret; + switch (messageID) { + case 0: + // Basic disclaimer + msgBox.setInformativeText("

This code has many configurations.

Please double check all settings before attempting flight!"); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Information); + ret = msgBox.exec(); + return 0; + break; + case 1: + // Not Tested disclaimer + msgBox.setInformativeText("

The CCPM mixer code needs more testing!

Use it at your own risk!

Do you wish to continue?"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Cancel); + msgBox.setIcon(QMessageBox::Warning); + ret = msgBox.exec(); + switch (ret) + { + case QMessageBox::Cancel: return -1; + case QMessageBox::Yes: return 0; + } + break; + case 2: + // DO NOT use + msgBox.setInformativeText("

The CCPM swashplate levelling code is NOT complete!

DO NOT use it for flight!"); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Critical); + ret = msgBox.exec(); + return 0; + break; + default: + // should never be reached + break; + } + return -1; +} + + +/** + Toggles the channel testing mode by making the GCS take over + the ActuatorCommand objects + */ +void ConfigccpmWidget::enableSwashplateLevellingControl(bool state) +{ + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + + UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorCommand"))); + UAVObject::Metadata mdata = obj->getMetadata(); + if (state) + { + SwashLvlaccInitialData = mdata; + mdata.flightAccess = UAVObject::ACCESS_READONLY; + mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE; + mdata.gcsTelemetryAcked = false; + mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE; + mdata.gcsTelemetryUpdatePeriod = 100; + SwashLvlConfigurationInProgress=1; + m_ccpm->TabObject->setTabEnabled(0,0); + m_ccpm->TabObject->setTabEnabled(2,0); + m_ccpm->TabObject->setTabEnabled(3,0); + m_ccpm->ccpmType->setEnabled(0); + } + else + { + mdata = SwashLvlaccInitialData; // Restore metadata + SwashLvlConfigurationInProgress=0; + + m_ccpm->TabObject->setTabEnabled(0,1); + m_ccpm->TabObject->setTabEnabled(2,1); + m_ccpm->TabObject->setTabEnabled(3,1); + m_ccpm->ccpmType->setEnabled(1); + + } + obj->setMetadata(mdata); + +} + +/** + Sets the swashplate level to a given value based on current settings for Max, Neutral and Min values. + level ranges -1 to +1 + */ +void ConfigccpmWidget::setSwashplateLevel(int percent) +{ + if (percent<0)return;// -1; + if (percent>100)return;// -1; + if (SwashLvlConfigurationInProgress!=1)return;// -1; + int i; + double value; + double level = ((double)percent /50.00) - 1.00; + + SwashLvlServoInterlock=1; + + ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager()); + ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData(); + + for (i=0;i 0) + value = (newSwashLvlConfiguration.Max[i] - newSwashLvlConfiguration.Neutral[i])*level + newSwashLvlConfiguration.Neutral[i]; + else if (level < 0) + value = (newSwashLvlConfiguration.Neutral[i] - newSwashLvlConfiguration.Min[i])*level + newSwashLvlConfiguration.Neutral[i]; + + actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value; + SwashLvlSpinBoxes[i]->setValue(value); + } + + actuatorCommand->setData(actuatorCommandData); + actuatorCommand->updated(); + + SwashLvlServoInterlock=0; + +return; +} + + +void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value) +{ + Q_UNUSED(value); + int i; + if (SwashLvlServoInterlock==1)return; + + ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager()); + ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData(); + + for (i = 0; i < CCPM_MAX_SWASH_SERVOS; i++) { + value = SwashLvlSpinBoxes[i]->value(); + + switch (SwashLvlState) + { + case 1: //Neutral levelling + newSwashLvlConfiguration.Neutral[i]=value; + break; + case 2: //Max levelling + newSwashLvlConfiguration.Max[i] = value; + break; + case 3: //Min levelling + newSwashLvlConfiguration.Min[i]= value; + break; + case 4: //levelling verification + break; + case 5: //levelling complete + break; + default: + break; + } + + actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value; + } + + + actuatorCommand->setData(actuatorCommandData); + actuatorCommand->updated(); + + return; +} diff --git a/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.h b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.h new file mode 100644 index 000000000..31a5e227d --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.h @@ -0,0 +1,160 @@ +/** + ****************************************************************************** + * + * @file configccpmtwidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief ccpm configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef CONFIGccpmWIDGET_H +#define CONFIGccpmWIDGET_H + +#include "ui_ccpm.h" +#include "../uavobjectwidgetutils/configtaskwidget.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include +#include +#include +#include +#include + +#define CCPM_MAX_SWASH_SERVOS 4 + +class Ui_Widget; + +typedef struct { + int ServoChannels[CCPM_MAX_SWASH_SERVOS]; + int Used[CCPM_MAX_SWASH_SERVOS]; + int Max[CCPM_MAX_SWASH_SERVOS]; + int Neutral[CCPM_MAX_SWASH_SERVOS]; + int Min[CCPM_MAX_SWASH_SERVOS]; +} SwashplateServoSettingsStruct; + +typedef struct { + uint SwasplateType:3; + uint FirstServoIndex:2; + uint CorrectionAngle:9; + uint ccpmCollectivePassthroughState:1; + uint ccpmLinkCyclicState:1; + uint ccpmLinkRollState:1; + uint SliderValue0:7; + uint SliderValue1:7; + uint SliderValue2:7;//41bits + uint ServoIndexW:4; + uint ServoIndexX:4; + uint ServoIndexY:4; + uint ServoIndexZ:4;//57bits + uint padding:7; +} __attribute__((packed)) heliGUISettingsStruct; + +typedef union +{ + uint UAVObject[2];//32bits * 2 + heliGUISettingsStruct heli;//64bits +} GUIConfigDataUnion; + +class ConfigccpmWidget: public ConfigTaskWidget +{ + Q_OBJECT + +public: + ConfigccpmWidget(QWidget *parent = 0); + ~ConfigccpmWidget(); + + friend class ConfigVehicleTypeWidget; + +private: + Ui_ccpmWidget *m_ccpm; + QGraphicsSvgItem *SwashplateImg; + QGraphicsSvgItem *CurveImg; + //QGraphicsSvgItem *ServoW; + //QGraphicsSvgItem *ServoX; + //QGraphicsSvgItem *ServoY; + //QGraphicsSvgItem *ServoZ; + //QGraphicsTextItem *ServoWText; + //QGraphicsTextItem *ServoXText; + //QGraphicsTextItem *ServoYText; + //QGraphicsTextItem *ServoZText; + QGraphicsSvgItem *Servos[CCPM_MAX_SWASH_SERVOS]; + QGraphicsTextItem *ServosText[CCPM_MAX_SWASH_SERVOS]; + QGraphicsLineItem *ServoLines[CCPM_MAX_SWASH_SERVOS]; + QGraphicsEllipseItem *ServosTextCircles[CCPM_MAX_SWASH_SERVOS]; + QSpinBox *SwashLvlSpinBoxes[CCPM_MAX_SWASH_SERVOS]; + + bool SwashLvlConfigurationInProgress; + UAVObject::Metadata SwashLvlaccInitialData; + int SwashLvlState; + int SwashLvlServoInterlock; + + SwashplateServoSettingsStruct oldSwashLvlConfiguration; + SwashplateServoSettingsStruct newSwashLvlConfiguration; + + GUIConfigDataUnion GUIConfigData; + + int MixerChannelData[6]; + int ShowDisclaimer(int messageID); + virtual void enableControls(bool enable) { Q_UNUSED(enable)}; // Not used by this widget + + bool updatingFromHardware; + bool updatingToHardware; + + private slots: + void ccpmSwashplateUpdate(); + void ccpmSwashplateRedraw(); + void UpdateCurveSettings(); + void GenerateCurve(); + void UpdateMixer(); + void UpdateType(); + void resetMixer(MixerCurveWidget *mixer, int numElements); + void UpdateCurveWidgets(); + void updatePitchCurveValue(QList,double); + void updateThrottleCurveValue(QList,double); + + void SwashLvlStartButtonPressed(); + void SwashLvlNextButtonPressed(); + void SwashLvlCancelButtonPressed(); + void SwashLvlFinishButtonPressed(); + + void UpdateCCPMOptionsFromUI(); + void UpdateCCPMUIFromOptions(); + + void SetUIComponentVisibilities(); + void ccpmChannelCheck(); + + void enableSwashplateLevellingControl(bool state); + void setSwashplateLevel(int percent); + void SwashLvlSpinBoxChanged(int value); + virtual void refreshValues() {}; // Not used + + public slots: + void requestccpmUpdate(); + void sendccpmUpdate(); + void saveccpmUpdate(); + +protected: + void showEvent(QShowEvent *event); + void resizeEvent(QResizeEvent *event); + +}; + +#endif // CONFIGccpmWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configfixedwingwidget.cpp b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configfixedwingwidget.cpp new file mode 100644 index 000000000..d61f8175e --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configfixedwingwidget.cpp @@ -0,0 +1,699 @@ +/** + ****************************************************************************** + * + * @file configccpmwidget.cpp + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief ccpm configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +//#include "configfixedwingwidget.h" +#include "configvehicletypewidget.h" +#include "mixersettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mixersettings.h" +#include "systemsettings.h" +#include "actuatorcommand.h" + + +/** + Helper function to setup the UI + */ +void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType) +{ + if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") { + // Setup the UI + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); + m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder")); + m_aircraft->fwRudder1ChannelBox->setEnabled(true); + m_aircraft->fwRudder1Label->setEnabled(true); + m_aircraft->fwRudder2ChannelBox->setEnabled(true); + m_aircraft->fwRudder2Label->setEnabled(true); + m_aircraft->fwElevator1ChannelBox->setEnabled(true); + m_aircraft->fwElevator1Label->setEnabled(true); + m_aircraft->fwElevator2ChannelBox->setEnabled(true); + m_aircraft->fwElevator2Label->setEnabled(true); + m_aircraft->fwAileron1ChannelBox->setEnabled(true); + m_aircraft->fwAileron1Label->setEnabled(true); + m_aircraft->fwAileron2ChannelBox->setEnabled(true); + m_aircraft->fwAileron2Label->setEnabled(true); + + m_aircraft->fwAileron1Label->setText("Aileron 1"); + m_aircraft->fwAileron2Label->setText("Aileron 2"); + m_aircraft->fwElevator1Label->setText("Elevator 1"); + m_aircraft->fwElevator2Label->setText("Elevator 2"); + m_aircraft->elevonMixBox->setHidden(true); + + } else if (frameType == "FixedWingElevon" || frameType == "Elevon") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); + m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon")); + m_aircraft->fwAileron1Label->setText("Elevon 1"); + m_aircraft->fwAileron2Label->setText("Elevon 2"); + m_aircraft->fwElevator1ChannelBox->setEnabled(false); + m_aircraft->fwElevator1Label->setEnabled(false); + m_aircraft->fwElevator2ChannelBox->setEnabled(false); + m_aircraft->fwElevator2Label->setEnabled(false); + m_aircraft->fwRudder1ChannelBox->setEnabled(true); + m_aircraft->fwRudder1Label->setEnabled(true); + m_aircraft->fwRudder2ChannelBox->setEnabled(true); + m_aircraft->fwRudder2Label->setEnabled(true); + m_aircraft->fwElevator1Label->setText("Elevator 1"); + m_aircraft->fwElevator2Label->setText("Elevator 2"); + m_aircraft->elevonMixBox->setHidden(false); + m_aircraft->elevonLabel1->setText("Roll"); + m_aircraft->elevonLabel2->setText("Pitch"); + + } else if (frameType == "FixedWingVtail" || frameType == "Vtail") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); + m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail")); + m_aircraft->fwRudder1ChannelBox->setEnabled(false); + m_aircraft->fwRudder1Label->setEnabled(false); + m_aircraft->fwRudder2ChannelBox->setEnabled(false); + m_aircraft->fwRudder2Label->setEnabled(false); + m_aircraft->fwElevator1ChannelBox->setEnabled(true); + m_aircraft->fwElevator1Label->setEnabled(true); + m_aircraft->fwElevator1Label->setText("Vtail 1"); + m_aircraft->fwElevator2Label->setText("Vtail 2"); + m_aircraft->elevonMixBox->setHidden(false); + m_aircraft->fwElevator2ChannelBox->setEnabled(true); + m_aircraft->fwElevator2Label->setEnabled(true); + m_aircraft->fwAileron1Label->setText("Aileron 1"); + m_aircraft->fwAileron2Label->setText("Aileron 2"); + m_aircraft->elevonLabel1->setText("Rudder"); + m_aircraft->elevonLabel2->setText("Pitch"); + } +} + + + +/** + Helper function to update the UI widget objects + */ +QString ConfigVehicleTypeWidget::updateFixedWingObjectsFromWidgets() +{ + QString airframeType = "FixedWing"; + + // Save the curve (common to all Fixed wing frames) + UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + + // Remove Feed Forward, it is pointless on a plane: + UAVObjectField* field = obj->getField(QString("FeedForward")); + field->setDouble(0); + + field = obj->getField("ThrottleCurve1"); + QList curve = m_aircraft->fixedWingThrottle->getCurve(); + for (int i=0;isetValue(curve.at(i),i); + } + + //All airframe types must start with "FixedWing" + if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) { + airframeType = "FixedWing"; + setupFrameFixedWing( airframeType ); + } else if (m_aircraft->fixedWingType->currentText() == "Elevon") { + airframeType = "FixedWingElevon"; + setupFrameElevon( airframeType ); + } else { // "Vtail" + airframeType = "FixedWingVtail"; + setupFrameVtail( airframeType ); + } + + // Now reflect those settings in the "Custom" panel as well + updateCustomAirframeUI(); + + return airframeType; +} + + +/** + Helper function to refresh the UI widget values + */ +void ConfigVehicleTypeWidget::refreshFixedWingWidgetsValues(QString frameType) +{ + + UAVDataObject* obj; + UAVObjectField *field; + + // Then retrieve how channels are setup + obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + field = obj->getField(QString("FixedWingThrottle")); + Q_ASSERT(field); + m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingRoll1")); + Q_ASSERT(field); + m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingRoll2")); + Q_ASSERT(field); + m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingPitch1")); + Q_ASSERT(field); + m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingPitch2")); + Q_ASSERT(field); + m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingYaw1")); + Q_ASSERT(field); + m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingYaw2")); + Q_ASSERT(field); + m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString())); + + if (frameType == "FixedWingElevon") { + // If the airframe is elevon, restore the slider setting + // Find the channel number for Elevon1 (FixedWingRoll1) + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; + if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check. + field = obj->getField(mixerVectors.at(chMixerNumber)); + int ti = field->getElementNames().indexOf("Roll"); + m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100); + ti = field->getElementNames().indexOf("Pitch"); + m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100); + } + } + if (frameType == "FixedWingVtail") { + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + int chMixerNumber = m_aircraft->fwElevator1ChannelBox->currentIndex()-1; + if (chMixerNumber >=0) { + field = obj->getField(mixerVectors.at(chMixerNumber)); + int ti = field->getElementNames().indexOf("Yaw"); + m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100); + ti = field->getElementNames().indexOf("Pitch"); + m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100); + } + } + +} + + + +/** + Setup Elevator/Aileron/Rudder airframe. + + If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing + + Returns False if impossible to create the mixer. + */ +bool ConfigVehicleTypeWidget::setupFrameFixedWing(QString airframeType) +{ + // Check coherence: + //Show any config errors in GUI + throwFixedWingChannelConfigError(airframeType); + + // - At least Pitch and either Roll or Yaw + if (m_aircraft->fwEngineChannelBox->currentText() == "None" || + m_aircraft->fwElevator1ChannelBox->currentText() == "None" || + ((m_aircraft->fwAileron1ChannelBox->currentText() == "None") && + (m_aircraft->fwRudder1ChannelBox->currentText() == "None"))) { + // TODO: explain the problem in the UI +// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment"); + return false; + } + // Now setup the channels: + resetActuators(); + + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + + // Elevator + UAVObjectField *field = obj->getField("FixedWingPitch1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwElevator1ChannelBox->currentText()); + field = obj->getField("FixedWingPitch2"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwElevator2ChannelBox->currentText()); + + // Aileron + field = obj->getField("FixedWingRoll1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); + field = obj->getField("FixedWingRoll2"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); + + // Rudder + field = obj->getField("FixedWingYaw1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwRudder1ChannelBox->currentText()); + + // Throttle + field = obj->getField("FixedWingThrottle"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwEngineChannelBox->currentText()); + + obj->updated(); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + // ... and compute the matrix: + // In order to make code a bit nicer, we assume: + // - Channel dropdowns start with 'None', then 0 to 7 + + // 1. Assign the servo/motor/none for each channel + // Disable all + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + field->setValue("Disabled"); + } + // and set only the relevant channels: + // Engine + int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Motor"); + field = obj->getField(mixerVectors.at(tmpVal)); + // First of all reset the vector + resetField(field); + int ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(127, ti); + + // Rudder + tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1; + // tmpVal will be -1 if rudder is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(127, ti); + } // Else: we have no rudder, only ailerons, we're fine with it. + + // Ailerons + tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(127, ti); + // Only set Aileron 2 if Aileron 1 is defined + tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(127, ti); + } + } // Else we have no ailerons. Our consistency check guarantees we have + // rudder in this case, so we're fine with it too. + + // Elevator + tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue(127, ti); + // Only set Elevator 2 if it is defined + tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue(127, ti); + } + + obj->updated(); + m_aircraft->fwStatusLabel->setText("Mixer generated"); + + return true; +} + + + +/** + Setup Elevon + */ +bool ConfigVehicleTypeWidget::setupFrameElevon(QString airframeType) +{ + // Check coherence: + //Show any config errors in GUI + throwFixedWingChannelConfigError(airframeType); + + // - At least Aileron1 and Aileron 2, and engine + if (m_aircraft->fwEngineChannelBox->currentText() == "None" || + m_aircraft->fwAileron1ChannelBox->currentText() == "None" || + m_aircraft->fwAileron2ChannelBox->currentText() == "None") { + // TODO: explain the problem in the UI +// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment"); + return false; + } + + resetActuators(); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + + // Elevons + UAVObjectField *field = obj->getField("FixedWingRoll1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); + field = obj->getField("FixedWingRoll2"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); + // Rudder 1 (can be None) + field = obj->getField("FixedWingYaw1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwRudder1ChannelBox->currentText()); + // Rudder 2 (can be None) + field = obj->getField("FixedWingYaw2"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwRudder2ChannelBox->currentText()); + // Throttle + field = obj->getField("FixedWingThrottle"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwEngineChannelBox->currentText()); + + obj->updated(); + + // Save the curve: + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + // ... and compute the matrix: + // In order to make code a bit nicer, we assume: + // - Channel dropdowns start with 'None', then 0 to 7 + + // 1. Assign the servo/motor/none for each channel + // Disable all + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + field->setValue("Disabled"); + } + // and set only the relevant channels: + // Engine + int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Motor"); + field = obj->getField(mixerVectors.at(tmpVal)); + // First of all reset the vector + resetField(field); + int ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(127, ti); + + // Rudder 1 + tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1; + // tmpVal will be -1 if rudder 1 is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(127, ti); + } // Else: we have no rudder, only elevons, we're fine with it. + + // Rudder 2 + tmpVal = m_aircraft->fwRudder2ChannelBox->currentIndex()-1; + // tmpVal will be -1 if rudder 2 is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(-127, ti); + } // Else: we have no rudder, only elevons, we're fine with it. + + tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti); + } + + tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti); + } + + obj->updated(); + m_aircraft->fwStatusLabel->setText("Mixer generated"); + return true; +} + + + +/** + Setup VTail + */ +bool ConfigVehicleTypeWidget::setupFrameVtail(QString airframeType) +{ + // Check coherence: + //Show any config errors in GUI + throwFixedWingChannelConfigError(airframeType); + + // - At least Pitch1 and Pitch2, and engine + if (m_aircraft->fwEngineChannelBox->currentText() == "None" || + m_aircraft->fwElevator1ChannelBox->currentText() == "None" || + m_aircraft->fwElevator2ChannelBox->currentText() == "None") { + // TODO: explain the problem in the UI +// m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment"); + return false; + } + + resetActuators(); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + + // Elevons + UAVObjectField *field = obj->getField("FixedWingPitch1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwElevator1ChannelBox->currentText()); + field = obj->getField("FixedWingPitch2"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwElevator2ChannelBox->currentText()); + field = obj->getField("FixedWingRoll1"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); + field = obj->getField("FixedWingRoll2"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); + + // Throttle + field = obj->getField("FixedWingThrottle"); + Q_ASSERT(field); + field->setValue(m_aircraft->fwEngineChannelBox->currentText()); + + obj->updated(); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + // ... and compute the matrix: + // In order to make code a bit nicer, we assume: + // - Channel dropdowns start with 'None', then 0 to 7 + + // 1. Assign the servo/motor/none for each channel + // Disable all + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + field->setValue("Disabled"); + } + // and set only the relevant channels: + // Engine + int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Motor"); + field = obj->getField(mixerVectors.at(tmpVal)); + // First of all reset the vector + resetField(field); + int ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(127, ti); + + tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(127,ti); + } + + tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(-127,ti); + } + + // Now compute the VTail + tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti); + + tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti); + + obj->updated(); + m_aircraft->fwStatusLabel->setText("Mixer generated"); + return true; +} + +/** + This function displays text and color formatting in order to help the user understand what channels have not yet been configured. + */ +void ConfigVehicleTypeWidget::throwFixedWingChannelConfigError(QString airframeType) +{ + //Initialize configuration error flag + bool error=false; + + //Create a red block. All combo boxes are the same size, so any one should do as a model + int size = m_aircraft->fwEngineChannelBox->style()->pixelMetric(QStyle::PM_SmallIconSize); + QPixmap pixmap(size,size); + pixmap.fill(QColor("red")); + + if (airframeType == "FixedWing" ) { + if (m_aircraft->fwEngineChannelBox->currentText() == "None"){ + m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if (m_aircraft->fwElevator1ChannelBox->currentText() == "None"){ + m_aircraft->fwElevator1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwElevator1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if ((m_aircraft->fwAileron1ChannelBox->currentText() == "None") && (m_aircraft->fwRudder1ChannelBox->currentText() == "None")) { + pixmap.fill(QColor("green")); + m_aircraft->fwAileron1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + m_aircraft->fwRudder1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwAileron1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + m_aircraft->fwRudder1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + } else if (airframeType == "FixedWingElevon"){ + if (m_aircraft->fwEngineChannelBox->currentText() == "None"){ + m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if(m_aircraft->fwAileron1ChannelBox->currentText() == "None"){ + m_aircraft->fwAileron1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwAileron1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if (m_aircraft->fwAileron2ChannelBox->currentText() == "None"){ + m_aircraft->fwAileron2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwAileron2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + } else if ( airframeType == "FixedWingVtail"){ + if (m_aircraft->fwEngineChannelBox->currentText() == "None"){ + m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if(m_aircraft->fwElevator1ChannelBox->currentText() == "None"){ + m_aircraft->fwElevator1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwElevator1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if(m_aircraft->fwElevator2ChannelBox->currentText() == "None"){ + m_aircraft->fwElevator2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->fwElevator2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + } + + if (error){ + m_aircraft->fwStatusLabel->setText(QString("ERROR: Assign all necessary channels")); + } +} diff --git a/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configgroundvehiclewidget.cpp b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configgroundvehiclewidget.cpp new file mode 100644 index 000000000..d10600cd1 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configgroundvehiclewidget.cpp @@ -0,0 +1,751 @@ +/** + ****************************************************************************** + * + * @file configccpmwidget.cpp + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief ccpm configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +//#include "configgroundvehiclewidget.h" +#include "configvehicletypewidget.h" +#include "mixersettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mixersettings.h" +#include "systemsettings.h" +#include "actuatorcommand.h" + + +/** + Helper function to setup the UI + */ +void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType) +{ + m_aircraft->differentialSteeringMixBox->setHidden(true); + //STILL NEEDS WORK + // Setup the UI + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Ground")); + + m_aircraft->gvEngineChannelBox->setEnabled(false); + m_aircraft->gvEngineLabel->setEnabled(false); + + + m_aircraft->gvAileron1ChannelBox->setEnabled(false); + m_aircraft->gvAileron1Label->setEnabled(false); + + m_aircraft->gvAileron2ChannelBox->setEnabled(false); + m_aircraft->gvAileron2Label->setEnabled(false); + + if (frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)"){ //Tank + m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Differential (tank)")); + m_aircraft->gvMotor1ChannelBox->setEnabled(true); + m_aircraft->gvMotor1Label->setEnabled(true); + + m_aircraft->gvMotor2ChannelBox->setEnabled(true); + m_aircraft->gvMotor2Label->setEnabled(true); + + m_aircraft->gvMotor1Label->setText("Left motor"); + m_aircraft->gvMotor2Label->setText("Right motor"); + + m_aircraft->gvSteering1ChannelBox->setEnabled(false); + m_aircraft->gvSteering1Label->setEnabled(false); + + m_aircraft->gvSteering2ChannelBox->setEnabled(false); + m_aircraft->gvSteering2Label->setEnabled(false); + + m_aircraft->gvSteering2Label->setText("Rear steering"); + + m_aircraft->differentialSteeringMixBox->setHidden(false); + + m_aircraft->gvThrottleCurve1GroupBox->setTitle("Left throttle curve"); + m_aircraft->gvThrottleCurve2GroupBox->setTitle("Right throttle curve"); + + } + else if (frameType == "GroundVehicleMotorcycle" || frameType == "Motorcycle"){ //Motorcycle + m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Motorcycle")); + m_aircraft->gvMotor1ChannelBox->setEnabled(false); + m_aircraft->gvMotor1Label->setEnabled(false); + + m_aircraft->gvMotor2ChannelBox->setEnabled(true); + m_aircraft->gvMotor2Label->setEnabled(true); + + m_aircraft->gvMotor1Label->setText("Front motor"); + m_aircraft->gvMotor2Label->setText("Rear motor"); + + m_aircraft->gvSteering1ChannelBox->setEnabled(true); + m_aircraft->gvSteering1Label->setEnabled(true); + + m_aircraft->gvSteering2ChannelBox->setEnabled(true); + m_aircraft->gvSteering2Label->setEnabled(true); + + m_aircraft->gvSteering2Label->setText("Balancing"); + + m_aircraft->differentialSteeringMixBox->setHidden(true); + + m_aircraft->gvThrottleCurve1GroupBox->setTitle("Front throttle curve"); + m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve"); + } + else {//Car + m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Turnable (car)")); + + m_aircraft->gvMotor1ChannelBox->setEnabled(true); + m_aircraft->gvMotor1Label->setEnabled(true); + + m_aircraft->gvMotor2ChannelBox->setEnabled(true); + m_aircraft->gvMotor2Label->setEnabled(true); + + m_aircraft->gvMotor1Label->setText("Front motor"); + m_aircraft->gvMotor2Label->setText("Rear motor"); + + m_aircraft->gvSteering1ChannelBox->setEnabled(true); + m_aircraft->gvSteering1Label->setEnabled(true); + + m_aircraft->gvSteering2ChannelBox->setEnabled(true); + m_aircraft->gvSteering2Label->setEnabled(true); + + m_aircraft->differentialSteeringMixBox->setHidden(true); + + m_aircraft->gvThrottleCurve1GroupBox->setTitle("Front throttle curve"); + m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve"); + } +} + + + +/** + Helper function to update the UI widget objects + */ +QString ConfigVehicleTypeWidget::updateGroundVehicleObjectsFromWidgets() +{ + QString airframeType = "GroundVehicleCar"; + + // Save the curve (common to all ground vehicle frames) + UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + + // Remove Feed Forward, it is pointless on a ground vehicle: + UAVObjectField* field = obj->getField(QString("FeedForward")); + field->setDouble(0); + + field = obj->getField("ThrottleCurve1"); + QList curve = m_aircraft->groundVehicleThrottle1->getCurve(); + for (int i=0;isetValue(curve.at(i),i); + } + + field = obj->getField("ThrottleCurve2"); + curve = m_aircraft->groundVehicleThrottle2->getCurve(); + for (int i=0;isetValue(curve.at(i),i); + } + + //All airframe types must start with "GroundVehicle" + if (m_aircraft->groundVehicleType->currentText() == "Turnable (car)" ) { + airframeType = "GroundVehicleCar"; + setupGroundVehicleCar(airframeType); + } else if (m_aircraft->groundVehicleType->currentText() == "Differential (tank)") { + airframeType = "GroundVehicleDifferential"; + setupGroundVehicleDifferential(airframeType); + } else { // "Motorcycle" + airframeType = "GroundVehicleMotorcycle"; + setupGroundVehicleMotorcycle(airframeType); + } + + // Now reflect those settings in the "Custom" panel as well + updateCustomAirframeUI(); + + return airframeType; +} + + + +/** + Helper function to refresh the UI widget values + */ +void ConfigVehicleTypeWidget::refreshGroundVehicleWidgetsValues(QString frameType) +{ + + UAVDataObject* obj; + UAVObjectField *field; + + //THIS SECTION STILL NEEDS WORK. FOR THE MOMENT, USE THE FIXED-WING ONBOARD SETTING IN ORDER TO MINIMIZE CHANCES OF BOLLOXING REAL CODE + // Retrieve channel setup values + obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + field = obj->getField(QString("FixedWingThrottle")); + Q_ASSERT(field); + m_aircraft->gvEngineChannelBox->setCurrentIndex(m_aircraft->gvEngineChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingRoll1")); + Q_ASSERT(field); + m_aircraft->gvAileron1ChannelBox->setCurrentIndex(m_aircraft->gvAileron1ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("FixedWingRoll2")); + Q_ASSERT(field); + m_aircraft->gvAileron2ChannelBox->setCurrentIndex(m_aircraft->gvAileron2ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("GroundVehicleThrottle1")); + Q_ASSERT(field); + m_aircraft->gvMotor1ChannelBox->setCurrentIndex(m_aircraft->gvMotor1ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("GroundVehicleThrottle2")); + Q_ASSERT(field); + m_aircraft->gvMotor2ChannelBox->setCurrentIndex(m_aircraft->gvMotor2ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("GroundVehicleSteering1")); + Q_ASSERT(field); + m_aircraft->gvSteering1ChannelBox->setCurrentIndex(m_aircraft->gvSteering1ChannelBox->findText(field->getValue().toString())); + + field = obj->getField(QString("GroundVehicleSteering2")); + Q_ASSERT(field); + m_aircraft->gvSteering2ChannelBox->setCurrentIndex(m_aircraft->gvSteering2ChannelBox->findText(field->getValue().toString())); + + if (frameType == "GroundVehicleDifferential") { + //CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE + // If the vehicle type is "differential", restore the slider setting + + // Find the channel number for Motor1 + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1; + if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check. + field = obj->getField(mixerVectors.at(chMixerNumber)); + int ti = field->getElementNames().indexOf("Roll"); + m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100); + + ti = field->getElementNames().indexOf("Pitch"); + m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100); + } + } + if (frameType == "GroundVehicleMotorcycle") { + //CURRENTLY BROKEN UNTIL WE DECIDE HOW MOTORCYCLE SHOULD BEHAVE +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1; +// if (chMixerNumber >=0) { +// field = obj->getField(mixerVectors.at(chMixerNumber)); +// int ti = field->getElementNames().indexOf("Yaw"); +// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100); +// +// ti = field->getElementNames().indexOf("Pitch"); +// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100); +// } + } +} + + + + +/** + Setup balancing ground vehicle. + + Returns False if impossible to create the mixer. + */ +bool ConfigVehicleTypeWidget::setupGroundVehicleMotorcycle(QString airframeType){ + // Check coherence: + //Show any config errors in GUI + throwGroundVehicleChannelConfigError(airframeType); + + // - Motor, steering, and balance + if (m_aircraft->gvMotor1ChannelBox->currentText() == "None" || + (m_aircraft->gvSteering1ChannelBox->currentText() == "None" || + m_aircraft->gvSteering2ChannelBox->currentText() == "None") ) + { + return false; + } + + + // Now setup the channels: + resetActuators(); + + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + + // Left motor + UAVObjectField *field = obj->getField("GroundVehicleThrottle1"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvMotor1ChannelBox->currentText()); + + // Right motor + field = obj->getField("GroundVehicleThrottle2"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvMotor2ChannelBox->currentText()); + + obj->updated(); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + // ... and compute the matrix: + // In order to make code a bit nicer, we assume: + // - Channel dropdowns start with 'None', then 0 to 7 + + // 1. Assign the servo/motor/none for each channel + + int tmpVal, ti; + + // Disable all output channels + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + + //Disable output channel + field->setValue("Disabled"); + + } + + // Set all mixer values to zero + foreach(QString mixer, mixerVectors) { + field = obj->getField(mixer); + resetField(field); + + ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("ThrottleCurve2"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(0, ti); + } + + // Motor + // Setup motor + tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); //Set motor mixer type to Servo + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward + field->setValue(127, ti); + + //Steering + // Setup steering + tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); //Set motor mixer type to Servo + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); //Set steering response to roll + field->setValue(-127, ti); + ti = field->getElementNames().indexOf("Roll"); //Set steering response to roll + field->setValue(-127, ti); + + //Balancing + // Setup balancing servo + tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); //Set motor mixer type to Servo + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); //Set balance response to yaw + field->setValue(127, ti); + ti = field->getElementNames().indexOf("Roll"); //Set balance response to roll + field->setValue(127, ti); + + obj->updated(); + + //Output success message + m_aircraft->gvStatusLabel->setText("Mixer generated"); + + return true; +} + + + +/** + Setup differentially steered ground vehicle. + + Returns False if impossible to create the mixer. + */ +bool ConfigVehicleTypeWidget::setupGroundVehicleDifferential(QString airframeType){ + // Check coherence: + //Show any config errors in GUI + throwGroundVehicleChannelConfigError(airframeType); + + // - Left and right steering + if ( m_aircraft->gvMotor2ChannelBox->currentText() == "None" || + m_aircraft->gvSteering1ChannelBox->currentText() == "None") + { + return false; + } + + + // Now setup the channels: + resetActuators(); + + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + + // Left motor + UAVObjectField *field = obj->getField("GroundVehicleThrottle1"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvMotor1ChannelBox->currentText()); + + // Right motor + field = obj->getField("GroundVehicleThrottle2"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvMotor2ChannelBox->currentText()); + + obj->updated(); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + // ... and compute the matrix: + // In order to make code a bit nicer, we assume: + // - Channel dropdowns start with 'None', then 0 to 7 + + // 1. Assign the servo/motor/none for each channel + + int tmpVal, ti; + + // Disable all output channels + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + + //Disable output channel + field->setValue("Disabled"); + + } + + // Set all mixer values to zero + foreach(QString mixer, mixerVectors) { + field = obj->getField(mixer); + resetField(field); + + ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("ThrottleCurve2"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(0, ti); + } + + // Motor + // Setup left motor + tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); //Set motor mixer type to Servo + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward + field->setValue(127, ti); + ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn right with increasing throttle + field->setValue(127, ti); + + // Setup right motor + tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1; + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); //Set motor mixer type to Servo + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("ThrottleCurve2"); //Set motor to full forward + field->setValue(127, ti); + ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn left with increasing throttle + field->setValue(-127, ti); + + obj->updated(); + + //Output success message + m_aircraft->gvStatusLabel->setText("Mixer generated"); + + return true; + +} + + + +/** + Setup steerable ground vehicle. + + Returns False if impossible to create the mixer. + */ +bool ConfigVehicleTypeWidget::setupGroundVehicleCar(QString airframeType) +{ + // Check coherence: + //Show any config errors in GUI + throwGroundVehicleChannelConfigError(airframeType); + + // - At least one motor and one steering servo + if ((m_aircraft->gvMotor1ChannelBox->currentText() == "None" && + m_aircraft->gvMotor2ChannelBox->currentText() == "None") || + (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && + m_aircraft->gvSteering2ChannelBox->currentText() == "None")) + { + return false; + } +// else{ +// // m_aircraft->gvStatusLabel->setText("Mixer generated"); +// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText()); +// } + + // Now setup the channels: + resetActuators(); + + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + + // Front motor + UAVObjectField *field = obj->getField("GroundVehicleThrottle1"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvMotor1ChannelBox->currentText()); + + // Rear motor + field = obj->getField("GroundVehicleThrottle2"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvMotor2ChannelBox->currentText()); + +// // Aileron +// field = obj->getField("FixedWingRoll1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); +// +// field = obj->getField("FixedWingRoll2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); + + // Front steering + field = obj->getField("GroundVehicleSteering1"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvSteering1ChannelBox->currentText()); + + // Rear steering + field = obj->getField("GroundVehicleSteering2"); + Q_ASSERT(field); + field->setValue(m_aircraft->gvSteering2ChannelBox->currentText()); + + obj->updated(); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + // ... and compute the matrix: + // In order to make code a bit nicer, we assume: + // - Channel dropdowns start with 'None', then 0 to 7 + + // 1. Assign the servo/motor/none for each channel + + int tmpVal, ti; + + // Disable all output channels + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + + //Disable output channel + field->setValue("Disabled"); + + } + + // Set all mixer values to zero + foreach(QString mixer, mixerVectors) { + field = obj->getField(mixer); + resetField(field); + + ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("ThrottleCurve2"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue(0, ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(0, ti); + } + + // Steering + // Only set front steering if it is defined + tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1; + // tmpVal will be -1 if steering is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(127, ti); + } // Else: we have no front steering. We're fine with it as long as we have rear steering + + // Only set rear steering if it is defined + tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1; + // tmpVal will be -1 if steering is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(-127, ti); + } // Else: we have no rear steering. We're fine with it as long as we have front steering + + // Motor + // Only set front motor if it is defined + tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(127, ti); + } + + // Only set rear motor if it is defined + tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1; + if (tmpVal > -1) { + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + ti = field->getElementNames().indexOf("ThrottleCurve2"); + field->setValue(127, ti); + } + + obj->updated(); + + //Output success message + m_aircraft->gvStatusLabel->setText("Mixer generated"); + + return true; +} + +/** + This function displays text and color formatting in order to help the user understand what channels have not yet been configured. + */ +void ConfigVehicleTypeWidget::throwGroundVehicleChannelConfigError(QString airframeType) +{ + //Initialize configuration error flag + bool error=false; + + + //Create a red block. All combo boxes are the same size, so any one should do as a model + int size = m_aircraft->gvEngineChannelBox->style()->pixelMetric(QStyle::PM_SmallIconSize); + QPixmap pixmap(size,size); + pixmap.fill(QColor("red")); + + if (airframeType == "GroundVehicleCar" ) { //Car + if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){ + pixmap.fill(QColor("green")); + m_aircraft->gvMotor1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes +// m_aircraft->gvMotor1Label->setText("" + m_aircraft->gvMotor1Label->text() + ""); +// m_aircraft->gvMotor2Label->setText("" + m_aircraft->gvMotor2Label->text() + ""); + error=true; + + } + else{ + m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes +// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText()); + } + + if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") { + m_aircraft->gvSteering1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + m_aircraft->gvSteering2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes +// m_aircraft->gvStatusLabel->setText("ERROR: check steering channel assignment"); +// m_aircraft->gvSteering1Label->setText("" + m_aircraft->gvSteering1Label->text() + ""); +// m_aircraft->gvSteering2Label->setText("" + m_aircraft->gvSteering2Label->text() + ""); + error=true; + } + else{ + m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes +// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText()); + } + + } else if (airframeType == "GroundVehicleDifferential"){ //Tank + if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" || m_aircraft->gvMotor2ChannelBox->currentText() == "None"){ + m_aircraft->gvMotor1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + //Always reset + m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } else if ( airframeType == "GroundVehicleMotorcycle"){ //Motorcycle + if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){ + m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") { + m_aircraft->gvSteering1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes + error=true; + } + else{ + m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + //Always reset + m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes + } + + if (error){ + m_aircraft->gvStatusLabel->setText(QString("ERROR: Assign all necessary channels")); + } +} + diff --git a/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configmultirotorwidget.cpp b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configmultirotorwidget.cpp new file mode 100644 index 000000000..2bc896be0 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/cfg_vehicletypes/configmultirotorwidget.cpp @@ -0,0 +1,1195 @@ +/** + ****************************************************************************** + * + * @file configccpmwidget.cpp + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief ccpm configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +//#include "configmultirotorwidget.h" +#include "configvehicletypewidget.h" +#include "mixersettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mixersettings.h" +#include "systemsettings.h" +#include "actuatorcommand.h" + +//#define Pi 3.14159265358979323846 + + +/** + Helper function to setup the UI + */ +void ConfigVehicleTypeWidget::setupMultiRotorUI(QString frameType) +{ + if (frameType == "Tri" || frameType == "Tricopter Y") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y")); + quad->setElementId("tri"); + + //Enable all necessary motor channel boxes... + for (int i=1; i <=3; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + //and grey out all unused motor channel boxes + for (int i=4; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(false); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(false); +// m_aircraft->multiMotorChannelBox5->setEnabled(false); +// m_aircraft->multiMotorChannelBox6->setEnabled(false); +// m_aircraft->multiMotorChannelBox7->setEnabled(false); +// m_aircraft->multiMotorChannelBox8->setEnabled(false); + m_aircraft->triYawChannelBox->setEnabled(true); + } else if (frameType == "QuadX" || frameType == "Quad X") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X")); + quad->setElementId("quad-X"); + + //Enable all necessary motor channel boxes... + for (int i=1; i <=4; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + //and grey out all unused motor channel boxes + for (int i=5; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(false); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(false); +// m_aircraft->multiMotorChannelBox6->setEnabled(false); +// m_aircraft->multiMotorChannelBox7->setEnabled(false); +// m_aircraft->multiMotorChannelBox8->setEnabled(false); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(50); + m_aircraft->mrPitchMixLevel->setValue(50); + m_aircraft->mrYawMixLevel->setValue(50); + } else if (frameType == "QuadP" || frameType == "Quad +") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +")); + quad->setElementId("quad-plus"); + + //Enable all necessary motor channel boxes... + for (int i=1; i <=4; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + //and grey out all unused motor channel boxes + for (int i=5; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(false); + } + // m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(false); +// m_aircraft->multiMotorChannelBox6->setEnabled(false); +// m_aircraft->multiMotorChannelBox7->setEnabled(false); +// m_aircraft->multiMotorChannelBox8->setEnabled(false); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(100); + m_aircraft->mrPitchMixLevel->setValue(100); + m_aircraft->mrYawMixLevel->setValue(50); + } else if (frameType == "Hexa" || frameType == "Hexacopter") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter")); + quad->setElementId("quad-hexa"); + + //Enable all necessary motor channel boxes... + for (int i=1; i <=6; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + //and grey out all unused motor channel boxes + for (int i=7; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(false); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(true); +// m_aircraft->multiMotorChannelBox6->setEnabled(true); +// m_aircraft->multiMotorChannelBox7->setEnabled(false); +// m_aircraft->multiMotorChannelBox8->setEnabled(false); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(50); + m_aircraft->mrPitchMixLevel->setValue(33); + m_aircraft->mrYawMixLevel->setValue(33); + } else if (frameType == "HexaX" || frameType == "Hexacopter X" ) { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X")); + quad->setElementId("quad-hexa-H"); + + //Enable all necessary motor channel boxes... + for (int i=1; i <=6; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + //and grey out all unused motor channel boxes + for (int i=7; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(false); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(true); +// m_aircraft->multiMotorChannelBox6->setEnabled(true); +// m_aircraft->multiMotorChannelBox7->setEnabled(false); +// m_aircraft->multiMotorChannelBox8->setEnabled(false); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(33); + m_aircraft->mrPitchMixLevel->setValue(50); + m_aircraft->mrYawMixLevel->setValue(33); + + } else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6")); + quad->setElementId("hexa-coax"); + + //Enable all necessary motor channel boxes... + for (int i=1; i <=6; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + //and grey out all unused motor channel boxes + for (int i=7; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(false); + } + + // m_aircraft->multiMotorChannelBox4->setEnabled(true); + // m_aircraft->multiMotorChannelBox5->setEnabled(true); + // m_aircraft->multiMotorChannelBox6->setEnabled(true); + // m_aircraft->multiMotorChannelBox7->setEnabled(false); + // m_aircraft->multiMotorChannelBox8->setEnabled(false); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(100); + m_aircraft->mrPitchMixLevel->setValue(50); + m_aircraft->mrYawMixLevel->setValue(66); + + } else if (frameType == "Octo" || frameType == "Octocopter") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter")); + quad->setElementId("quad-octo"); + + //Enable all necessary motor channel boxes + for (int i=1; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(true); +// m_aircraft->multiMotorChannelBox6->setEnabled(true); +// m_aircraft->multiMotorChannelBox7->setEnabled(true); +// m_aircraft->multiMotorChannelBox8->setEnabled(true); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(33); + m_aircraft->mrPitchMixLevel->setValue(33); + m_aircraft->mrYawMixLevel->setValue(25); + } else if (frameType == "OctoV" || frameType == "Octocopter V") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V")); + quad->setElementId("quad-octo-v"); + + //Enable all necessary motor channel boxes + for (int i=1; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(true); +// m_aircraft->multiMotorChannelBox6->setEnabled(true); +// m_aircraft->multiMotorChannelBox7->setEnabled(true); +// m_aircraft->multiMotorChannelBox8->setEnabled(true); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(25); + m_aircraft->mrPitchMixLevel->setValue(25); + m_aircraft->mrYawMixLevel->setValue(25); + + } else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +")); + quad->setElementId("octo-coax-P"); + + //Enable all necessary motor channel boxes + for (int i=1; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(true); +// m_aircraft->multiMotorChannelBox6->setEnabled(true); +// m_aircraft->multiMotorChannelBox7->setEnabled(true); +// m_aircraft->multiMotorChannelBox8->setEnabled(true); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(100); + m_aircraft->mrPitchMixLevel->setValue(100); + m_aircraft->mrYawMixLevel->setValue(50); + + } else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); + m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X")); + quad->setElementId("octo-coax-X"); + + //Enable all necessary motor channel boxes + for (int i=1; i <=8; i++) { + QComboBox *combobox = qFindChild(this, "multiMotorChannelBox" + QString::number(i)); + combobox->setEnabled(true); + } + +// m_aircraft->multiMotorChannelBox4->setEnabled(true); +// m_aircraft->multiMotorChannelBox5->setEnabled(true); +// m_aircraft->multiMotorChannelBox6->setEnabled(true); +// m_aircraft->multiMotorChannelBox7->setEnabled(true); +// m_aircraft->multiMotorChannelBox8->setEnabled(true); + m_aircraft->triYawChannelBox->setEnabled(false); + m_aircraft->mrRollMixLevel->setValue(50); + m_aircraft->mrPitchMixLevel->setValue(50); + m_aircraft->mrYawMixLevel->setValue(50); + + } +} + + + +/** + Helper function to update the UI widget objects + */ +QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets() +{ + QString airframeType; + QList motorList; + + // We can already setup the feedforward here, as it is common to all platforms + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("FeedForward")); + field->setDouble((double)m_aircraft->feedForwardSlider->value()/100); + field = obj->getField(QString("AccelTime")); + field->setDouble(m_aircraft->accelTime->value()); + field = obj->getField(QString("DecelTime")); + field->setDouble(m_aircraft->decelTime->value()); + field = obj->getField(QString("MaxAccel")); + field->setDouble(m_aircraft->maxAccelSlider->value()); + + // Curve is also common to all quads: + field = obj->getField("ThrottleCurve1"); + QList curve = m_aircraft->multiThrottleCurve->getCurve(); + for (int i=0;isetValue(curve.at(i),i); + } + + if (m_aircraft->multirotorFrameType->currentText() == "Quad +") { + airframeType = "QuadP"; + setupQuad(true); + } else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") { + airframeType = "QuadX"; + setupQuad(false); + } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") { + airframeType = "Hexa"; + setupHexa(true); + } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") { + airframeType = "HexaX"; + setupHexa(false); + } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") { + airframeType = "HexaCoax"; + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(6); + + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None" || + m_aircraft->multiMotorChannelBox5->currentText() == "None" || + m_aircraft->multiMotorChannelBox6->currentText() == "None" ) { + + return airframeType; + } + motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE" + << "VTOLMotorS" << "VTOLMotorSE"; + setupMotors(motorList); + + // Motor 1 to 6, Y6 Layout: + // pitch roll yaw + double mixer [8][3] = { + { 0.5, 1, -1}, + { 0.5, 1, 1}, + { 0.5, -1, -1}, + { 0.5, -1, 1}, + { -1, 0, -1}, + { -1, 0, 1}, + { 0, 0, 0}, + { 0, 0, 0} + }; + setupMultiRotorMixer(mixer); + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + + } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") { + airframeType = "Octo"; + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(8); + + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None" || + m_aircraft->multiMotorChannelBox5->currentText() == "None" || + m_aircraft->multiMotorChannelBox6->currentText() == "None" || + m_aircraft->multiMotorChannelBox7->currentText() == "None" || + m_aircraft->multiMotorChannelBox8->currentText() == "None") { + + return airframeType; + } + motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" + << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; + setupMotors(motorList); + // Motor 1 to 8: + // pitch roll yaw + double mixer [8][3] = { + { 1, 0, -1}, + { 1, -1, 1}, + { 0, -1, -1}, + { -1, -1, 1}, + { -1, 0, -1}, + { -1, 1, 1}, + { 0, 1, -1}, + { 1, 1, 1} + }; + setupMultiRotorMixer(mixer); + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + + } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") { + airframeType = "OctoV"; + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(8); + + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None" || + m_aircraft->multiMotorChannelBox5->currentText() == "None" || + m_aircraft->multiMotorChannelBox6->currentText() == "None" || + m_aircraft->multiMotorChannelBox7->currentText() == "None" || + m_aircraft->multiMotorChannelBox8->currentText() == "None") { + + return airframeType; + } + motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" + << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; + setupMotors(motorList); + // Motor 1 to 8: + // IMPORTANT: Assumes evenly spaced engines + // pitch roll yaw + double mixer [8][3] = { + { 0.33, -1, -1}, + { 1 , -1, 1}, + { -1 , -1, -1}, + { -0.33, -1, 1}, + { -0.33, 1, -1}, + { -1 , 1, 1}, + { 1 , 1, -1}, + { 0.33, 1, 1} + }; + setupMultiRotorMixer(mixer); + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + + } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") { + airframeType = "OctoCoaxP"; + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(8); + + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None" || + m_aircraft->multiMotorChannelBox5->currentText() == "None" || + m_aircraft->multiMotorChannelBox6->currentText() == "None" || + m_aircraft->multiMotorChannelBox7->currentText() == "None" || + m_aircraft->multiMotorChannelBox8->currentText() == "None") { + + return airframeType; + } + motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" + << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; + setupMotors(motorList); + // Motor 1 to 8: + // pitch roll yaw + double mixer [8][3] = { + { 1, 0, -1}, + { 1, 0, 1}, + { 0, -1, -1}, + { 0, -1, 1}, + { -1, 0, -1}, + { -1, 0, 1}, + { 0, 1, -1}, + { 0, 1, 1} + }; + setupMultiRotorMixer(mixer); + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + + } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") { + airframeType = "OctoCoaxX"; + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(8); + + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None" || + m_aircraft->multiMotorChannelBox5->currentText() == "None" || + m_aircraft->multiMotorChannelBox6->currentText() == "None" || + m_aircraft->multiMotorChannelBox7->currentText() == "None" || + m_aircraft->multiMotorChannelBox8->currentText() == "None") { + + return airframeType; + } + motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" + << "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW"; + setupMotors(motorList); + // Motor 1 to 8: + // pitch roll yaw + double mixer [8][3] = { + { 1, 1, -1}, + { 1, 1, 1}, + { 1, -1, -1}, + { 1, -1, 1}, + { -1, -1, -1}, + { -1, -1, 1}, + { -1, 1, -1}, + { -1, 1, 1} + }; + setupMultiRotorMixer(mixer); + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + + } else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") { + airframeType = "Tri"; + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(3); + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" ) { + + return airframeType; + } + if (m_aircraft->triYawChannelBox->currentText() == "None") { + m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel"); + return airframeType; + } + motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS"; + setupMotors(motorList); + obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + field = obj->getField("FixedWingYaw1"); + field->setValue(m_aircraft->triYawChannelBox->currentText()); + + // Motor 1 to 6, Y6 Layout: + // pitch roll yaw + double mixer [8][3] = { + { 0.5, 1, 0}, + { 0.5, -1, 0}, + { -1, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0} + }; + setupMultiRotorMixer(mixer); + + int tmpVal = m_aircraft->triYawChannelBox->currentIndex()-1; + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + field = obj->getField(mixerTypes.at(tmpVal)); + field->setValue("Servo"); + field = obj->getField(mixerVectors.at(tmpVal)); + resetField(field); + int ti = field->getElementNames().indexOf("Yaw"); + field->setValue(127,ti); + + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + + } + // Now reflect those settings in the "Custom" panel as well + updateCustomAirframeUI(); + + return airframeType; +} + + + +/** + Helper function to refresh the UI widget values + */ +void ConfigVehicleTypeWidget::refreshMultiRotorWidgetsValues(QString frameType) +{ + ////////////////////////////////////////////////////////////////// + // Retrieve settings + ////////////////////////////////////////////////////////////////// + + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + UAVObjectField *field; + + if (frameType == "QuadP") { + // Motors 1/2/3/4 are: N / E / S / W + field = obj->getField(QString("VTOLMotorN")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorS")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = field->getDouble(i)/1.27; + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = (1-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1; + field = obj->getField(mixerVectors.at(tmpVal)); + i = field->getElementNames().indexOf("Roll"); + val = -field->getDouble(i)/1.27; + m_aircraft->mrRollMixLevel->setValue(val); + } + } else if (frameType == "QuadX") { + // Motors 1/2/3/4 are: NW / NE / SE / SW + field = obj->getField(QString("VTOLMotorNW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = field->getDouble(i)/1.27; + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = 1-field->getDouble(i)/1.27; + m_aircraft->mrYawMixLevel->setValue(val); + i = field->getElementNames().indexOf("Roll"); + val = field->getDouble(i)/1.27; + m_aircraft->mrRollMixLevel->setValue(val); + } + } else if (frameType == "Hexa") { + // Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW + field = obj->getField(QString("VTOLMotorN")); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNE")); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSE")); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorS")); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSW")); + m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNW")); + m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1; + if(tmpVal>-1) + { + field = obj->getField(mixerVectors.at(tmpVal)); + i = field->getElementNames().indexOf("Roll"); + val = floor(1-field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } + } + } else if (frameType == "HexaX") { + // Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW + field = obj->getField(QString("VTOLMotorNE")); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorE")); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSE")); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSW")); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorW")); + m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNW")); + m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1; + field = obj->getField(mixerVectors.at(tmpVal)); + i = field->getElementNames().indexOf("Roll"); + val = floor(1-field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } + } else if (frameType == "HexaCoax") { + // Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE + field = obj->getField(QString("VTOLMotorNW")); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorW")); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNE")); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorE")); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorS")); + m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSE")); + m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(2*field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + i = field->getElementNames().indexOf("Roll"); + val = floor(field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } + } else if (frameType == "Octo" || frameType == "OctoV" || + frameType == "OctoCoaxP") { + // Motors 1 to 8 are N / NE / E / etc + field = obj->getField(QString("VTOLMotorN")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorS")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + if (frameType == "Octo") { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1; + field = obj->getField(mixerVectors.at(tmpVal)); + i = field->getElementNames().indexOf("Roll"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } else if (frameType == "OctoV") { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Yaw"); + double val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + i = field->getElementNames().indexOf("Roll"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1; + field = obj->getField(mixerVectors.at(tmpVal)); + i = field->getElementNames().indexOf("Pitch"); + val = floor(field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + + } else if (frameType == "OctoCoaxP") { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + tmpVal = m_aircraft->multiMotorChannelBox3->currentIndex()-1; + field = obj->getField(mixerVectors.at(tmpVal)); + i = field->getElementNames().indexOf("Roll"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + + } + } + } else if (frameType == "OctoCoaxX") { + // Motors 1 to 8 are N / NE / E / etc + field = obj->getField(QString("VTOLMotorNW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorN")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorS")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorSW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString())); + + // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. + // This assumes that all vectors are identical - if not, the user should use the + // "custom" setting. + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Yaw"); + val = floor(-field->getDouble(i)/1.27); + m_aircraft->mrYawMixLevel->setValue(val); + i = field->getElementNames().indexOf("Roll"); + val = floor(field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } + } else if (frameType == "Tri") { + // Motors 1 to 8 are N / NE / E / etc + field = obj->getField(QString("VTOLMotorNW")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorNE")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString())); + field = obj->getField(QString("VTOLMotorS")); + Q_ASSERT(field); + m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + field = obj->getField(QString("FixedWingYaw1")); + Q_ASSERT(field); + m_aircraft->triYawChannelBox->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString())); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1; + // tmpVal will be -1 if value is set to "None" + if (tmpVal > -1) { + field = obj->getField(mixerVectors.at(tmpVal)); + int i = field->getElementNames().indexOf("Pitch"); + double val = floor(2*field->getDouble(i)/1.27); + m_aircraft->mrPitchMixLevel->setValue(val); + i = field->getElementNames().indexOf("Roll"); + val = floor(field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } + } +} + + + +/** + Helper function: setupQuadMotor + */ +void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw) +{ + qDebug()<(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + UAVObjectField *field = obj->getField(mixerTypes.at(channel)); + field->setValue("Motor"); + field = obj->getField(mixerVectors.at(channel)); + // First of all reset the vector + resetField(field); + int ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(127, ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(roll*127,ti); + qDebug()<<"Set roll="<getElementNames().indexOf("Pitch"); + field->setValue(pitch*127,ti); + qDebug()<<"Set pitch="<getElementNames().indexOf("Yaw"); + field->setValue(yaw*127,ti); + qDebug()<<"Set yaw="< motorList) +{ + resetActuators(); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + UAVObjectField *field; + QList mmList; + mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3 + << m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6 + << m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8; + foreach (QString motor, motorList) { + field = obj->getField(motor); + field->setValue(mmList.takeFirst()->currentText()); + } + //obj->updated(); // Save... +} + + + +/** + Set up a Quad-X or Quad-P mixer + */ +bool ConfigVehicleTypeWidget::setupQuad(bool pLayout) +{ + // Check coherence: + + //Show any config errors in GUI + throwMultiRotorChannelConfigError(4); + + // - Four engines have to be defined + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None") { + + return false; + } + + + QList motorList; + if (pLayout) { + motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS" + << "VTOLMotorW"; + } else { + motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE" + << "VTOLMotorSW"; + } + setupMotors(motorList); + + // Now, setup the mixer: + // Motor 1 to 4, X Layout: + // pitch roll yaw + // {0.5 ,0.5 ,-0.5 //Front left motor (CW) + // {0.5 ,-0.5 ,0.5 //Front right motor(CCW) + // {-0.5 ,-0.5 ,-0.5 //rear right motor (CW) + // {-0.5 ,0.5 ,0.5 //Rear left motor (CCW) + double xMixer [8][3] = { + { 1, 1, -1}, + { 1, -1, 1}, + {-1, -1, -1}, + {-1, 1, 1}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0} + }; + // + // Motor 1 to 4, P Layout: + // pitch roll yaw + // {1 ,0 ,-0.5 //Front motor (CW) + // {0 ,-1 ,0.5 //Right motor(CCW) + // {-1 ,0 ,-0.5 //Rear motor (CW) + // {0 ,1 ,0.5 //Left motor (CCW) + double pMixer [8][3] = { + { 1, 0, -1}, + { 0, -1, 1}, + {-1, 0, -1}, + { 0, 1, 1}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0} + }; + + if (pLayout) { + setupMultiRotorMixer(pMixer); + } else { + setupMultiRotorMixer(xMixer); + } + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + return true; +} + + + +/** + Set up a Hexa-X or Hexa-P mixer + */ +bool ConfigVehicleTypeWidget::setupHexa(bool pLayout) +{ + // Check coherence: + //Show any config errors in GUI + throwMultiRotorChannelConfigError(6); + + // - Four engines have to be defined + if (m_aircraft->multiMotorChannelBox1->currentText() == "None" || + m_aircraft->multiMotorChannelBox2->currentText() == "None" || + m_aircraft->multiMotorChannelBox3->currentText() == "None" || + m_aircraft->multiMotorChannelBox4->currentText() == "None" || + m_aircraft->multiMotorChannelBox5->currentText() == "None" || + m_aircraft->multiMotorChannelBox6->currentText() == "None") { + + return false; + } + + QList motorList; + if (pLayout) { + motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE" + << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW"; + } else { + motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" + << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; + } + setupMotors(motorList); + + // and set only the relevant channels: + + // Motor 1 to 6, P Layout: + // pitch roll yaw + // 1 { 0.3 , 0 ,-0.3 // N CW + // 2 { 0.3 ,-0.5 , 0.3 // NE CCW + // 3 {-0.3 ,-0.5 ,-0.3 // SE CW + // 4 {-0.3 , 0 , 0.3 // S CCW + // 5 {-0.3 , 0.5 ,-0.3 // SW CW + // 6 { 0.3 , 0.5 , 0.3 // NW CCW + + double pMixer [8][3] = { + { 1, 0, -1}, + { 1, -1, 1}, + {-1, -1, -1}, + {-1, 0, 1}, + {-1, 1, -1}, + { 1, 1, 1}, + { 0, 0, 0}, + { 0, 0, 0} + }; + + // + // Motor 1 to 6, X Layout: + // 1 [ 0.5, -0.3, -0.3 ] NE + // 2 [ 0 , -0.3, 0.3 ] E + // 3 [ -0.5, -0.3, -0.3 ] SE + // 4 [ -0.5, 0.3, 0.3 ] SW + // 5 [ 0 , 0.3, -0.3 ] W + // 6 [ 0.5, 0.3, 0.3 ] NW + double xMixer [8][3] = { + { 1, -1, -1}, + { 0, -1, 1}, + { -1, -1, -1}, + { -1, 1, 1}, + { 0, 1, -1}, + { 1, 1, 1}, + { 0, 0, 0}, + { 0, 0, 0} + }; + + if (pLayout) { + setupMultiRotorMixer(pMixer); + } else { + setupMultiRotorMixer(xMixer); + } + m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); + return true; +} + + +/** + This function sets up the multirotor mixer values. + */ +bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3]) +{ + qDebug()<<"Mixer factors"; + qDebug()< mmList; + mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3 + << m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6 + << m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8; + UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + // 1. Assign the servo/motor/none for each channel + // Disable all + foreach(QString mixer, mixerTypes) { + field = obj->getField(mixer); + Q_ASSERT(field); + field->setValue("Disabled"); + } + // and enable only the relevant channels: + double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100; + double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100; + double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100; + qDebug()<isEnabled()) + { + int channel = mmList.at(i)->currentIndex()-1; + if (channel > -1) + setupQuadMotor(channel, mixerFactors[i][0]*pFactor, + rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]); + } + } + // obj->updated(); + return true; +} + + +/** + This function displays text and color formatting in order to help the user understand what channels have not yet been configured. + */ +void ConfigVehicleTypeWidget::throwMultiRotorChannelConfigError(int numMotors) +{ + //Initialize configuration error flag + bool error=false; + + //Iterate through all instances of multiMotorChannelBox + for (int i=0; i(this, "multiMotorChannelBox" + QString::number(i+1)); + if (combobox){ //if QLabel exists + QLabel *label = qFindChild(this, "MotorOutputLabel" + QString::number(i+1)); + if (combobox->currentText() == "None") { + +// label->setText("" + label->text() + ""); + + int size = combobox->style()->pixelMetric(QStyle::PM_SmallIconSize); + QPixmap pixmap(size,size); + pixmap.fill(QColor("red")); + combobox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes +// combobox->setStyleSheet("QComboBox { color: red}"); + error=true; + + } + else { + combobox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes +// combobox->setStyleSheet("color: black;"); +// QTextEdit* htmlText=new QTextEdit(label->text()); // htmlText is any QString with html tags. +// label->setText(htmlText->toPlainText()); + } + } + } + + + if (error){ + m_aircraft->mrStatusLabel->setText(QString("ERROR: Assign all %1 motor channels").arg(numMotors)); + } +} \ No newline at end of file diff --git a/ground/openpilotgcs/src/plugins/config/config.pro b/ground/openpilotgcs/src/plugins/config/config.pro index 990ecfe56..52a2b394a 100644 --- a/ground/openpilotgcs/src/plugins/config/config.pro +++ b/ground/openpilotgcs/src/plugins/config/config.pro @@ -4,7 +4,9 @@ DEFINES += CONFIG_LIBRARY QT += svg include(config_dependencies.pri) INCLUDEPATH += ../../libs/eigen + OTHER_FILES += Config.pluginspec + HEADERS += configplugin.h \ configgadgetconfiguration.h \ configgadgetwidget.h \ @@ -14,12 +16,12 @@ HEADERS += configplugin.h \ fancytabwidget.h \ configinputwidget.h \ configoutputwidget.h \ - configairframewidget.h \ + configvehicletypewidget.h \ config_pro_hw_widget.h \ config_cc_hw_widget.h \ configahrswidget.h \ configccattitudewidget.h \ - configccpmwidget.h \ + cfg_vehicletypes/configccpmwidget.h \ configstabilizationwidget.h \ assertions.h \ calibration.h \ @@ -39,12 +41,11 @@ SOURCES += configplugin.cpp \ fancytabwidget.cpp \ configinputwidget.cpp \ configoutputwidget.cpp \ - configairframewidget.cpp \ + configvehicletypewidget.cpp \ config_pro_hw_widget.cpp \ config_cc_hw_widget.cpp \ configahrswidget.cpp \ configccattitudewidget.cpp \ - configccpmwidget.cpp \ configstabilizationwidget.cpp \ twostep.cpp \ legacy-calibration.cpp \ @@ -55,6 +56,10 @@ SOURCES += configplugin.cpp \ inputchannelform.cpp \ configcamerastabilizationwidget.cpp \ configtxpidwidget.cpp \ + cfg_vehicletypes/configmultirotorwidget.cpp \ + cfg_vehicletypes/configgroundvehiclewidget.cpp \ + cfg_vehicletypes/configfixedwingwidget.cpp \ + cfg_vehicletypes/configccpmwidget.cpp \ outputchannelform.cpp FORMS += airframe.ui \ cc_hw_settings.ui \ diff --git a/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp b/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp deleted file mode 100644 index 6390cec0e..000000000 --- a/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp +++ /dev/null @@ -1,2221 +0,0 @@ -/** - ****************************************************************************** - * - * @file configairframewidget.cpp - * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup ConfigPlugin Config Plugin - * @{ - * @brief Airframe configuration panel - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "configairframewidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "systemsettings.h" -#include "mixersettings.h" -#include "actuatorsettings.h" -#include - -/** - Helper delegate for the custom mixer editor table. - Taken straight from Qt examples, thanks! - */ -SpinBoxDelegate::SpinBoxDelegate(QObject *parent) - : QItemDelegate(parent) - { - } - -QWidget *SpinBoxDelegate::createEditor(QWidget *parent, - const QStyleOptionViewItem &/* option */, - const QModelIndex &/* index */) const -{ - QSpinBox *editor = new QSpinBox(parent); - editor->setMinimum(-127); - editor->setMaximum(127); - - return editor; -} - -void SpinBoxDelegate::setEditorData(QWidget *editor, - const QModelIndex &index) const -{ - int value = index.model()->data(index, Qt::EditRole).toInt(); - - QSpinBox *spinBox = static_cast(editor); - spinBox->setValue(value); -} - -void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, - const QModelIndex &index) const -{ - QSpinBox *spinBox = static_cast(editor); - spinBox->interpretText(); - int value = spinBox->value(); - - model->setData(index, value, Qt::EditRole); -} - -void SpinBoxDelegate::updateEditorGeometry(QWidget *editor, - const QStyleOptionViewItem &option, const QModelIndex &/* index */) const -{ - editor->setGeometry(option.rect); -} - -/**********************************************************************************/ - - - -ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(parent) -{ - m_aircraft = new Ui_AircraftWidget(); - m_aircraft->setupUi(this); - - addApplySaveButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD); - - addUAVObject("SystemSettings"); - addUAVObject("MixerSettings"); - addUAVObject("ActuatorSettings"); - - - ffTuningInProgress = false; - ffTuningPhase = false; - - QStringList channels; - channels << "None"; - for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) { - mixerTypes << QString("Mixer%1Type").arg(i+1); - mixerVectors << QString("Mixer%1Vector").arg(i+1); - channels << QString("Channel%1").arg(i+1); - } - - QStringList airframeTypes; - airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Custom"; - m_aircraft->aircraftType->addItems(airframeTypes); - m_aircraft->aircraftType->setCurrentIndex(1); - - QStringList fixedWingTypes; - fixedWingTypes << "Elevator aileron rudder" << "Elevon" << "Vtail"; - m_aircraft->fixedWingType->addItems(fixedWingTypes); - - QStringList multiRotorTypes; - multiRotorTypes << "Quad +" << "Quad X" << "Hexacopter" << "Octocopter" << "Hexacopter X" << "Octocopter V" << "Octo Coax +" - << "Octo Coax X" << "Hexacopter Y6" << "Tricopter Y"; - m_aircraft->multirotorFrameType->addItems(multiRotorTypes); - - // Now load all the channel assignements for fixed wing - m_aircraft->fwElevator1Channel->addItems(channels); - m_aircraft->fwElevator2Channel->addItems(channels); - m_aircraft->fwEngineChannel->addItems(channels); - m_aircraft->fwRudder1Channel->addItems(channels); - m_aircraft->fwRudder2Channel->addItems(channels); - m_aircraft->fwAileron1Channel->addItems(channels); - m_aircraft->fwAileron2Channel->addItems(channels); - m_aircraft->multiMotor1->addItems(channels); - m_aircraft->multiMotor2->addItems(channels); - m_aircraft->multiMotor3->addItems(channels); - m_aircraft->multiMotor4->addItems(channels); - m_aircraft->multiMotor5->addItems(channels); - m_aircraft->multiMotor6->addItems(channels); - m_aircraft->multiMotor7->addItems(channels); - m_aircraft->multiMotor8->addItems(channels); - m_aircraft->triYawChannel->addItems(channels); - - // Setup the Multirotor picture in the Quad settings interface - m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_aircraft->quadShape->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - QSvgRenderer *renderer = new QSvgRenderer(); - renderer->load(QString(":/configgadget/images/quad-shapes.svg")); - quad = new QGraphicsSvgItem(); - quad->setSharedRenderer(renderer); - quad->setElementId("quad-plus"); - QGraphicsScene *scene = new QGraphicsScene(this); - scene->addItem(quad); - scene->setSceneRect(quad->boundingRect()); - m_aircraft->quadShape->setScene(scene); - - // Put combo boxes in line one of the custom mixer table: - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("Mixer1Type")); - QStringList list = field->getOptions(); - for (int i=0;i<8;i++) { - QComboBox* qb = new QComboBox(m_aircraft->customMixerTable); - qb->addItems(list); - m_aircraft->customMixerTable->setCellWidget(0,i,qb); - } - - SpinBoxDelegate *sbd = new SpinBoxDelegate(); - for (int i=1;i<8; i++) { - m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd); - } - - connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); - connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); - connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int))); - - connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer())); - connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer())); - connect(m_aircraft->customReset1, SIGNAL(clicked()), this, SLOT(resetCt1Mixer())); - connect(m_aircraft->customReset2, SIGNAL(clicked()), this, SLOT(resetCt2Mixer())); - connect(m_aircraft->fixedWingThrottle, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateFwThrottleCurveValue(QList,double))); - connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateMrThrottleCurveValue(QList,double))); - connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateCustomThrottle1CurveValue(QList,double))); - connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateCustomThrottle2CurveValue(QList,double))); - -// connect(m_aircraft->fwAileron1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleAileron2(int))); -// connect(m_aircraft->fwElevator1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleElevator2(int))); - - // Now connect the three feed forward test checkboxes - connect(m_aircraft->ffTestBox1, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); - connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); - connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); - - enableControls(false); - refreshWidgetsValues(); - - - // Connect the help button - connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp())); - addToDirtyMonitor(); -} - -ConfigAirframeWidget::~ConfigAirframeWidget() -{ - // Do nothing -} - -/** - Slot for switching the airframe type. We do it explicitely - rather than a signal in the UI, because we want to force a fitInView of the quad shapes. - This is because this method (fitinview) only works when the widget is shown. - */ -void ConfigAirframeWidget::switchAirframeType(int index){ - m_aircraft->airframesWidget->setCurrentIndex(index); - m_aircraft->quadShape->setSceneRect(quad->boundingRect()); - m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); - if (m_aircraft->aircraftType->findText("Custom")) { - m_aircraft->customMixerTable->resizeColumnsToContents(); - for (int i=0;i<8;i++) { - m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()- - m_aircraft->customMixerTable->verticalHeader()->width())/8); - } - } -} - -void ConfigAirframeWidget::showEvent(QShowEvent *event) -{ - Q_UNUSED(event) - // Thit fitInView method should only be called now, once the - // widget is shown, otherwise it cannot compute its values and - // the result is usually a ahrsbargraph that is way too small. - m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); - m_aircraft->customMixerTable->resizeColumnsToContents(); - for (int i=0;i<8;i++) { - m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()- - m_aircraft->customMixerTable->verticalHeader()->width())/8); - } -} - -void ConfigAirframeWidget::resizeEvent(QResizeEvent* event) -{ - Q_UNUSED(event); - m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); - // Make the custom table columns autostretch: - m_aircraft->customMixerTable->resizeColumnsToContents(); - for (int i=0;i<8;i++) { - m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()- - m_aircraft->customMixerTable->verticalHeader()->width())/8); - } - -} - - -void ConfigAirframeWidget::toggleAileron2(int index) -{ - if (index) { - m_aircraft->fwAileron2Channel->setEnabled(true); - m_aircraft->fwAileron2Label->setEnabled(true); - } else { - m_aircraft->fwAileron2Channel->setEnabled(false); - m_aircraft->fwAileron2Label->setEnabled(false); - } -} - -void ConfigAirframeWidget::toggleElevator2(int index) -{ - if (index) { - m_aircraft->fwElevator2Channel->setEnabled(true); - m_aircraft->fwElevator2Label->setEnabled(true); - } else { - m_aircraft->fwElevator2Channel->setEnabled(false); - m_aircraft->fwElevator2Label->setEnabled(false); - } -} - -void ConfigAirframeWidget::toggleRudder2(int index) -{ - if (index) { - m_aircraft->fwRudder2Channel->setEnabled(true); - m_aircraft->fwRudder2Label->setEnabled(true); - } else { - m_aircraft->fwRudder2Channel->setEnabled(false); - m_aircraft->fwRudder2Label->setEnabled(false); - } -} - -///////////////////////////////////////////////////////// -/// Feed Forward Testing -///////////////////////////////////////////////////////// - -/** - Enables and runs feed forward testing - */ -void ConfigAirframeWidget::enableFFTest() -{ - // Role: - // - Check if all three checkboxes are checked - // - Every other timer event: toggle engine from 45% to 55% - // - Every other time event: send FF settings to flight FW - if (m_aircraft->ffTestBox1->isChecked() && - m_aircraft->ffTestBox2->isChecked() && - m_aircraft->ffTestBox3->isChecked()) { - if (!ffTuningInProgress) - { - // Initiate tuning: - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlCommand"))); - UAVObject::Metadata mdata = obj->getMetadata(); - accInitialData = mdata; - mdata.flightAccess = UAVObject::ACCESS_READONLY; - obj->setMetadata(mdata); - } - // Depending on phase, either move actuator or send FF settings: - if (ffTuningPhase) { - // Send FF settings to the board - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("FeedForward")); - field->setDouble((double)m_aircraft->feedForwardSlider->value()/100); - field = obj->getField(QString("AccelTime")); - field->setDouble(m_aircraft->accelTime->value()); - field = obj->getField(QString("DecelTime")); - field->setDouble(m_aircraft->decelTime->value()); - field = obj->getField(QString("MaxAccel")); - field->setDouble(m_aircraft->maxAccelSlider->value()); - obj->updated(); - } else { - // Toggle motor state - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlCommand"))); - double value = obj->getField("Throttle")->getDouble(); - double target = (value < 0.5) ? 0.55 : 0.45; - obj->getField("Throttle")->setValue(target); - obj->updated(); - } - ffTuningPhase = !ffTuningPhase; - ffTuningInProgress = true; - QTimer::singleShot(1000, this, SLOT(enableFFTest())); - } else { - // - If no: disarm timer, restore actuatorcommand metadata - // Disarm! - if (ffTuningInProgress) { - ffTuningInProgress = false; - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlCommand"))); - UAVObject::Metadata mdata = obj->getMetadata(); - mdata = accInitialData; // Restore metadata - obj->setMetadata(mdata); - } - } -} - - -/** - Resets Fixed wing throttle mixer - */ -void ConfigAirframeWidget::resetFwMixer() -{ - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1); -} - -/** - Resets Multirotor throttle mixer - */ -void ConfigAirframeWidget::resetMrMixer() -{ - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9); -} - -/** - Resets Custom throttle 1 mixer - */ -void ConfigAirframeWidget::resetCt1Mixer() -{ - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1); -} - -/** - Resets Custom throttle 2 mixer - */ -void ConfigAirframeWidget::resetCt2Mixer() -{ - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("ThrottleCurve2")); - resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1); -} - - -/** - Resets a mixer curve - */ -void ConfigAirframeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue) -{ - // Setup all Throttle1 curves for all types of airframes - mixer->initLinearCurve((quint32)numElements,maxvalue); -} - -/** - Updates the currently moved throttle curve item value - */ -void ConfigAirframeWidget::updateFwThrottleCurveValue(QList list, double value) -{ - Q_UNUSED(list); - m_aircraft->fwThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value)); -} - -/** - Updates the currently moved throttle curve item value - */ -void ConfigAirframeWidget::updateMrThrottleCurveValue(QList list, double value) -{ - Q_UNUSED(list); - m_aircraft->mrThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value)); -} - -/** - Updates the currently moved throttle curve item value (Custom throttle 1) - */ -void ConfigAirframeWidget::updateCustomThrottle1CurveValue(QList list, double value) -{ - Q_UNUSED(list); - m_aircraft->customThrottleCurve1Value->setText(QString().sprintf("Val: %.2f",value)); -} - -/** - Updates the currently moved throttle curve item value (Custom throttle 2) - */ -void ConfigAirframeWidget::updateCustomThrottle2CurveValue(QList list, double value) -{ - Q_UNUSED(list); - m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value)); -} - - -/************************** - * Aircraft settings - **************************/ -/** - Refreshes the current value of the SystemSettings which holds the aircraft type - */ -void ConfigAirframeWidget::refreshWidgetsValues() -{ - if(!allObjectsUpdated()) - return; - bool dirty=isDirty(); - // Get the Airframe type from the system settings: - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); - Q_ASSERT(obj); - UAVObjectField *field = obj->getField(QString("AirframeType")); - Q_ASSERT(field); - // At this stage, we will need to have some hardcoded settings in this code, this - // is not ideal, but here you go. - QString frameType = field->getValue().toString(); - setupAirframeUI(frameType); - - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - field = obj->getField(QString("ThrottleCurve1")); - Q_ASSERT(field); - QList curveValues; - // If the 1st element of the curve is <= -10, then the curve - // is a straight line (that's how the mixer works on the mainboard): - if (field->getValue(0).toInt() <= -10) { - m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1); - m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1); - } - else { - double temp=0; - double value; - for (unsigned int i=0; i < field->getNumElements(); i++) { - value=field->getValue(i).toDouble(); - temp+=value; - curveValues.append(value); - } - if(temp==0) - { - m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);; - m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1); - } - else - { - m_aircraft->multiThrottleCurve->initCurve(curveValues); - m_aircraft->fixedWingThrottle->initCurve(curveValues); - } - } - // Setup all Throttle1 curves for all types of airframes - // Load the Settings for fixed wing frames: - if (frameType.startsWith("FixedWing")) { - // Then retrieve how channels are setup - obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - field = obj->getField(QString("FixedWingThrottle")); - Q_ASSERT(field); - m_aircraft->fwEngineChannel->setCurrentIndex(m_aircraft->fwEngineChannel->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingRoll1")); - Q_ASSERT(field); - m_aircraft->fwAileron1Channel->setCurrentIndex(m_aircraft->fwAileron1Channel->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingRoll2")); - Q_ASSERT(field); - m_aircraft->fwAileron2Channel->setCurrentIndex(m_aircraft->fwAileron2Channel->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingPitch1")); - Q_ASSERT(field); - m_aircraft->fwElevator1Channel->setCurrentIndex(m_aircraft->fwElevator1Channel->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingPitch2")); - Q_ASSERT(field); - m_aircraft->fwElevator2Channel->setCurrentIndex(m_aircraft->fwElevator2Channel->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingYaw1")); - Q_ASSERT(field); - m_aircraft->fwRudder1Channel->setCurrentIndex(m_aircraft->fwRudder1Channel->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingYaw2")); - Q_ASSERT(field); - m_aircraft->fwRudder2Channel->setCurrentIndex(m_aircraft->fwRudder2Channel->findText(field->getValue().toString())); - - if (frameType == "FixedWingElevon") { - // If the airframe is elevon, restore the slider setting - // Find the channel number for Elevon1 (FixedWingRoll1) - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - int chMixerNumber = m_aircraft->fwAileron1Channel->currentIndex()-1; - if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check. - field = obj->getField(mixerVectors.at(chMixerNumber)); - int ti = field->getElementNames().indexOf("Roll"); - m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100); - ti = field->getElementNames().indexOf("Pitch"); - m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100); - } - } - if (frameType == "FixedWingVtail") { - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - int chMixerNumber = m_aircraft->fwElevator1Channel->currentIndex()-1; - if (chMixerNumber >=0) { - field = obj->getField(mixerVectors.at(chMixerNumber)); - int ti = field->getElementNames().indexOf("Yaw"); - m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100); - ti = field->getElementNames().indexOf("Pitch"); - m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100); - } - } - - } else if (frameType == "QuadX" || frameType == "QuadP" || - frameType == "Hexa" || frameType == "Octo" || - frameType == "HexaCoax" || frameType == "OctoV" || - frameType == "HexaX" || frameType == "OctoCoaxP" || - frameType == "OctoCoaxX" || frameType == "Tri") { - ////////////////////////////////////////////////////////////////// - // Retrieve Multirotor settings - ////////////////////////////////////////////////////////////////// - - obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - if (frameType == "QuadP") { - // Motors 1/2/3/4 are: N / E / S / W - field = obj->getField(QString("VTOLMotorN")); - Q_ASSERT(field); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorE")); - Q_ASSERT(field); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorS")); - Q_ASSERT(field); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorW")); - Q_ASSERT(field); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = field->getDouble(i)/1.27; - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = (1-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - eng = m_aircraft->multiMotor2->currentIndex()-1; - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Roll"); - val = -field->getDouble(i)/1.27; - m_aircraft->mrRollMixLevel->setValue(val); - } - } else if (frameType == "QuadX") { - // Motors 1/2/3/4 are: NW / NE / SE / SW - field = obj->getField(QString("VTOLMotorNW")); - Q_ASSERT(field); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNE")); - Q_ASSERT(field); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSE")); - Q_ASSERT(field); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSW")); - Q_ASSERT(field); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = field->getDouble(i)/1.27; - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = 1-field->getDouble(i)/1.27; - m_aircraft->mrYawMixLevel->setValue(val); - i = field->getElementNames().indexOf("Roll"); - val = field->getDouble(i)/1.27; - m_aircraft->mrRollMixLevel->setValue(val); - } - } else if (frameType == "Hexa") { - // Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW - field = obj->getField(QString("VTOLMotorN")); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNE")); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSE")); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorS")); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSW")); - m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNW")); - m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - eng = m_aircraft->multiMotor2->currentIndex()-1; - if(eng>-1) - { - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Roll"); - val = floor(1-field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - } - } - } else if (frameType == "HexaX") { - // Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW - field = obj->getField(QString("VTOLMotorNE")); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorE")); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSE")); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSW")); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorW")); - m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNW")); - m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - eng = m_aircraft->multiMotor2->currentIndex()-1; - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Roll"); - val = floor(1-field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - } - } else if (frameType == "HexaCoax") { - // Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE - field = obj->getField(QString("VTOLMotorNW")); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorW")); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNE")); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorE")); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorS")); - m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSE")); - m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(2*field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - i = field->getElementNames().indexOf("Roll"); - val = floor(field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - } - } else if (frameType == "Octo" || frameType == "OctoV" || - frameType == "OctoCoaxP") { - // Motors 1 to 8 are N / NE / E / etc - field = obj->getField(QString("VTOLMotorN")); - Q_ASSERT(field); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNE")); - Q_ASSERT(field); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorE")); - Q_ASSERT(field); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSE")); - Q_ASSERT(field); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorS")); - Q_ASSERT(field); - m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSW")); - Q_ASSERT(field); - m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorW")); - Q_ASSERT(field); - m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNW")); - Q_ASSERT(field); - m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - if (frameType == "Octo") { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - eng = m_aircraft->multiMotor2->currentIndex()-1; - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Roll"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - } else if (frameType == "OctoV") { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Yaw"); - double val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - i = field->getElementNames().indexOf("Roll"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - eng = m_aircraft->multiMotor2->currentIndex()-1; - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Pitch"); - val = floor(field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - - } else if (frameType == "OctoCoaxP") { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - eng = m_aircraft->multiMotor3->currentIndex()-1; - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Roll"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - - } - } - } else if (frameType == "OctoCoaxX") { - // Motors 1 to 8 are N / NE / E / etc - field = obj->getField(QString("VTOLMotorNW")); - Q_ASSERT(field); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorN")); - Q_ASSERT(field); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNE")); - Q_ASSERT(field); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorE")); - Q_ASSERT(field); - m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSE")); - Q_ASSERT(field); - m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorS")); - Q_ASSERT(field); - m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorSW")); - Q_ASSERT(field); - m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorW")); - Q_ASSERT(field); - m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); - // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. - // This assumes that all vectors are identical - if not, the user should use the - // "custom" setting. - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Yaw"); - val = floor(-field->getDouble(i)/1.27); - m_aircraft->mrYawMixLevel->setValue(val); - i = field->getElementNames().indexOf("Roll"); - val = floor(field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - } - } else if (frameType == "Tri") { - // Motors 1 to 8 are N / NE / E / etc - field = obj->getField(QString("VTOLMotorNW")); - Q_ASSERT(field); - m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorNE")); - Q_ASSERT(field); - m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); - field = obj->getField(QString("VTOLMotorS")); - Q_ASSERT(field); - m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - field = obj->getField(QString("FixedWingYaw1")); - Q_ASSERT(field); - m_aircraft->triYawChannel->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); - - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - int eng= m_aircraft->multiMotor1->currentIndex()-1; - // eng will be -1 if value is set to "None" - if (eng > -1) { - field = obj->getField(mixerVectors.at(eng)); - int i = field->getElementNames().indexOf("Pitch"); - double val = floor(2*field->getDouble(i)/1.27); - m_aircraft->mrPitchMixLevel->setValue(val); - i = field->getElementNames().indexOf("Roll"); - val = floor(field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); - } - - } - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - // Now, retrieve the Feedforward values: - field = obj->getField(QString("FeedForward")); - Q_ASSERT(field); - m_aircraft->feedForwardSlider->setValue(field->getDouble()*100); - field = obj->getField(QString("AccelTime")); - Q_ASSERT(field); - m_aircraft->accelTime->setValue(field->getDouble()); - field = obj->getField(QString("DecelTime")); - Q_ASSERT(field); - m_aircraft->decelTime->setValue(field->getDouble()); - field = obj->getField(QString("MaxAccel")); - Q_ASSERT(field); - m_aircraft->maxAccelSlider->setValue(field->getDouble()); - - } else if (frameType == "HeliCP") { - m_aircraft->widget_3->requestccpmUpdate(); - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter" - } else if (frameType == "Custom") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom")); - } - - updateCustomAirframeUI(); - setDirty(dirty); -} - -/** - \brief Sets up the mixer depending on Airframe type. Accepts either system settings or - combo box entry from airframe type, as those do not overlap. - */ -void ConfigAirframeWidget::setupAirframeUI(QString frameType) -{ - bool dirty=isDirty(); - if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") { - // Setup the UI - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); - m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder")); - m_aircraft->fwRudder1Channel->setEnabled(true); - m_aircraft->fwRudder1Label->setEnabled(true); - m_aircraft->fwRudder2Channel->setEnabled(true); - m_aircraft->fwRudder2Label->setEnabled(true); - m_aircraft->fwElevator1Channel->setEnabled(true); - m_aircraft->fwElevator1Label->setEnabled(true); - m_aircraft->fwElevator2Channel->setEnabled(true); - m_aircraft->fwElevator2Label->setEnabled(true); - m_aircraft->fwAileron1Channel->setEnabled(true); - m_aircraft->fwAileron1Label->setEnabled(true); - m_aircraft->fwAileron2Channel->setEnabled(true); - m_aircraft->fwAileron2Label->setEnabled(true); - - m_aircraft->fwAileron1Label->setText("Aileron 1"); - m_aircraft->fwAileron2Label->setText("Aileron 2"); - m_aircraft->fwElevator1Label->setText("Elevator 1"); - m_aircraft->fwElevator2Label->setText("Elevator 2"); - m_aircraft->elevonMixBox->setHidden(true); - - } else if (frameType == "FixedWingElevon" || frameType == "Elevon") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); - m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon")); - m_aircraft->fwAileron1Label->setText("Elevon 1"); - m_aircraft->fwAileron2Label->setText("Elevon 2"); - m_aircraft->fwElevator1Channel->setEnabled(false); - m_aircraft->fwElevator1Label->setEnabled(false); - m_aircraft->fwElevator2Channel->setEnabled(false); - m_aircraft->fwElevator2Label->setEnabled(false); - m_aircraft->fwRudder1Channel->setEnabled(true); - m_aircraft->fwRudder1Label->setEnabled(true); - m_aircraft->fwRudder2Channel->setEnabled(true); - m_aircraft->fwRudder2Label->setEnabled(true); - m_aircraft->fwElevator1Label->setText("Elevator 1"); - m_aircraft->fwElevator2Label->setText("Elevator 2"); - m_aircraft->elevonMixBox->setHidden(false); - m_aircraft->elevonLabel1->setText("Roll"); - m_aircraft->elevonLabel2->setText("Pitch"); - - } else if (frameType == "FixedWingVtail" || frameType == "Vtail") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); - m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail")); - m_aircraft->fwRudder1Channel->setEnabled(false); - m_aircraft->fwRudder1Label->setEnabled(false); - m_aircraft->fwRudder2Channel->setEnabled(false); - m_aircraft->fwRudder2Label->setEnabled(false); - m_aircraft->fwElevator1Channel->setEnabled(true); - m_aircraft->fwElevator1Label->setEnabled(true); - m_aircraft->fwElevator1Label->setText("Vtail 1"); - m_aircraft->fwElevator2Label->setText("Vtail 2"); - m_aircraft->elevonMixBox->setHidden(false); - m_aircraft->fwElevator2Channel->setEnabled(true); - m_aircraft->fwElevator2Label->setEnabled(true); - m_aircraft->fwAileron1Label->setText("Aileron 1"); - m_aircraft->fwAileron2Label->setText("Aileron 2"); - m_aircraft->elevonLabel1->setText("Rudder"); - m_aircraft->elevonLabel2->setText("Pitch"); - - } else if (frameType == "QuadX" || frameType == "Quad X") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X")); - quad->setElementId("quad-X"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(false); - m_aircraft->multiMotor6->setEnabled(false); - m_aircraft->multiMotor7->setEnabled(false); - m_aircraft->multiMotor8->setEnabled(false); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(50); - m_aircraft->mrPitchMixLevel->setValue(50); - m_aircraft->mrYawMixLevel->setValue(50); - } else if (frameType == "QuadP" || frameType == "Quad +") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +")); - quad->setElementId("quad-plus"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(false); - m_aircraft->multiMotor6->setEnabled(false); - m_aircraft->multiMotor7->setEnabled(false); - m_aircraft->multiMotor8->setEnabled(false); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(100); - m_aircraft->mrPitchMixLevel->setValue(100); - m_aircraft->mrYawMixLevel->setValue(50); - } else if (frameType == "Hexa" || frameType == "Hexacopter") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter")); - quad->setElementId("quad-hexa"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(false); - m_aircraft->multiMotor8->setEnabled(false); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(50); - m_aircraft->mrPitchMixLevel->setValue(33); - m_aircraft->mrYawMixLevel->setValue(33); - } else if (frameType == "Octo" || frameType == "Octocopter") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter")); - quad->setElementId("quad-octo"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(true); - m_aircraft->multiMotor8->setEnabled(true); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(33); - m_aircraft->mrPitchMixLevel->setValue(33); - m_aircraft->mrYawMixLevel->setValue(25); - } else if (frameType == "HexaX" || frameType == "Hexacopter X" ) { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X")); - quad->setElementId("quad-hexa-H"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(false); - m_aircraft->multiMotor8->setEnabled(false); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(33); - m_aircraft->mrPitchMixLevel->setValue(50); - m_aircraft->mrYawMixLevel->setValue(33); - - } else if (frameType == "OctoV" || frameType == "Octocopter V") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V")); - quad->setElementId("quad-octo-v"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(true); - m_aircraft->multiMotor8->setEnabled(true); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(25); - m_aircraft->mrPitchMixLevel->setValue(25); - m_aircraft->mrYawMixLevel->setValue(25); - - } else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +")); - quad->setElementId("octo-coax-P"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(true); - m_aircraft->multiMotor8->setEnabled(true); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(100); - m_aircraft->mrPitchMixLevel->setValue(100); - m_aircraft->mrYawMixLevel->setValue(50); - - } else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X")); - quad->setElementId("octo-coax-X"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(true); - m_aircraft->multiMotor8->setEnabled(true); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(50); - m_aircraft->mrPitchMixLevel->setValue(50); - m_aircraft->mrYawMixLevel->setValue(50); - - } else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6")); - quad->setElementId("hexa-coax"); - m_aircraft->multiMotor4->setEnabled(true); - m_aircraft->multiMotor5->setEnabled(true); - m_aircraft->multiMotor6->setEnabled(true); - m_aircraft->multiMotor7->setEnabled(false); - m_aircraft->multiMotor8->setEnabled(false); - m_aircraft->triYawChannel->setEnabled(false); - m_aircraft->mrRollMixLevel->setValue(100); - m_aircraft->mrPitchMixLevel->setValue(50); - m_aircraft->mrYawMixLevel->setValue(66); - - } else if (frameType == "Tri" || frameType == "Tricopter Y") { - m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); - m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y")); - quad->setElementId("tri"); - m_aircraft->multiMotor4->setEnabled(false); - m_aircraft->multiMotor5->setEnabled(false); - m_aircraft->multiMotor6->setEnabled(false); - m_aircraft->multiMotor7->setEnabled(false); - m_aircraft->multiMotor8->setEnabled(false); - m_aircraft->triYawChannel->setEnabled(true); - - } - m_aircraft->quadShape->setSceneRect(quad->boundingRect()); - m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); - setDirty(dirty); -} - -/** - Reset the contents of a field - */ -void ConfigAirframeWidget::resetField(UAVObjectField * field) -{ - for (unsigned int i=0;igetNumElements();i++) { - field->setValue(0,i); - } -} - -/** - Reset actuator values - */ -void ConfigAirframeWidget::resetActuators() -{ - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - QList fieldList = obj->getFields(); - // Reset all assignements first: - foreach (UAVObjectField* field, fieldList) { - // NOTE: we assume that all options in ActuatorSettings are a channel assignement - // except for the options called "ChannelXXX" - if (field->getUnits().contains("channel")) { - field->setValue(field->getOptions().last()); - } - } -} - -/** - Setup Elevator/Aileron/Rudder airframe. - - If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing - - Returns False if impossible to create the mixer. - */ -bool ConfigAirframeWidget::setupFrameFixedWing() -{ - // Check coherence: - // - At least Pitch and either Roll or Yaw - if (m_aircraft->fwEngineChannel->currentText() == "None" || - m_aircraft->fwElevator1Channel->currentText() == "None" || - ((m_aircraft->fwAileron1Channel->currentText() == "None") && - (m_aircraft->fwRudder1Channel->currentText() == "None"))) { - // TODO: explain the problem in the UI - m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment"); - return false; - } - // Now setup the channels: - resetActuators(); - - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - - // Elevator - UAVObjectField *field = obj->getField("FixedWingPitch1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwElevator1Channel->currentText()); - field = obj->getField("FixedWingPitch2"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwElevator2Channel->currentText()); - // Aileron - field = obj->getField("FixedWingRoll1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwAileron1Channel->currentText()); - field = obj->getField("FixedWingRoll2"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwAileron2Channel->currentText()); - // Rudder - field = obj->getField("FixedWingYaw1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwRudder1Channel->currentText()); - // Throttle - field = obj->getField("FixedWingThrottle"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwEngineChannel->currentText()); - - obj->updated(); - - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - // ... and compute the matrix: - // In order to make code a bit nicer, we assume: - // - Channel dropdowns start with 'None', then 0 to 7 - - // 1. Assign the servo/motor/none for each channel - // Disable all - foreach(QString mixer, mixerTypes) { - field = obj->getField(mixer); - Q_ASSERT(field); - field->setValue("Disabled"); - } - // and set only the relevant channels: - // Engine - int eng = m_aircraft->fwEngineChannel->currentIndex()-1; - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Motor"); - field = obj->getField(mixerVectors.at(eng)); - // First of all reset the vector - resetField(field); - int ti = field->getElementNames().indexOf("ThrottleCurve1"); - field->setValue(127, ti); - - // Rudder - eng = m_aircraft->fwRudder1Channel->currentIndex()-1; - // eng will be -1 if rudder is set to "None" - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Yaw"); - field->setValue(127, ti); - } // Else: we have no rudder, only ailerons, we're fine with it. - - // Ailerons - eng = m_aircraft->fwAileron1Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(127, ti); - // Only set Aileron 2 if Aileron 1 is defined - eng = m_aircraft->fwAileron2Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(127, ti); - } - } // Else we have no ailerons. Our consistency check guarantees we have - // rudder in this case, so we're fine with it too. - - // Elevator - eng = m_aircraft->fwElevator1Channel->currentIndex()-1; - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue(127, ti); - // Only set Elevator 2 if it is defined - eng = m_aircraft->fwElevator2Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue(127, ti); - } - - obj->updated(); - m_aircraft->fwStatusLabel->setText("Mixer generated"); - - return true; -} - - -/** - Setup Elevon - */ -bool ConfigAirframeWidget::setupFrameElevon() -{ - // Check coherence: - // - At least Aileron1 and Aileron 2, and engine - if (m_aircraft->fwEngineChannel->currentText() == "None" || - m_aircraft->fwAileron1Channel->currentText() == "None" || - m_aircraft->fwAileron2Channel->currentText() == "None") { - // TODO: explain the problem in the UI - m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment"); - return false; - } - - resetActuators(); - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - - // Elevons - UAVObjectField *field = obj->getField("FixedWingRoll1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwAileron1Channel->currentText()); - field = obj->getField("FixedWingRoll2"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwAileron2Channel->currentText()); - // Rudder 1 (can be None) - field = obj->getField("FixedWingYaw1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwRudder1Channel->currentText()); - // Rudder 2 (can be None) - field = obj->getField("FixedWingYaw2"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwRudder2Channel->currentText()); - // Throttle - field = obj->getField("FixedWingThrottle"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwEngineChannel->currentText()); - - obj->updated(); - - // Save the curve: - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - // ... and compute the matrix: - // In order to make code a bit nicer, we assume: - // - Channel dropdowns start with 'None', then 0 to 7 - - // 1. Assign the servo/motor/none for each channel - // Disable all - foreach(QString mixer, mixerTypes) { - field = obj->getField(mixer); - Q_ASSERT(field); - field->setValue("Disabled"); - } - // and set only the relevant channels: - // Engine - int eng = m_aircraft->fwEngineChannel->currentIndex()-1; - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Motor"); - field = obj->getField(mixerVectors.at(eng)); - // First of all reset the vector - resetField(field); - int ti = field->getElementNames().indexOf("ThrottleCurve1"); - field->setValue(127, ti); - - // Rudder 1 - eng = m_aircraft->fwRudder1Channel->currentIndex()-1; - // eng will be -1 if rudder 1 is set to "None" - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Yaw"); - field->setValue(127, ti); - } // Else: we have no rudder, only elevons, we're fine with it. - - // Rudder 2 - eng = m_aircraft->fwRudder2Channel->currentIndex()-1; - // eng will be -1 if rudder 2 is set to "None" - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Yaw"); - field->setValue(-127, ti); - } // Else: we have no rudder, only elevons, we're fine with it. - - eng = m_aircraft->fwAileron1Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); - ti = field->getElementNames().indexOf("Roll"); - field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti); - } - - eng = m_aircraft->fwAileron2Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti); - } - - obj->updated(); - m_aircraft->fwStatusLabel->setText("Mixer generated"); - return true; -} - -/** - Setup VTail - */ -bool ConfigAirframeWidget::setupFrameVtail() -{ - // Check coherence: - // - At least Pitch1 and Pitch2, and engine - if (m_aircraft->fwEngineChannel->currentText() == "None" || - m_aircraft->fwElevator1Channel->currentText() == "None" || - m_aircraft->fwElevator2Channel->currentText() == "None") { - // TODO: explain the problem in the UI - m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment"); - return false; - } - - resetActuators(); - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - - // Elevons - UAVObjectField *field = obj->getField("FixedWingPitch1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwElevator1Channel->currentText()); - field = obj->getField("FixedWingPitch2"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwElevator2Channel->currentText()); - field = obj->getField("FixedWingRoll1"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwAileron1Channel->currentText()); - field = obj->getField("FixedWingRoll2"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwAileron2Channel->currentText()); - - // Throttle - field = obj->getField("FixedWingThrottle"); - Q_ASSERT(field); - field->setValue(m_aircraft->fwEngineChannel->currentText()); - - obj->updated(); - - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - // ... and compute the matrix: - // In order to make code a bit nicer, we assume: - // - Channel dropdowns start with 'None', then 0 to 7 - - // 1. Assign the servo/motor/none for each channel - // Disable all - foreach(QString mixer, mixerTypes) { - field = obj->getField(mixer); - Q_ASSERT(field); - field->setValue("Disabled"); - } - // and set only the relevant channels: - // Engine - int eng = m_aircraft->fwEngineChannel->currentIndex()-1; - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Motor"); - field = obj->getField(mixerVectors.at(eng)); - // First of all reset the vector - resetField(field); - int ti = field->getElementNames().indexOf("ThrottleCurve1"); - field->setValue(127, ti); - - eng = m_aircraft->fwAileron1Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(127,ti); - } - - eng = m_aircraft->fwAileron2Channel->currentIndex()-1; - if (eng > -1) { - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(-127,ti); - } - - // Now compute the VTail - eng = m_aircraft->fwElevator1Channel->currentIndex()-1; - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); - ti = field->getElementNames().indexOf("Yaw"); - field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti); - - eng = m_aircraft->fwElevator2Channel->currentIndex()-1; - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); - ti = field->getElementNames().indexOf("Yaw"); - field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti); - - obj->updated(); - m_aircraft->fwStatusLabel->setText("Mixer generated"); - return true; -} - -/** - Set up a complete mixer, taking a table of factors. The factors - shoudl mainly be +/- 1 factors, since they will be weighted by the - value of the Pitch/Roll/Yaw sliders. - - Example: - double xMixer [8][3] = { - P R Y - { 1, 1, -1}, Motor 1 - { 1, -1, 1}, Motor 2 - {-1, -1, -1}, Motor 3 - {-1, 1, 1}, ... - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0} - }; - */ -bool ConfigAirframeWidget::setupMixer(double mixerFactors[8][3]) -{ - qDebug()<<"Mixer factors"; - qDebug()< mmList; - mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3 - << m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6 - << m_aircraft->multiMotor7 << m_aircraft->multiMotor8; - UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - // 1. Assign the servo/motor/none for each channel - // Disable all - foreach(QString mixer, mixerTypes) { - field = obj->getField(mixer); - Q_ASSERT(field); - field->setValue("Disabled"); - } - // and enable only the relevant channels: - double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100; - double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100; - double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100; - qDebug()<isEnabled()) - { - int channel = mmList.at(i)->currentIndex()-1; - if (channel > -1) - setupQuadMotor(channel, mixerFactors[i][0]*pFactor, - rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]); - } - } -// obj->updated(); - return true; -} - - -/** - Help function: setupQuadMotor - */ -void ConfigAirframeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw) -{ - qDebug()<(getObjectManager()->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); - UAVObjectField *field = obj->getField(mixerTypes.at(channel)); - field->setValue("Motor"); - field = obj->getField(mixerVectors.at(channel)); - // First of all reset the vector - resetField(field); - int ti = field->getElementNames().indexOf("ThrottleCurve1"); - field->setValue(127, ti); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(roll*127,ti); - qDebug()<<"Set roll="<getElementNames().indexOf("Pitch"); - field->setValue(pitch*127,ti); - qDebug()<<"Set pitch="<getElementNames().indexOf("Yaw"); - field->setValue(yaw*127,ti); - qDebug()<<"Set yaw="< motorList) -{ - resetActuators(); - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - UAVObjectField *field; - QList mmList; - mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3 - << m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6 - << m_aircraft->multiMotor7 << m_aircraft->multiMotor8; - foreach (QString motor, motorList) { - field = obj->getField(motor); - field->setValue(mmList.takeFirst()->currentText()); - } - //obj->updated(); // Save... -} - - -/** - Set up a Quad-X or Quad-P -*/ -bool ConfigAirframeWidget::setupQuad(bool pLayout) -{ - // Check coherence: - // - Four engines have to be defined - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 4 motor channels"); - return false; - } - - - QList motorList; - if (pLayout) { - motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS" - << "VTOLMotorW"; - } else { - motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE" - << "VTOLMotorSW"; - } - setupMotors(motorList); - - // Now, setup the mixer: - // Motor 1 to 4, X Layout: - // pitch roll yaw - // {0.5 ,0.5 ,-0.5 //Front left motor (CW) - // {0.5 ,-0.5 ,0.5 //Front right motor(CCW) - // {-0.5 ,-0.5 ,-0.5 //rear right motor (CW) - // {-0.5 ,0.5 ,0.5 //Rear left motor (CCW) - double xMixer [8][3] = { - { 1, 1, -1}, - { 1, -1, 1}, - {-1, -1, -1}, - {-1, 1, 1}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0} - }; - // - // Motor 1 to 4, P Layout: - // pitch roll yaw - // {1 ,0 ,-0.5 //Front motor (CW) - // {0 ,-1 ,0.5 //Right motor(CCW) - // {-1 ,0 ,-0.5 //Rear motor (CW) - // {0 ,1 ,0.5 //Left motor (CCW) - double pMixer [8][3] = { - { 1, 0, -1}, - { 0, -1, 1}, - {-1, 0, -1}, - { 0, 1, 1}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0} - }; - - if (pLayout) { - setupMixer(pMixer); - } else { - setupMixer(xMixer); - } - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - return true; -} - - - -/** - Set up a Hexa-X or Hexa-P -*/ -bool ConfigAirframeWidget::setupHexa(bool pLayout) -{ - // Check coherence: - // - Four engines have to be defined - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None" || - m_aircraft->multiMotor5->currentText() == "None" || - m_aircraft->multiMotor6->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels"); - return false; - } - - QList motorList; - if (pLayout) { - motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE" - << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW"; - } else { - motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" - << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; - } - setupMotors(motorList); - - // and set only the relevant channels: - - // Motor 1 to 6, P Layout: - // pitch roll yaw - // 1 { 0.3 , 0 ,-0.3 // N CW - // 2 { 0.3 ,-0.5 , 0.3 // NE CCW - // 3 {-0.3 ,-0.5 ,-0.3 // SE CW - // 4 {-0.3 , 0 , 0.3 // S CCW - // 5 {-0.3 , 0.5 ,-0.3 // SW CW - // 6 { 0.3 , 0.5 , 0.3 // NW CCW - - double pMixer [8][3] = { - { 1, 0, -1}, - { 1, -1, 1}, - {-1, -1, -1}, - {-1, 0, 1}, - {-1, 1, -1}, - { 1, 1, 1}, - { 0, 0, 0}, - { 0, 0, 0} - }; - - // - // Motor 1 to 6, X Layout: - // 1 [ 0.5, -0.3, -0.3 ] NE - // 2 [ 0 , -0.3, 0.3 ] E - // 3 [ -0.5, -0.3, -0.3 ] SE - // 4 [ -0.5, 0.3, 0.3 ] SW - // 5 [ 0 , 0.3, -0.3 ] W - // 6 [ 0.5, 0.3, 0.3 ] NW - double xMixer [8][3] = { - { 1, -1, -1}, - { 0, -1, 1}, - { -1, -1, -1}, - { -1, 1, 1}, - { 0, 1, -1}, - { 1, 1, 1}, - { 0, 0, 0}, - { 0, 0, 0} - }; - - if (pLayout) { - setupMixer(pMixer); - } else { - setupMixer(xMixer); - } - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - return true; -} - -/** - Updates the custom airframe settings based on the current airframe. - - Note: does NOT ask for an object refresh itself! - */ -void ConfigAirframeWidget::updateCustomAirframeUI() -{ - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - QList curveValues; - // If the 1st element of the curve is <= -10, then the curve - // is a straight line (that's how the mixer works on the mainboard): - if (field->getValue(0).toInt() <= -10) { - m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1); - } else { - double temp=0; - double value; - for (unsigned int i=0; i < field->getNumElements(); i++) { - value=field->getValue(i).toDouble(); - temp+=value; - curveValues.append(value); - } - if(temp==0) - m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1); - else - m_aircraft->customThrottle1Curve->initCurve(curveValues); - } - field = obj->getField(QString("ThrottleCurve2")); - curveValues.clear();; - // If the 1st element of the curve is <= -10, then the curve - // is a straight line (that's how the mixer works on the mainboard): - if (field->getValue(0).toInt() <= -10) { - m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1); - } else { - for (unsigned int i=0; i < field->getNumElements(); i++) { - curveValues.append(field->getValue(i).toDouble()); - } - m_aircraft->customThrottle2Curve->initCurve(curveValues); - } - - // Update the table: - for (int i=0; i<8; i++) { - field = obj->getField(mixerTypes.at(i)); - QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i); - QString s = field->getValue().toString(); - q->setCurrentIndex(q->findText(s)); - //bool en = (s != "Disabled"); - field = obj->getField(mixerVectors.at(i)); - int ti = field->getElementNames().indexOf("ThrottleCurve1"); - m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString()); - ti = field->getElementNames().indexOf("ThrottleCurve2"); - m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString()); - ti = field->getElementNames().indexOf("Roll"); - m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString()); - ti = field->getElementNames().indexOf("Pitch"); - m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString()); - ti = field->getElementNames().indexOf("Yaw"); - m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString()); - } -} - - -/** - Sends the config to the board (airframe type) - - We do all the tasks common to all airframes, or family of airframes, and - we call additional methods for specific frames, so that we do not have a code - that is too heavy. -*/ -void ConfigAirframeWidget::updateObjectsFromWidgets() -{ - qDebug()<<"updateObjectsFromWidgets"; - QString airframeType = "Custom"; - if (m_aircraft->aircraftType->currentText() == "Fixed Wing") { - // Save the curve (common to all Fixed wing frames) - UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - // Remove Feed Forward, it is pointless on a plane: - UAVObjectField* field = obj->getField(QString("FeedForward")); - field->setDouble(0); - field = obj->getField("ThrottleCurve1"); - QList curve = m_aircraft->fixedWingThrottle->getCurve(); - for (int i=0;isetValue(curve.at(i),i); - } - - if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) { - airframeType = "FixedWing"; - setupFrameFixedWing(); - } else if (m_aircraft->fixedWingType->currentText() == "Elevon") { - airframeType = "FixedWingElevon"; - setupFrameElevon(); - } else { // "Vtail" - airframeType = "FixedWingVtail"; - setupFrameVtail(); - } - // Now reflect those settings in the "Custom" panel as well - updateCustomAirframeUI(); - } else if (m_aircraft->aircraftType->currentText() == "Multirotor") { - - QList motorList; - - // We can already setup the feedforward here, as it is common to all platforms - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("FeedForward")); - field->setDouble((double)m_aircraft->feedForwardSlider->value()/100); - field = obj->getField(QString("AccelTime")); - field->setDouble(m_aircraft->accelTime->value()); - field = obj->getField(QString("DecelTime")); - field->setDouble(m_aircraft->decelTime->value()); - field = obj->getField(QString("MaxAccel")); - field->setDouble(m_aircraft->maxAccelSlider->value()); - - // Curve is also common to all quads: - field = obj->getField("ThrottleCurve1"); - QList curve = m_aircraft->multiThrottleCurve->getCurve(); - for (int i=0;isetValue(curve.at(i),i); - } - - if (m_aircraft->multirotorFrameType->currentText() == "Quad +") { - airframeType = "QuadP"; - setupQuad(true); - } else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") { - airframeType = "QuadX"; - setupQuad(false); - } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") { - airframeType = "Hexa"; - setupHexa(true); - } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") { - airframeType = "Octo"; - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None" || - m_aircraft->multiMotor5->currentText() == "None" || - m_aircraft->multiMotor6->currentText() == "None" || - m_aircraft->multiMotor7->currentText() == "None" || - m_aircraft->multiMotor8->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); - return; - } - motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" - << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; - setupMotors(motorList); - // Motor 1 to 8: - // pitch roll yaw - double mixer [8][3] = { - { 1, 0, -1}, - { 1, -1, 1}, - { 0, -1, -1}, - { -1, -1, 1}, - { -1, 0, -1}, - { -1, 1, 1}, - { 0, 1, -1}, - { 1, 1, 1} - }; - setupMixer(mixer); - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - - } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") { - airframeType = "HexaX"; - setupHexa(false); - } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") { - airframeType = "OctoV"; - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None" || - m_aircraft->multiMotor5->currentText() == "None" || - m_aircraft->multiMotor6->currentText() == "None" || - m_aircraft->multiMotor7->currentText() == "None" || - m_aircraft->multiMotor8->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); - return; - } - motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" - << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; - setupMotors(motorList); - // Motor 1 to 8: - // IMPORTANT: Assumes evenly spaced engines - // pitch roll yaw - double mixer [8][3] = { - { 0.33, -1, -1}, - { 1 , -1, 1}, - { -1 , -1, -1}, - { -0.33, -1, 1}, - { -0.33, 1, -1}, - { -1 , 1, 1}, - { 1 , 1, -1}, - { 0.33, 1, 1} - }; - setupMixer(mixer); - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - - } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") { - airframeType = "OctoCoaxP"; - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None" || - m_aircraft->multiMotor5->currentText() == "None" || - m_aircraft->multiMotor6->currentText() == "None" || - m_aircraft->multiMotor7->currentText() == "None" || - m_aircraft->multiMotor8->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); - return; - } - motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" - << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; - setupMotors(motorList); - // Motor 1 to 8: - // pitch roll yaw - double mixer [8][3] = { - { 1, 0, -1}, - { 1, 0, 1}, - { 0, -1, -1}, - { 0, -1, 1}, - { -1, 0, -1}, - { -1, 0, 1}, - { 0, 1, -1}, - { 0, 1, 1} - }; - setupMixer(mixer); - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - - } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") { - airframeType = "OctoCoaxX"; - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None" || - m_aircraft->multiMotor5->currentText() == "None" || - m_aircraft->multiMotor6->currentText() == "None" || - m_aircraft->multiMotor7->currentText() == "None" || - m_aircraft->multiMotor8->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); - return; - } - motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" - << "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW"; - setupMotors(motorList); - // Motor 1 to 8: - // pitch roll yaw - double mixer [8][3] = { - { 1, 1, -1}, - { 1, 1, 1}, - { 1, -1, -1}, - { 1, -1, 1}, - { -1, -1, -1}, - { -1, -1, 1}, - { -1, 1, -1}, - { -1, 1, 1} - }; - setupMixer(mixer); - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - - } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") { - airframeType = "HexaCoax"; - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" || - m_aircraft->multiMotor4->currentText() == "None" || - m_aircraft->multiMotor5->currentText() == "None" || - m_aircraft->multiMotor6->currentText() == "None" ) { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels"); - return; - } - motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE" - << "VTOLMotorS" << "VTOLMotorSE"; - setupMotors(motorList); - - // Motor 1 to 6, Y6 Layout: - // pitch roll yaw - double mixer [8][3] = { - { 0.5, 1, -1}, - { 0.5, 1, 1}, - { 0.5, -1, -1}, - { 0.5, -1, 1}, - { -1, 0, -1}, - { -1, 0, 1}, - { 0, 0, 0}, - { 0, 0, 0} - }; - setupMixer(mixer); - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - - } else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") { - airframeType = "Tri"; - if (m_aircraft->multiMotor1->currentText() == "None" || - m_aircraft->multiMotor2->currentText() == "None" || - m_aircraft->multiMotor3->currentText() == "None" ) { - m_aircraft->mrStatusLabel->setText("ERROR: Assign 3 motor channels"); - return; - } - if (m_aircraft->triYawChannel->currentText() == "None") { - m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel"); - return; - } - motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS"; - setupMotors(motorList); - obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); - field = obj->getField("FixedWingYaw1"); - field->setValue(m_aircraft->triYawChannel->currentText()); - - // Motor 1 to 6, Y6 Layout: - // pitch roll yaw - double mixer [8][3] = { - { 0.5, 1, 0}, - { 0.5, -1, 0}, - { -1, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0}, - { 0, 0, 0} - }; - setupMixer(mixer); - - int eng = m_aircraft->triYawChannel->currentIndex()-1; - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - field = obj->getField(mixerTypes.at(eng)); - field->setValue("Servo"); - field = obj->getField(mixerVectors.at(eng)); - resetField(field); - int ti = field->getElementNames().indexOf("Yaw"); - field->setValue(127,ti); - - m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); - - } - // Now reflect those settings in the "Custom" panel as well - updateCustomAirframeUI(); - - } else if (m_aircraft->aircraftType->currentText() == "Helicopter") { - airframeType = "HeliCP"; - m_aircraft->widget_3->sendccpmUpdate(); - } else { - airframeType = "Custom"; - - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - UAVObjectField* field = obj->getField(QString("FeedForward")); - - // Curve is also common to all quads: - field = obj->getField("ThrottleCurve1"); - QList curve = m_aircraft->customThrottle1Curve->getCurve(); - for (int i=0;isetValue(curve.at(i),i); - } - - field = obj->getField("ThrottleCurve2"); - curve.clear(); - curve = m_aircraft->customThrottle2Curve->getCurve(); - for (int i=0;isetValue(curve.at(i),i); - } - - // Update the table: - for (int i=0; i<8; i++) { - field = obj->getField(mixerTypes.at(i)); - QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i); - field->setValue(q->currentText()); - field = obj->getField(mixerVectors.at(i)); - int ti = field->getElementNames().indexOf("ThrottleCurve1"); - field->setValue(m_aircraft->customMixerTable->item(1,i)->text(),ti); - ti = field->getElementNames().indexOf("ThrottleCurve2"); - field->setValue(m_aircraft->customMixerTable->item(2,i)->text(),ti); - ti = field->getElementNames().indexOf("Roll"); - field->setValue(m_aircraft->customMixerTable->item(3,i)->text(),ti); - ti = field->getElementNames().indexOf("Pitch"); - field->setValue(m_aircraft->customMixerTable->item(4,i)->text(),ti); - ti = field->getElementNames().indexOf("Yaw"); - field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti); - } - - } - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); - UAVObjectField* field = obj->getField(QString("AirframeType")); - field->setValue(airframeType); - -} - -void ConfigAirframeWidget::openHelp() -{ - - QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) ); -} - -void ConfigAirframeWidget::addToDirtyMonitor() -{ - addWidget(m_aircraft->customMixerTable); - addWidget(m_aircraft->customThrottle2Curve); - addWidget(m_aircraft->customThrottle1Curve); - addWidget(m_aircraft->multiThrottleCurve); - addWidget(m_aircraft->fixedWingThrottle); - addWidget(m_aircraft->fixedWingType); - addWidget(m_aircraft->feedForwardSlider); - addWidget(m_aircraft->accelTime); - addWidget(m_aircraft->decelTime); - addWidget(m_aircraft->maxAccelSlider); - addWidget(m_aircraft->multirotorFrameType); - addWidget(m_aircraft->multiMotor1); - addWidget(m_aircraft->multiMotor2); - addWidget(m_aircraft->multiMotor3); - addWidget(m_aircraft->multiMotor4); - addWidget(m_aircraft->multiMotor5); - addWidget(m_aircraft->multiMotor6); - addWidget(m_aircraft->multiMotor7); - addWidget(m_aircraft->multiMotor8); - addWidget(m_aircraft->triYawChannel); - addWidget(m_aircraft->aircraftType); - addWidget(m_aircraft->fwEngineChannel); - addWidget(m_aircraft->fwAileron1Channel); - addWidget(m_aircraft->fwAileron2Channel); - addWidget(m_aircraft->fwElevator1Channel); - addWidget(m_aircraft->fwElevator2Channel); - addWidget(m_aircraft->fwRudder1Channel); - addWidget(m_aircraft->fwRudder2Channel); - addWidget(m_aircraft->elevonSlider1); - addWidget(m_aircraft->elevonSlider2); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmType); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox); - addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider); - addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox); - addWidget(m_aircraft->widget_3->m_ccpm->CurveType); - addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints); - addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1); - addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2); - addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3); - addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate); - addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings); - addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve); - addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve); - addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable); -} - diff --git a/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp index 29a36636a..40705b42f 100644 --- a/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp @@ -28,7 +28,7 @@ #include "configahrswidget.h" #include "configgadgetwidget.h" -#include "configairframewidget.h" +#include "ConfigVehicleTypeWidget.h" #include "configccattitudewidget.h" #include "configinputwidget.h" #include "configoutputwidget.h" @@ -68,7 +68,7 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent) qwd = new DefaultHwSettingsWidget(this); ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings")); - qwd = new ConfigAirframeWidget(this); + qwd = new ConfigVehicleTypeWidget(this); ftw->insertTab(ConfigGadgetWidget::aircraft, qwd, QIcon(":/configgadget/images/Airframe.png"), QString("Aircraft")); qwd = new ConfigInputWidget(this); diff --git a/ground/openpilotgcs/src/plugins/config/configvehicletypewidget.cpp b/ground/openpilotgcs/src/plugins/config/configvehicletypewidget.cpp new file mode 100644 index 000000000..614516de9 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/configvehicletypewidget.cpp @@ -0,0 +1,2751 @@ +/** + ****************************************************************************** + * + * @file configvehicletypewidget.cpp + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Airframe configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "configvehicletypewidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "systemsettings.h" +#include "mixersettings.h" +#include "actuatorsettings.h" +#include + +/** + Helper delegate for the custom mixer editor table. + Taken straight from Qt examples, thanks! + */ +SpinBoxDelegate::SpinBoxDelegate(QObject *parent) + : QItemDelegate(parent) + { + } + +QWidget *SpinBoxDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &/* option */, + const QModelIndex &/* index */) const +{ + QSpinBox *editor = new QSpinBox(parent); + editor->setMinimum(-127); + editor->setMaximum(127); + + return editor; +} + +void SpinBoxDelegate::setEditorData(QWidget *editor, + const QModelIndex &index) const +{ + int value = index.model()->data(index, Qt::EditRole).toInt(); + + QSpinBox *spinBox = static_cast(editor); + spinBox->setValue(value); +} + +void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + QSpinBox *spinBox = static_cast(editor); + spinBox->interpretText(); + int value = spinBox->value(); + + model->setData(index, value, Qt::EditRole); +} + +void SpinBoxDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &/* index */) const +{ + editor->setGeometry(option.rect); +} + +/**********************************************************************************/ + + +/** + Constructor + */ +ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWidget(parent) +{ + m_aircraft = new Ui_AircraftWidget(); + m_aircraft->setupUi(this); + + addApplySaveButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD); + + addUAVObject("SystemSettings"); + addUAVObject("MixerSettings"); + addUAVObject("ActuatorSettings"); + + + ffTuningInProgress = false; + ffTuningPhase = false; + + //Generate list of channels + QStringList channels; + channels << "None"; + for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) { + mixerTypes << QString("Mixer%1Type").arg(i+1); + mixerVectors << QString("Mixer%1Vector").arg(i+1); + channels << QString("Channel%1").arg(i+1); + } + + QStringList airframeTypes; + airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Ground" << "Custom"; + m_aircraft->aircraftType->addItems(airframeTypes); + m_aircraft->aircraftType->setCurrentIndex(1); + + QStringList fixedWingTypes; + fixedWingTypes << "Elevator aileron rudder" << "Elevon" << "Vtail"; + m_aircraft->fixedWingType->addItems(fixedWingTypes); + m_aircraft->fixedWingType->setCurrentIndex(0); //Set default model to "Elevator aileron rudder" + + QStringList groundVehicleTypes; + groundVehicleTypes << "Turnable (car)" << "Differential (tank)" << "Motorcycle"; +// groundVehicleTypes << "Turnable (car)"; + m_aircraft->groundVehicleType->addItems(groundVehicleTypes); + m_aircraft->groundVehicleType->setCurrentIndex(0); //Set default model to "Turnable (car)" + + QStringList multiRotorTypes; + multiRotorTypes << "Tricopter Y"<< "Quad +" << "Quad X" << + "Hexacopter" << "Hexacopter X" << "Hexacopter Y6" << + "Octocopter" << "Octocopter V" << "Octo Coax +" << "Octo Coax X" ; + m_aircraft->multirotorFrameType->addItems(multiRotorTypes); + m_aircraft->multirotorFrameType->setCurrentIndex(1); //Set default model to "Quad +" + + // Now load all the channel assignements + //OLD STYLE: DO IT MANUALLY +// m_aircraft->triYawChannelBox->addItems(channels); +// m_aircraft->gvMotor1ChannelBox->addItems(channels); +// m_aircraft->gvMotor2ChannelBox->addItems(channels); +// m_aircraft->gvSteering1ChannelBox->addItems(channels); +// m_aircraft->gvSteering2ChannelBox->addItems(channels); +// m_aircraft->fwElevator1ChannelBox->addItems(channels); +// m_aircraft->fwElevator2ChannelBox->addItems(channels); +// m_aircraft->fwEngineChannelBox->addItems(channels); +// m_aircraft->fwRudder1ChannelBox->addItems(channels); +// m_aircraft->fwRudder2ChannelBox->addItems(channels); +// m_aircraft->fwAileron1ChannelBox->addItems(channels); +// m_aircraft->fwAileron2ChannelBox->addItems(channels); + + //NEW STYLE: Loop through the widgets looking for all widgets that have "ChannelBox" in their name + // The upshot of this is that ALL new ComboBox widgets for selecting the output channel must have "ChannelBox" in their name + foreach(QComboBox *combobox, this->findChildren(QRegExp("\\S+ChannelBo\\S+")))//FOR WHATEVER REASON, THIS DOES NOT WORK WITH ChannelBox. ChannelBo is sufficiently accurate + { + combobox->addItems(channels); + } + + // Setup the Multirotor picture in the Quad settings interface + m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_aircraft->quadShape->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + QSvgRenderer *renderer = new QSvgRenderer(); + renderer->load(QString(":/configgadget/images/quad-shapes.svg")); + quad = new QGraphicsSvgItem(); + quad->setSharedRenderer(renderer); + quad->setElementId("quad-plus"); + QGraphicsScene *scene = new QGraphicsScene(this); + scene->addItem(quad); + scene->setSceneRect(quad->boundingRect()); + m_aircraft->quadShape->setScene(scene); + + // Put combo boxes in line one of the custom mixer table: + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("Mixer1Type")); + QStringList list = field->getOptions(); + for (int i=0;i<8;i++) { + QComboBox* qb = new QComboBox(m_aircraft->customMixerTable); + qb->addItems(list); + m_aircraft->customMixerTable->setCellWidget(0,i,qb); + } + + SpinBoxDelegate *sbd = new SpinBoxDelegate(); + for (int i=1;i<8; i++) { + m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd); + } + + //Connect aircraft type selection dropbox to callback function + connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int))); + + //Connect airframe selection dropbox to callback functions + connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); + connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); + connect(m_aircraft->groundVehicleType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); + + //Connect throttle curve reset pushbuttons to reset functions + connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer())); + connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer())); + connect(m_aircraft->gvThrottleCurve1Reset, SIGNAL(clicked()), this, SLOT(resetGvFrontMixer())); + connect(m_aircraft->gvThrottleCurve2Reset, SIGNAL(clicked()), this, SLOT(resetGvRearMixer())); + connect(m_aircraft->customReset1, SIGNAL(clicked()), this, SLOT(resetCt1Mixer())); + connect(m_aircraft->customReset2, SIGNAL(clicked()), this, SLOT(resetCt2Mixer())); + + //Connect throttle curve manipulation points to output text + connect(m_aircraft->fixedWingThrottle, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateFwThrottleCurveValue(QList,double))); + connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateMrThrottleCurveValue(QList,double))); + connect(m_aircraft->groundVehicleThrottle1, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateGvThrottle1CurveValue(QList,double))); + connect(m_aircraft->groundVehicleThrottle2, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateGvThrottle2CurveValue(QList,double))); + connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateCustomThrottle1CurveValue(QList,double))); + connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateCustomThrottle2CurveValue(QList,double))); + +// connect(m_aircraft->fwAileron1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleAileron2(int))); +// connect(m_aircraft->fwElevator1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleElevator2(int))); + + //Connect the three feed forward test checkboxes + connect(m_aircraft->ffTestBox1, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); + connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); + connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); + + //WHAT DOES THIS DO? + enableControls(false); + refreshWidgetsValues(); + + // Connect the help pushbutton + connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp())); + addToDirtyMonitor(); + + //Initialize GUI tabs //MOVING THIS FROM THE END OF THIS FUNCTION CAN CAUSE RUNTIME ERRORS DUE TO setupMultiRotorUI. WHY? + setupMultiRotorUI( m_aircraft->multirotorFrameType->currentText() ); + setupGroundVehicleUI( m_aircraft->groundVehicleType->currentText() ); + setupFixedWingUI( m_aircraft->fixedWingType->currentText() ); + +} + + +/** + Destructor + */ +ConfigVehicleTypeWidget::~ConfigVehicleTypeWidget() +{ + // Do nothing +} + + +/** + Slot for switching the airframe type. We do it explicitely + rather than a signal in the UI, because we want to force a fitInView of the quad shapes. + This is because this method (fitinview) only works when the widget is shown. + */ +void ConfigVehicleTypeWidget::switchAirframeType(int index){ + m_aircraft->airframesWidget->setCurrentIndex(index); + m_aircraft->quadShape->setSceneRect(quad->boundingRect()); + m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); + if (m_aircraft->aircraftType->findText("Custom")) { + m_aircraft->customMixerTable->resizeColumnsToContents(); + for (int i=0;i<8;i++) { + m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()- + m_aircraft->customMixerTable->verticalHeader()->width())/8); + } + } +} + + +/** + WHAT DOES THIS DO??? + */ +void ConfigVehicleTypeWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + // Thit fitInView method should only be called now, once the + // widget is shown, otherwise it cannot compute its values and + // the result is usually a ahrsbargraph that is way too small. + m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); + m_aircraft->customMixerTable->resizeColumnsToContents(); + for (int i=0;i<8;i++) { + m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()- + m_aircraft->customMixerTable->verticalHeader()->width())/8); + } +} + +/** + Resize the GUI contents when the user changes the window size + */ +void ConfigVehicleTypeWidget::resizeEvent(QResizeEvent* event) +{ + Q_UNUSED(event); + m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); + // Make the custom table columns autostretch: + m_aircraft->customMixerTable->resizeColumnsToContents(); + for (int i=0;i<8;i++) { + m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()- + m_aircraft->customMixerTable->verticalHeader()->width())/8); + } + +} + + +void ConfigVehicleTypeWidget::toggleAileron2(int index) +{ + if (index) { + m_aircraft->fwAileron2ChannelBox->setEnabled(true); + m_aircraft->fwAileron2Label->setEnabled(true); + } else { + m_aircraft->fwAileron2ChannelBox->setEnabled(false); + m_aircraft->fwAileron2Label->setEnabled(false); + } +} + +void ConfigVehicleTypeWidget::toggleElevator2(int index) +{ + if (index) { + m_aircraft->fwElevator2ChannelBox->setEnabled(true); + m_aircraft->fwElevator2Label->setEnabled(true); + } else { + m_aircraft->fwElevator2ChannelBox->setEnabled(false); + m_aircraft->fwElevator2Label->setEnabled(false); + } +} + +void ConfigVehicleTypeWidget::toggleRudder2(int index) +{ + if (index) { + m_aircraft->fwRudder2ChannelBox->setEnabled(true); + m_aircraft->fwRudder2Label->setEnabled(true); + } else { + m_aircraft->fwRudder2ChannelBox->setEnabled(false); + m_aircraft->fwRudder2Label->setEnabled(false); + } +} + + +///////////////////////////////////////////////////////// +/// Feed Forward Testing +///////////////////////////////////////////////////////// +/** + Enables and runs feed forward testing + */ +void ConfigVehicleTypeWidget::enableFFTest() +{ + // Role: + // - Check if all three checkboxes are checked + // - Every other timer event: toggle engine from 45% to 55% + // - Every other time event: send FF settings to flight FW + if (m_aircraft->ffTestBox1->isChecked() && + m_aircraft->ffTestBox2->isChecked() && + m_aircraft->ffTestBox3->isChecked()) { + if (!ffTuningInProgress) + { + // Initiate tuning: + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlCommand"))); + UAVObject::Metadata mdata = obj->getMetadata(); + accInitialData = mdata; + mdata.flightAccess = UAVObject::ACCESS_READONLY; + obj->setMetadata(mdata); + } + // Depending on phase, either move actuator or send FF settings: + if (ffTuningPhase) { + // Send FF settings to the board + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("FeedForward")); + field->setDouble((double)m_aircraft->feedForwardSlider->value()/100); + field = obj->getField(QString("AccelTime")); + field->setDouble(m_aircraft->accelTime->value()); + field = obj->getField(QString("DecelTime")); + field->setDouble(m_aircraft->decelTime->value()); + field = obj->getField(QString("MaxAccel")); + field->setDouble(m_aircraft->maxAccelSlider->value()); + obj->updated(); + } else { + // Toggle motor state + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlCommand"))); + double value = obj->getField("Throttle")->getDouble(); + double target = (value < 0.5) ? 0.55 : 0.45; + obj->getField("Throttle")->setValue(target); + obj->updated(); + } + ffTuningPhase = !ffTuningPhase; + ffTuningInProgress = true; + QTimer::singleShot(1000, this, SLOT(enableFFTest())); + } else { + // - If no: disarm timer, restore actuatorcommand metadata + // Disarm! + if (ffTuningInProgress) { + ffTuningInProgress = false; + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlCommand"))); + UAVObject::Metadata mdata = obj->getMetadata(); + mdata = accInitialData; // Restore metadata + obj->setMetadata(mdata); + } + } +} + + +/** + Resets Fixed wing throttle mixer + */ +void ConfigVehicleTypeWidget::resetFwMixer() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); + resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1); +} + +/** + Resets Multirotor throttle mixer + */ +void ConfigVehicleTypeWidget::resetMrMixer() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); + resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9); +} + +/** + Resets Ground vehicle front throttle mixer + */ +void ConfigVehicleTypeWidget::resetGvFrontMixer() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); + resetMixer(m_aircraft->groundVehicleThrottle1, field->getNumElements(),1); +} + +/** + Resets Ground vehicle rear throttle mixer + */ +void ConfigVehicleTypeWidget::resetGvRearMixer() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve2")); + resetMixer(m_aircraft->groundVehicleThrottle2, field->getNumElements(),1); +} + +/** + Resets Custom throttle 1 mixer + */ +void ConfigVehicleTypeWidget::resetCt1Mixer() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); + resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1); +} + +/** + Resets Custom throttle 2 mixer + */ +void ConfigVehicleTypeWidget::resetCt2Mixer() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve2")); + resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1); +} + + +/** + Resets a mixer curve + */ +void ConfigVehicleTypeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue) +{ + // Setup all Throttle1 curves for all types of airframes + mixer->initLinearCurve((quint32)numElements,maxvalue); +} + +/** + Updates the currently moved fixed wing throttle curve item value + */ +void ConfigVehicleTypeWidget::updateFwThrottleCurveValue(QList list, double value) +{ + Q_UNUSED(list); + m_aircraft->fwThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value)); +} + +/** + Updates the currently moved multi-rotor throttle curve item value + */ +void ConfigVehicleTypeWidget::updateMrThrottleCurveValue(QList list, double value) +{ + Q_UNUSED(list); + m_aircraft->mrThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value)); +} + +/** + Updates the moved ground vehicle front throttle curve item value + */ +void ConfigVehicleTypeWidget::updateGvThrottle1CurveValue(QList list, double value) +{ + Q_UNUSED(list); + m_aircraft->gvThrottleCurve1ItemValue->setText(QString().sprintf("Val: %.2f",value)); +} + +/** + Updates the moved ground vehicle rear throttle curve item value + */ +void ConfigVehicleTypeWidget::updateGvThrottle2CurveValue(QList list, double value) +{ + Q_UNUSED(list); + m_aircraft->gvThrottleCurve2ItemValue->setText(QString().sprintf("Val: %.2f",value)); +} + +/** + Updates the currently moved custom throttle curve item value (Custom throttle 1) + */ +void ConfigVehicleTypeWidget::updateCustomThrottle1CurveValue(QList list, double value) +{ + Q_UNUSED(list); + m_aircraft->customThrottleCurve1Value->setText(QString().sprintf("Val: %.2f",value)); +} + +/** + Updates the currently moved custom throttle curve item value (Custom throttle 2) + */ +void ConfigVehicleTypeWidget::updateCustomThrottle2CurveValue(QList list, double value) +{ + Q_UNUSED(list); + m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value)); +} + + +/************************** + * Aircraft settings + **************************/ +/** + Refreshes the current value of the SystemSettings which holds the aircraft type + */ +void ConfigVehicleTypeWidget::refreshWidgetsValues() +{ + if(!allObjectsUpdated()) + return; + + //WHAT DOES THIS DO? + bool dirty=isDirty(); //WHY IS THIS CALLED HERE AND THEN AGAIN SEVERAL LINES LATER IN setupAirframeUI() + + // Get the Airframe type from the system settings: + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); + Q_ASSERT(obj); + UAVObjectField *field = obj->getField(QString("AirframeType")); + Q_ASSERT(field); + // At this stage, we will need to have some hardcoded settings in this code, this + // is not ideal, but here you go. + QString frameType = field->getValue().toString(); + setupAirframeUI(frameType); + + obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + Q_ASSERT(obj); + field = obj->getField(QString("ThrottleCurve1")); + Q_ASSERT(field); + QList curveValues; + // If the 1st element of the curve is <= -10, then the curve + // is a straight line (that's how the mixer works on the mainboard): + if (field->getValue(0).toInt() <= -10) { + m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1); + m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1); + m_aircraft->groundVehicleThrottle1->initLinearCurve(field->getNumElements(),(double)1); + } + else { + double temp=0; + double value; + for (unsigned int i=0; i < field->getNumElements(); i++) { + value=field->getValue(i).toDouble(); + temp+=value; + curveValues.append(value); + } + if(temp==0) + { + m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9); + m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1); + m_aircraft->groundVehicleThrottle1->initLinearCurve(field->getNumElements(),(double)1); + } + else + { + m_aircraft->multiThrottleCurve->initCurve(curveValues); + m_aircraft->fixedWingThrottle->initCurve(curveValues); + m_aircraft->groundVehicleThrottle1->initCurve(curveValues); + } + } + + // Setup all Throttle2 curves for all types of airframes //AT THIS MOMENT, THAT MEANS ONLY GROUND VEHICLES + Q_ASSERT(obj); + field = obj->getField(QString("ThrottleCurve2")); + Q_ASSERT(field); + curveValues.clear(); + // If the 1st element of the curve is <= -10, then the curve + // is a straight line (that's how the mixer works on the mainboard): + if (field->getValue(0).toInt() <= -10) { + m_aircraft->groundVehicleThrottle2->initLinearCurve(field->getNumElements(),(double)1); + } + else { + double temp=0; + double value; + for (unsigned int i=0; i < field->getNumElements(); i++) { + value=field->getValue(i).toDouble(); + temp+=value; + curveValues.append(value); + } + if(temp==0) + { + m_aircraft->groundVehicleThrottle2->initLinearCurve(field->getNumElements(),(double)1); + } + else + { + m_aircraft->groundVehicleThrottle2->initCurve(curveValues); + } + } + + // Load the Settings for fixed wing frames: + if (frameType.startsWith("FixedWing")) { + + // Retrieve fixed wing settings + if(1){ + refreshFixedWingWidgetsValues(frameType); + } +// // Then retrieve how channels are setup +// obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// field = obj->getField(QString("FixedWingThrottle")); +// Q_ASSERT(field); +// m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingRoll1")); +// Q_ASSERT(field); +// m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingRoll2")); +// Q_ASSERT(field); +// m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingPitch1")); +// Q_ASSERT(field); +// m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingPitch2")); +// Q_ASSERT(field); +// m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingYaw1")); +// Q_ASSERT(field); +// m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingYaw2")); +// Q_ASSERT(field); +// m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString())); +// +// if (frameType == "FixedWingElevon") { +// // If the airframe is elevon, restore the slider setting +// // Find the channel number for Elevon1 (FixedWingRoll1) +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; +// if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check. +// field = obj->getField(mixerVectors.at(chMixerNumber)); +// int ti = field->getElementNames().indexOf("Roll"); +// m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100); +// ti = field->getElementNames().indexOf("Pitch"); +// m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100); +// } +// } +// if (frameType == "FixedWingVtail") { +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int chMixerNumber = m_aircraft->fwElevator1ChannelBox->currentIndex()-1; +// if (chMixerNumber >=0) { +// field = obj->getField(mixerVectors.at(chMixerNumber)); +// int ti = field->getElementNames().indexOf("Yaw"); +// m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100); +// ti = field->getElementNames().indexOf("Pitch"); +// m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100); +// } +// } + + } else if (frameType == "Tri" || + frameType == "QuadX" || frameType == "QuadP" || + frameType == "Hexa" || frameType == "HexaCoax" || frameType == "HexaX" || + frameType == "Octo" || frameType == "OctoV" || frameType == "OctoCoaxP" || frameType == "OctoCoaxX" ) { + + // Retrieve multirotor settings + if(1){ + refreshMultiRotorWidgetsValues(frameType); + } + else{// +// ////////////////////////////////////////////////////////////////// +// // Retrieve Multirotor settings +// ////////////////////////////////////////////////////////////////// +// +// obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// if (frameType == "QuadP") { +// // Motors 1/2/3/4 are: N / E / S / W +// field = obj->getField(QString("VTOLMotorN")); +// Q_ASSERT(field); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorS")); +// Q_ASSERT(field); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = field->getDouble(i)/1.27; +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = (1-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// tmpVal = m_aircraft->multiMotor2->currentIndex()-1; +// field = obj->getField(mixerVectors.at(tmpVal)); +// i = field->getElementNames().indexOf("Roll"); +// val = -field->getDouble(i)/1.27; +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// } else if (frameType == "QuadX") { +// // Motors 1/2/3/4 are: NW / NE / SE / SW +// field = obj->getField(QString("VTOLMotorNW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = field->getDouble(i)/1.27; +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = 1-field->getDouble(i)/1.27; +// m_aircraft->mrYawMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Roll"); +// val = field->getDouble(i)/1.27; +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// } else if (frameType == "Hexa") { +// // Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW +// field = obj->getField(QString("VTOLMotorN")); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNE")); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSE")); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorS")); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSW")); +// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNW")); +// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// tmpVal = m_aircraft->multiMotor2->currentIndex()-1; +// if(tmpVal>-1) +// { +// field = obj->getField(mixerVectors.at(tmpVal)); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(1-field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// } +// } else if (frameType == "HexaX") { +// // Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW +// field = obj->getField(QString("VTOLMotorNE")); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorE")); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSE")); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSW")); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorW")); +// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNW")); +// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// tmpVal = m_aircraft->multiMotor2->currentIndex()-1; +// field = obj->getField(mixerVectors.at(tmpVal)); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(1-field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// } else if (frameType == "HexaCoax") { +// // Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE +// field = obj->getField(QString("VTOLMotorNW")); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorW")); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNE")); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorE")); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorS")); +// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSE")); +// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(2*field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// } else if (frameType == "Octo" || frameType == "OctoV" || +// frameType == "OctoCoaxP") { +// // Motors 1 to 8 are N / NE / E / etc +// field = obj->getField(QString("VTOLMotorN")); +// Q_ASSERT(field); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorS")); +// Q_ASSERT(field); +// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// if (frameType == "Octo") { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// tmpVal = m_aircraft->multiMotor2->currentIndex()-1; +// field = obj->getField(mixerVectors.at(tmpVal)); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// } else if (frameType == "OctoV") { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Yaw"); +// double val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// tmpVal = m_aircraft->multiMotor2->currentIndex()-1; +// field = obj->getField(mixerVectors.at(tmpVal)); +// i = field->getElementNames().indexOf("Pitch"); +// val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// +// } else if (frameType == "OctoCoaxP") { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// tmpVal = m_aircraft->multiMotor3->currentIndex()-1; +// field = obj->getField(mixerVectors.at(tmpVal)); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// +// } +// } +// } else if (frameType == "OctoCoaxX") { +// // Motors 1 to 8 are N / NE / E / etc +// field = obj->getField(QString("VTOLMotorNW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorN")); +// Q_ASSERT(field); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorS")); +// Q_ASSERT(field); +// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorSW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString())); +// +// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders. +// // This assumes that all vectors are identical - if not, the user should use the +// // "custom" setting. +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Yaw"); +// val = floor(-field->getDouble(i)/1.27); +// m_aircraft->mrYawMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// } else if (frameType == "Tri") { +// // Motors 1 to 8 are N / NE / E / etc +// field = obj->getField(QString("VTOLMotorNW")); +// Q_ASSERT(field); +// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorNE")); +// Q_ASSERT(field); +// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString())); +// field = obj->getField(QString("VTOLMotorS")); +// Q_ASSERT(field); +// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingYaw1")); +// Q_ASSERT(field); +// m_aircraft->triYawChannelBoxBox->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString())); +// +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1; +// // tmpVal will be -1 if value is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerVectors.at(tmpVal)); +// int i = field->getElementNames().indexOf("Pitch"); +// double val = floor(2*field->getDouble(i)/1.27); +// m_aircraft->mrPitchMixLevel->setValue(val); +// i = field->getElementNames().indexOf("Roll"); +// val = floor(field->getDouble(i)/1.27); +// m_aircraft->mrRollMixLevel->setValue(val); +// } +// +// } +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// // Now, retrieve the Feedforward values: +// field = obj->getField(QString("FeedForward")); +// Q_ASSERT(field); +// m_aircraft->feedForwardSlider->setValue(field->getDouble()*100); +// field = obj->getField(QString("AccelTime")); +// Q_ASSERT(field); +// m_aircraft->accelTime->setValue(field->getDouble()); +// field = obj->getField(QString("DecelTime")); +// Q_ASSERT(field); +// m_aircraft->decelTime->setValue(field->getDouble()); +// field = obj->getField(QString("MaxAccel")); +// Q_ASSERT(field); +// m_aircraft->maxAccelSlider->setValue(field->getDouble()); + } + } else if (frameType == "HeliCP") { + m_aircraft->widget_3->requestccpmUpdate(); + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter" + } else if (frameType.startsWith("GroundVehicle")) { + + // Retrieve ground vehicle settings + if(1){ + refreshGroundVehicleWidgetsValues(frameType); + } + +// //THIS SECTION STILL NEEDS WORK. FOR THE MOMENT, USE THE FIXED-WING ONBOARD SETTING IN ORDER TO MINIMIZE CHANCES OF BOLLOXING REAL CODE +// // Then retrieve channel setup values +// obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// field = obj->getField(QString("FixedWingThrottle")); +// Q_ASSERT(field); +// m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingRoll1")); +// Q_ASSERT(field); +// m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingRoll2")); +// Q_ASSERT(field); +// m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingPitch1")); +// Q_ASSERT(field); +// m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingPitch2")); +// Q_ASSERT(field); +// m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingYaw1")); +// Q_ASSERT(field); +// m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString())); +// field = obj->getField(QString("FixedWingYaw2")); +// Q_ASSERT(field); +// m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString())); +// +// if (frameType == "GroundDifferential") { +// //CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE +// // If the airframe is differential, restore the slider setting +// // Find the channel number for Elevon1 (FixedWingRoll1) +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; +// if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check. +// field = obj->getField(mixerVectors.at(chMixerNumber)); +// int ti = field->getElementNames().indexOf("Roll"); +// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100); +// +// ti = field->getElementNames().indexOf("Pitch"); +// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100); +// } +// } +// if (frameType == "GroundMotorcycle") { +// //CURRENTLY BROKEN UNTIL WE DECIDE HOW MOTORCYCLE SHOULD BEHAVE +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1; +// if (chMixerNumber >=0) { +// field = obj->getField(mixerVectors.at(chMixerNumber)); +// int ti = field->getElementNames().indexOf("Yaw"); +// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100); +// +// ti = field->getElementNames().indexOf("Pitch"); +// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100); +// } +// } + } else if (frameType == "Custom") { + m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom")); + } + + + updateCustomAirframeUI(); + setDirty(dirty); +} + +/** + \brief Sets up the mixer depending on Airframe type. Accepts either system settings or + combo box entry from airframe type, as those do not overlap. + */ +void ConfigVehicleTypeWidget::setupAirframeUI(QString frameType) +{ + + bool dirty=isDirty(); + if(frameType == "FixedWing" || frameType == "Elevator aileron rudder" || + frameType == "FixedWingElevon" || frameType == "Elevon" || + frameType == "FixedWingVtail" || frameType == "Vtail"){ + setupFixedWingUI(frameType); +// } +// else if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") { +// // Setup the UI +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); +// m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder")); +// m_aircraft->fwRudder1ChannelBox->setEnabled(true); +// m_aircraft->fwRudder1Label->setEnabled(true); +// m_aircraft->fwRudder2ChannelBox->setEnabled(true); +// m_aircraft->fwRudder2Label->setEnabled(true); +// m_aircraft->fwElevator1ChannelBox->setEnabled(true); +// m_aircraft->fwElevator1Label->setEnabled(true); +// m_aircraft->fwElevator2ChannelBox->setEnabled(true); +// m_aircraft->fwElevator2Label->setEnabled(true); +// m_aircraft->fwAileron1ChannelBox->setEnabled(true); +// m_aircraft->fwAileron1Label->setEnabled(true); +// m_aircraft->fwAileron2ChannelBox->setEnabled(true); +// m_aircraft->fwAileron2Label->setEnabled(true); +// +// m_aircraft->fwAileron1Label->setText("Aileron 1"); +// m_aircraft->fwAileron2Label->setText("Aileron 2"); +// m_aircraft->fwElevator1Label->setText("Elevator 1"); +// m_aircraft->fwElevator2Label->setText("Elevator 2"); +// m_aircraft->elevonMixBox->setHidden(true); +// +// } else if (frameType == "FixedWingElevon" || frameType == "Elevon") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); +// m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon")); +// m_aircraft->fwAileron1Label->setText("Elevon 1"); +// m_aircraft->fwAileron2Label->setText("Elevon 2"); +// m_aircraft->fwElevator1ChannelBox->setEnabled(false); +// m_aircraft->fwElevator1Label->setEnabled(false); +// m_aircraft->fwElevator2ChannelBox->setEnabled(false); +// m_aircraft->fwElevator2Label->setEnabled(false); +// m_aircraft->fwRudder1ChannelBox->setEnabled(true); +// m_aircraft->fwRudder1Label->setEnabled(true); +// m_aircraft->fwRudder2ChannelBox->setEnabled(true); +// m_aircraft->fwRudder2Label->setEnabled(true); +// m_aircraft->fwElevator1Label->setText("Elevator 1"); +// m_aircraft->fwElevator2Label->setText("Elevator 2"); +// m_aircraft->elevonMixBox->setHidden(false); +// m_aircraft->elevonLabel1->setText("Roll"); +// m_aircraft->elevonLabel2->setText("Pitch"); +// +// } else if (frameType == "FixedWingVtail" || frameType == "Vtail") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing")); +// m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail")); +// m_aircraft->fwRudder1ChannelBox->setEnabled(false); +// m_aircraft->fwRudder1Label->setEnabled(false); +// m_aircraft->fwRudder2ChannelBox->setEnabled(false); +// m_aircraft->fwRudder2Label->setEnabled(false); +// m_aircraft->fwElevator1ChannelBox->setEnabled(true); +// m_aircraft->fwElevator1Label->setEnabled(true); +// m_aircraft->fwElevator1Label->setText("Vtail 1"); +// m_aircraft->fwElevator2Label->setText("Vtail 2"); +// m_aircraft->elevonMixBox->setHidden(false); +// m_aircraft->fwElevator2ChannelBox->setEnabled(true); +// m_aircraft->fwElevator2Label->setEnabled(true); +// m_aircraft->fwAileron1Label->setText("Aileron 1"); +// m_aircraft->fwAileron2Label->setText("Aileron 2"); +// m_aircraft->elevonLabel1->setText("Rudder"); +// m_aircraft->elevonLabel2->setText("Pitch"); + + } else if (frameType == "Tri" || frameType == "Tricopter Y" || + frameType == "QuadX" || frameType == "Quad X" || + frameType == "QuadP" || frameType == "Quad +" || + frameType == "Hexa" || frameType == "Hexacopter" || + frameType == "HexaX" || frameType == "Hexacopter X" || + frameType == "HexaCoax" || frameType == "Hexacopter Y6" || + frameType == "Octo" || frameType == "Octocopter" || + frameType == "OctoV" || frameType == "Octocopter V" || + frameType == "OctoCoaxP" || frameType == "Octo Coax +" ) { + + //Call multi-rotor setup UI + setupMultiRotorUI(frameType); + } +// } else if (frameType == "QuadX" || frameType == "Quad X") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X")); +// quad->setElementId("quad-X"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(false); +// m_aircraft->multiMotor6->setEnabled(false); +// m_aircraft->multiMotor7->setEnabled(false); +// m_aircraft->multiMotor8->setEnabled(false); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(50); +// m_aircraft->mrPitchMixLevel->setValue(50); +// m_aircraft->mrYawMixLevel->setValue(50); +// } else if (frameType == "QuadP" || frameType == "Quad +") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +")); +// quad->setElementId("quad-plus"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(false); +// m_aircraft->multiMotor6->setEnabled(false); +// m_aircraft->multiMotor7->setEnabled(false); +// m_aircraft->multiMotor8->setEnabled(false); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(100); +// m_aircraft->mrPitchMixLevel->setValue(100); +// m_aircraft->mrYawMixLevel->setValue(50); +// } else if (frameType == "Hexa" || frameType == "Hexacopter") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter")); +// quad->setElementId("quad-hexa"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(false); +// m_aircraft->multiMotor8->setEnabled(false); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(50); +// m_aircraft->mrPitchMixLevel->setValue(33); +// m_aircraft->mrYawMixLevel->setValue(33); +// } else if (frameType == "Octo" || frameType == "Octocopter") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter")); +// quad->setElementId("quad-octo"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(true); +// m_aircraft->multiMotor8->setEnabled(true); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(33); +// m_aircraft->mrPitchMixLevel->setValue(33); +// m_aircraft->mrYawMixLevel->setValue(25); +// } else if (frameType == "HexaX" || frameType == "Hexacopter X" ) { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X")); +// quad->setElementId("quad-hexa-H"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(false); +// m_aircraft->multiMotor8->setEnabled(false); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(33); +// m_aircraft->mrPitchMixLevel->setValue(50); +// m_aircraft->mrYawMixLevel->setValue(33); +// +// } else if (frameType == "OctoV" || frameType == "Octocopter V") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V")); +// quad->setElementId("quad-octo-v"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(true); +// m_aircraft->multiMotor8->setEnabled(true); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(25); +// m_aircraft->mrPitchMixLevel->setValue(25); +// m_aircraft->mrYawMixLevel->setValue(25); +// +// } else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +")); +// quad->setElementId("octo-coax-P"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(true); +// m_aircraft->multiMotor8->setEnabled(true); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(100); +// m_aircraft->mrPitchMixLevel->setValue(100); +// m_aircraft->mrYawMixLevel->setValue(50); +// +// } else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X")); +// quad->setElementId("octo-coax-X"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(true); +// m_aircraft->multiMotor8->setEnabled(true); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(50); +// m_aircraft->mrPitchMixLevel->setValue(50); +// m_aircraft->mrYawMixLevel->setValue(50); +// +// } else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6")); +// quad->setElementId("hexa-coax"); +// m_aircraft->multiMotor4->setEnabled(true); +// m_aircraft->multiMotor5->setEnabled(true); +// m_aircraft->multiMotor6->setEnabled(true); +// m_aircraft->multiMotor7->setEnabled(false); +// m_aircraft->multiMotor8->setEnabled(false); +// m_aircraft->triYawChannelBox->setEnabled(false); +// m_aircraft->mrRollMixLevel->setValue(100); +// m_aircraft->mrPitchMixLevel->setValue(50); +// m_aircraft->mrYawMixLevel->setValue(66); +// +// } else if (frameType == "Tri" || frameType == "Tricopter Y") { +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor")); +// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y")); +// quad->setElementId("tri"); +// m_aircraft->multiMotor4->setEnabled(false); +// m_aircraft->multiMotor5->setEnabled(false); +// m_aircraft->multiMotor6->setEnabled(false); +// m_aircraft->multiMotor7->setEnabled(false); +// m_aircraft->multiMotor8->setEnabled(false); +// m_aircraft->triYawChannelBox->setEnabled(true); +// + else if (frameType == "GroundVehicleCar" || frameType == "Turnable (car)" || + frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)" || + frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle") { + setupGroundVehicleUI(frameType); + +//// } else if (m_aircraft->aircraftType->currentText() == "Ground") { +// m_aircraft->differentialSteeringMixBox->setHidden(true); +// //STILL NEEDS WORK +// // Setup the UI +// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Ground")); +// +// m_aircraft->gvSteering1Label->setEnabled(true); +// m_aircraft->gvSteering1Label->setEnabled(true); +// m_aircraft->gvSteering2Label->setEnabled(true); +// m_aircraft->gvSteering2Label->setEnabled(true); +// m_aircraft->gvMotor1ChannelBox->setEnabled(true); +// m_aircraft->gvMotor1Label->setEnabled(true); +// m_aircraft->gvAileron1ChannelBox->setEnabled(true); +// m_aircraft->gvAileron1Label->setEnabled(true); +// m_aircraft->gvAileron2ChannelBox->setEnabled(true); +// m_aircraft->gvAileron2Label->setEnabled(true); +// +// if (frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)"){ +// m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Differential (tank)")); +// m_aircraft->gvMotor2ChannelBox->setEnabled(true); +// m_aircraft->gvMotor2Label->setEnabled(true); +// +// m_aircraft->gvMotor1Label->setText("Left motor"); +// m_aircraft->gvMotor2Label->setText("Right motor"); +// m_aircraft->differentialSteeringMixBox->setHidden(false); +// } +// else if (frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle"){ +// m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Motorcycle")); +// m_aircraft->gvMotor2ChannelBox->setEnabled(false); +// m_aircraft->gvMotor2Label->setEnabled(false); +// +// m_aircraft->gvMotor1Label->setText("Motor"); +// m_aircraft->gvMotor2Label->setText("Elevator 2"); +// m_aircraft->differentialSteeringMixBox->setHidden(true); +// } +// else { +// m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Turnable (car)")); +// +// m_aircraft->gvMotor2ChannelBox->setEnabled(true); +// m_aircraft->gvMotor2Label->setEnabled(true); +// +// m_aircraft->gvMotor1Label->setText("Front motor"); +// m_aircraft->gvMotor2Label->setText("Rear motor"); +// m_aircraft->differentialSteeringMixBox->setHidden(true); +// } + + } + + //SHOULDN'T THIS BE DONE ONLY IN QUAD SETUP, AND NOT ALL THE REST??? + m_aircraft->quadShape->setSceneRect(quad->boundingRect()); + m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio); + + setDirty(dirty); +} + +/** + Reset the contents of a field + */ +void ConfigVehicleTypeWidget::resetField(UAVObjectField * field) +{ + for (unsigned int i=0;igetNumElements();i++) { + field->setValue(0,i); + } +} + +/** + Reset actuator values + */ +void ConfigVehicleTypeWidget::resetActuators() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); + Q_ASSERT(obj); + QList fieldList = obj->getFields(); + // Reset all assignements first: + foreach (UAVObjectField* field, fieldList) { + // NOTE: we assume that all options in ActuatorSettings are a channel assignement + // except for the options called "ChannelBoxXXX" + if (field->getUnits().contains("channel")) { + field->setValue(field->getOptions().last()); + } + } +} +// +///** +// Setup Elevator/Aileron/Rudder airframe. +// +// If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing +// +// Returns False if impossible to create the mixer. +// */ +//bool ConfigVehicleTypeWidget::setupFrameFixedWing() +//{ +// // Check coherence: +// // - At least Pitch and either Roll or Yaw +// if (m_aircraft->fwEngineChannelBox->currentText() == "None" || +// m_aircraft->fwElevator1ChannelBox->currentText() == "None" || +// ((m_aircraft->fwAileron1ChannelBox->currentText() == "None") && +// (m_aircraft->fwRudder1ChannelBox->currentText() == "None"))) { +// // TODO: explain the problem in the UI +// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment"); +// return false; +// } +// // Now setup the channels: +// resetActuators(); +// +// UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// +// // Elevator +// UAVObjectField *field = obj->getField("FixedWingPitch1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwElevator1ChannelBox->currentText()); +// field = obj->getField("FixedWingPitch2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwElevator2ChannelBox->currentText()); +// // Aileron +// field = obj->getField("FixedWingRoll1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); +// field = obj->getField("FixedWingRoll2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); +// // Rudder +// field = obj->getField("FixedWingYaw1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwRudder1ChannelBox->currentText()); +// // Throttle +// field = obj->getField("FixedWingThrottle"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwEngineChannelBox->currentText()); +// +// obj->updated(); +// +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// // ... and compute the matrix: +// // In order to make code a bit nicer, we assume: +// // - ChannelBox dropdowns start with 'None', then 0 to 7 +// +// // 1. Assign the servo/motor/none for each channel +// // Disable all +// foreach(QString mixer, mixerTypes) { +// field = obj->getField(mixer); +// Q_ASSERT(field); +// field->setValue("Disabled"); +// } +// // and set only the relevant channels: +// // Engine +// int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Motor"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// // First of all reset the vector +// resetField(field); +// int ti = field->getElementNames().indexOf("ThrottleCurve1"); +// field->setValue(127, ti); +// +// // Rudder +// tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1; +// // tmpVal will be -1 if rudder is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Yaw"); +// field->setValue(127, ti); +// } // Else: we have no rudder, only ailerons, we're fine with it. +// +// // Ailerons +// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(127, ti); +// // Only set Aileron 2 if Aileron 1 is defined +// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(127, ti); +// } +// } // Else we have no ailerons. Our consistency check guarantees we have +// // rudder in this case, so we're fine with it too. +// +// // Elevator +// tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Pitch"); +// field->setValue(127, ti); +// // Only set Elevator 2 if it is defined +// tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Pitch"); +// field->setValue(127, ti); +// } +// +// obj->updated(); +// m_aircraft->fwStatusLabel->setText("Mixer generated"); +// +// return true; +//} +// +///** +// Setup Elevon +// */ +//bool ConfigVehicleTypeWidget::setupFrameElevon() +//{ +// // Check coherence: +// // - At least Aileron1 and Aileron 2, and engine +// if (m_aircraft->fwEngineChannelBox->currentText() == "None" || +// m_aircraft->fwAileron1ChannelBox->currentText() == "None" || +// m_aircraft->fwAileron2ChannelBox->currentText() == "None") { +// // TODO: explain the problem in the UI +// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment"); +// return false; +// } +// +// resetActuators(); +// UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// +// // Elevons +// UAVObjectField *field = obj->getField("FixedWingRoll1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); +// field = obj->getField("FixedWingRoll2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); +// // Rudder 1 (can be None) +// field = obj->getField("FixedWingYaw1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwRudder1ChannelBox->currentText()); +// // Rudder 2 (can be None) +// field = obj->getField("FixedWingYaw2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwRudder2ChannelBox->currentText()); +// // Throttle +// field = obj->getField("FixedWingThrottle"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwEngineChannelBox->currentText()); +// +// obj->updated(); +// +// // Save the curve: +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// // ... and compute the matrix: +// // In order to make code a bit nicer, we assume: +// // - ChannelBox dropdowns start with 'None', then 0 to 7 +// +// // 1. Assign the servo/motor/none for each channel +// // Disable all +// foreach(QString mixer, mixerTypes) { +// field = obj->getField(mixer); +// Q_ASSERT(field); +// field->setValue("Disabled"); +// } +// // and set only the relevant channels: +// // Engine +// int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Motor"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// // First of all reset the vector +// resetField(field); +// int ti = field->getElementNames().indexOf("ThrottleCurve1"); +// field->setValue(127, ti); +// +// // Rudder 1 +// tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1; +// // tmpVal will be -1 if rudder 1 is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Yaw"); +// field->setValue(127, ti); +// } // Else: we have no rudder, only elevons, we're fine with it. +// +// // Rudder 2 +// tmpVal = m_aircraft->fwRudder2ChannelBox->currentIndex()-1; +// // tmpVal will be -1 if rudder 2 is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Yaw"); +// field->setValue(-127, ti); +// } // Else: we have no rudder, only elevons, we're fine with it. +// +// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Pitch"); +// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti); +// } +// +// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Pitch"); +// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti); +// } +// +// obj->updated(); +// m_aircraft->fwStatusLabel->setText("Mixer generated"); +// return true; +//} +// +// +///** +// Setup VTail +// */ +//bool ConfigVehicleTypeWidget::setupFrameVtail() +//{ +// // Check coherence: +// // - At least Pitch1 and Pitch2, and engine +// if (m_aircraft->fwEngineChannelBox->currentText() == "None" || +// m_aircraft->fwElevator1ChannelBox->currentText() == "None" || +// m_aircraft->fwElevator2ChannelBox->currentText() == "None") { +// // TODO: explain the problem in the UI +// m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment"); +// return false; +// } +// +// resetActuators(); +// UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// +// // Elevons +// UAVObjectField *field = obj->getField("FixedWingPitch1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwElevator1ChannelBox->currentText()); +// field = obj->getField("FixedWingPitch2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwElevator2ChannelBox->currentText()); +// field = obj->getField("FixedWingRoll1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); +// field = obj->getField("FixedWingRoll2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); +// +// // Throttle +// field = obj->getField("FixedWingThrottle"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwEngineChannelBox->currentText()); +// +// obj->updated(); +// +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// // ... and compute the matrix: +// // In order to make code a bit nicer, we assume: +// // - ChannelBox dropdowns start with 'None', then 0 to 7 +// +// // 1. Assign the servo/motor/none for each channel +// // Disable all +// foreach(QString mixer, mixerTypes) { +// field = obj->getField(mixer); +// Q_ASSERT(field); +// field->setValue("Disabled"); +// } +// // and set only the relevant channels: +// // Engine +// int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Motor"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// // First of all reset the vector +// resetField(field); +// int ti = field->getElementNames().indexOf("ThrottleCurve1"); +// field->setValue(127, ti); +// +// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(127,ti); +// } +// +// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(-127,ti); +// } +// +// // Now compute the VTail +// tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Pitch"); +// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); +// ti = field->getElementNames().indexOf("Yaw"); +// field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti); +// +// tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Pitch"); +// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti); +// ti = field->getElementNames().indexOf("Yaw"); +// field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti); +// +// obj->updated(); +// m_aircraft->fwStatusLabel->setText("Mixer generated"); +// return true; +//} + + +///** +// Setup steerable ground vehicle. +// +// If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing +// +// Returns False if impossible to create the mixer. +// */ +//bool ConfigVehicleTypeWidget::setupGroundVehicle() +//{ +// // Check coherence: +// // - At least Pitch and either Roll or Yaw +// if ((m_aircraft->gvMotor1ChannelBox->currentText() == "None" && +// m_aircraft->gvMotor2ChannelBox->currentText() == "None") || +// (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && +// m_aircraft->gvSteering2ChannelBox->currentText() == "None")) { +// // TODO: explain the problem in the UI +// m_aircraft->gvStatusLabel->setText("ERROR: check channel assignments"); +// if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){ +// m_aircraft->gvStatusLabel->setText("ERROR: check motor channel assignment"); +// m_aircraft->gvMotor1Label->setText("" + m_aircraft->gvMotor1Label->text() + ""); +// m_aircraft->gvMotor2Label->setText("" + m_aircraft->gvMotor2Label->text() + ""); +// +// } +// else{ +// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText()); +// } +// +// if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") { +// m_aircraft->gvStatusLabel->setText("ERROR: check steering channel assignment"); +// m_aircraft->gvSteering1Label->setText("" + m_aircraft->gvSteering1Label->text() + ""); +// m_aircraft->gvSteering2Label->setText("" + m_aircraft->gvSteering2Label->text() + ""); +// } +// else{ +// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText()); +// } +// return false; +// } +// else{ +//// m_aircraft->gvStatusLabel->setText("Mixer generated"); +// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText()); +// delete htmlText; +// +// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags. +// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText()); +// +// +// +// +// } +// +////#if 0 +// // Now setup the channels: +// resetActuators(); +// +// UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// +// // Elevator +// UAVObjectField *field = obj->getField("FixedWingPitch1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->gvMotor1ChannelBox->currentText()); +// field = obj->getField("FixedWingPitch2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->gvMotor2ChannelBox->currentText()); +// // Aileron +// field = obj->getField("FixedWingRoll1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText()); +// field = obj->getField("FixedWingRoll2"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText()); +// // Rudder +// field = obj->getField("FixedWingYaw1"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->gvSteering1ChannelBox->currentText()); +// // Throttle +// field = obj->getField("FixedWingThrottle"); +// Q_ASSERT(field); +// field->setValue(m_aircraft->gvSteering2ChannelBox->currentText()); +// +// obj->updated(); +// +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// // ... and compute the matrix: +// // In order to make code a bit nicer, we assume: +// // - ChannelBox dropdowns start with 'None', then 0 to 7 +// +// // 1. Assign the servo/motor/none for each channel +// // Disable all +// foreach(QString mixer, mixerTypes) { +// field = obj->getField(mixer); +// Q_ASSERT(field); +// field->setValue("Disabled"); +// } +// +// int tmpVal, ti; +//#if 0 +// // and set only the relevant channels: +// // Engine +// tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Motor"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// // First of all reset the vector +// resetField(field); +// ti = field->getElementNames().indexOf("ThrottleCurve1"); +// field->setValue(127, ti); +//#endif +// // Steering +// tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1; +// // tmpVal will be -1 if steering is set to "None" +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Yaw"); +// field->setValue(127, ti); +// } // Else: we have no rudder, only ailerons, we're fine with it. +// +//#if 0 +// // Ailerons +// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(127, ti); +// // Only set Aileron 2 if Aileron 1 is defined +// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(127, ti); +// } +// } // Else we have no ailerons. Our consistency check guarantees we have +// // rudder in this case, so we're fine with it too. +//#endif +// +// // Motor +// tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1; +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("ThrottleCurve1"); +// field->setValue(127, ti); +// +// // Only set Motor 2 if it is defined +// tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1; +// if (tmpVal > -1) { +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// ti = field->getElementNames().indexOf("ThrottleCurve2"); +// field->setValue(127, ti); +// } +// +// obj->updated(); +////#endif +// m_aircraft->gvStatusLabel->setText("Mixer generated"); +// +// return true; +//} + + +/** + Set up a complete mixer, taking a table of factors. The factors + shoudl mainly be +/- 1 factors, since they will be weighted by the + value of the Pitch/Roll/Yaw sliders. + + Example: + double xMixer [8][3] = { + P R Y + { 1, 1, -1}, Motor 1 + { 1, -1, 1}, Motor 2 + {-1, -1, -1}, Motor 3 + {-1, 1, 1}, ... + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0}, + { 0, 0, 0} + }; + */ +//bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3]) +//{ +// qDebug()<<"Mixer factors"; +// qDebug()< mmList; +// mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3 +// << m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6 +// << m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8; +// UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// // 1. Assign the servo/motor/none for each channel +// // Disable all +// foreach(QString mixer, mixerTypes) { +// field = obj->getField(mixer); +// Q_ASSERT(field); +// field->setValue("Disabled"); +// } +// // and enable only the relevant channels: +// double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100; +// double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100; +// double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100; +// qDebug()<isEnabled()) +// { +// int channel = mmList.at(i)->currentIndex()-1; +// if (channel > -1) +// setupQuadMotor(channel, mixerFactors[i][0]*pFactor, +// rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]); +// } +// } +//// obj->updated(); +// return true; +//} + + +///** +// Helper function: setupQuadMotor +// */ +//void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw) +//{ +// qDebug()<(getObjectManager()->getObject(QString("MixerSettings"))); +// Q_ASSERT(obj); +// UAVObjectField *field = obj->getField(mixerTypes.at(channel)); +// field->setValue("Motor"); +// field = obj->getField(mixerVectors.at(channel)); +// // First of all reset the vector +// resetField(field); +// int ti = field->getElementNames().indexOf("ThrottleCurve1"); +// field->setValue(127, ti); +// ti = field->getElementNames().indexOf("Roll"); +// field->setValue(roll*127,ti); +// qDebug()<<"Set roll="<getElementNames().indexOf("Pitch"); +// field->setValue(pitch*127,ti); +// qDebug()<<"Set pitch="<getElementNames().indexOf("Yaw"); +// field->setValue(yaw*127,ti); +// qDebug()<<"Set yaw="< motorList) +//{ +// resetActuators(); +// UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// UAVObjectField *field; +// QList mmList; +// mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3 +// << m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6 +// << m_aircraft->multiMotor7 << m_aircraft->multiMotor8; +// foreach (QString motor, motorList) { +// field = obj->getField(motor); +// field->setValue(mmList.takeFirst()->currentText()); +// } +// //obj->updated(); // Save... +//} + + +///** +// Set up a Quad-X or Quad-P +//*/ +//bool ConfigVehicleTypeWidget::setupQuad(bool pLayout) +//{ +// // Check coherence: +// // - Four engines have to be defined +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 4 motor channels"); +// return false; +// } +// +// +// QList motorList; +// if (pLayout) { +// motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS" +// << "VTOLMotorW"; +// } else { +// motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE" +// << "VTOLMotorSW"; +// } +// setupMotors(motorList); +// +// // Now, setup the mixer: +// // Motor 1 to 4, X Layout: +// // pitch roll yaw +// // {0.5 ,0.5 ,-0.5 //Front left motor (CW) +// // {0.5 ,-0.5 ,0.5 //Front right motor(CCW) +// // {-0.5 ,-0.5 ,-0.5 //rear right motor (CW) +// // {-0.5 ,0.5 ,0.5 //Rear left motor (CCW) +// double xMixer [8][3] = { +// { 1, 1, -1}, +// { 1, -1, 1}, +// {-1, -1, -1}, +// {-1, 1, 1}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0} +// }; +// // +// // Motor 1 to 4, P Layout: +// // pitch roll yaw +// // {1 ,0 ,-0.5 //Front motor (CW) +// // {0 ,-1 ,0.5 //Right motor(CCW) +// // {-1 ,0 ,-0.5 //Rear motor (CW) +// // {0 ,1 ,0.5 //Left motor (CCW) +// double pMixer [8][3] = { +// { 1, 0, -1}, +// { 0, -1, 1}, +// {-1, 0, -1}, +// { 0, 1, 1}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0} +// }; +// +// if (pLayout) { +// setupMultiRotorMixer(pMixer); +// } else { +// setupMultiRotorMixer(xMixer); +// } +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// return true; +//} +// +// +// +///** +// Set up a Hexa-X or Hexa-P +//*/ +//bool ConfigVehicleTypeWidget::setupHexa(bool pLayout) +//{ +// // Check coherence: +// // - Four engines have to be defined +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None" || +// m_aircraft->multiMotor5->currentText() == "None" || +// m_aircraft->multiMotor6->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels"); +// return false; +// } +// +// QList motorList; +// if (pLayout) { +// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE" +// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW"; +// } else { +// motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" +// << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; +// } +// setupMotors(motorList); +// +// // and set only the relevant channels: +// +// // Motor 1 to 6, P Layout: +// // pitch roll yaw +// // 1 { 0.3 , 0 ,-0.3 // N CW +// // 2 { 0.3 ,-0.5 , 0.3 // NE CCW +// // 3 {-0.3 ,-0.5 ,-0.3 // SE CW +// // 4 {-0.3 , 0 , 0.3 // S CCW +// // 5 {-0.3 , 0.5 ,-0.3 // SW CW +// // 6 { 0.3 , 0.5 , 0.3 // NW CCW +// +// double pMixer [8][3] = { +// { 1, 0, -1}, +// { 1, -1, 1}, +// {-1, -1, -1}, +// {-1, 0, 1}, +// {-1, 1, -1}, +// { 1, 1, 1}, +// { 0, 0, 0}, +// { 0, 0, 0} +// }; +// +// // +// // Motor 1 to 6, X Layout: +// // 1 [ 0.5, -0.3, -0.3 ] NE +// // 2 [ 0 , -0.3, 0.3 ] E +// // 3 [ -0.5, -0.3, -0.3 ] SE +// // 4 [ -0.5, 0.3, 0.3 ] SW +// // 5 [ 0 , 0.3, -0.3 ] W +// // 6 [ 0.5, 0.3, 0.3 ] NW +// double xMixer [8][3] = { +// { 1, -1, -1}, +// { 0, -1, 1}, +// { -1, -1, -1}, +// { -1, 1, 1}, +// { 0, 1, -1}, +// { 1, 1, 1}, +// { 0, 0, 0}, +// { 0, 0, 0} +// }; +// +// if (pLayout) { +// setupMultiRotorMixer(pMixer); +// } else { +// setupMultiRotorMixer(xMixer); +// } +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// return true; +//} + + + +/** + Updates the custom airframe settings based on the current airframe. + + Note: does NOT ask for an object refresh itself! + */ +void ConfigVehicleTypeWidget::updateCustomAirframeUI() +{ + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); + QList curveValues; + // If the 1st element of the curve is <= -10, then the curve + // is a straight line (that's how the mixer works on the mainboard): + if (field->getValue(0).toInt() <= -10) { + m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1); + } else { + double temp=0; + double value; + for (unsigned int i=0; i < field->getNumElements(); i++) { + value=field->getValue(i).toDouble(); + temp+=value; + curveValues.append(value); + } + if(temp==0) + m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1); + else + m_aircraft->customThrottle1Curve->initCurve(curveValues); + } + + field = obj->getField(QString("ThrottleCurve2")); + curveValues.clear(); + // If the 1st element of the curve is <= -10, then the curve + // is a straight line (that's how the mixer works on the mainboard): + if (field->getValue(0).toInt() <= -10) { + m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1); + } else { + for (unsigned int i=0; i < field->getNumElements(); i++) { + curveValues.append(field->getValue(i).toDouble()); + } + m_aircraft->customThrottle2Curve->initCurve(curveValues); + } + + // Update the table: + for (int i=0; i<8; i++) { + field = obj->getField(mixerTypes.at(i)); + QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i); + QString s = field->getValue().toString(); + q->setCurrentIndex(q->findText(s)); + //bool en = (s != "Disabled"); + field = obj->getField(mixerVectors.at(i)); + int ti = field->getElementNames().indexOf("ThrottleCurve1"); + m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString()); + ti = field->getElementNames().indexOf("ThrottleCurve2"); + m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString()); + ti = field->getElementNames().indexOf("Roll"); + m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString()); + ti = field->getElementNames().indexOf("Pitch"); + m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString()); + ti = field->getElementNames().indexOf("Yaw"); + m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString()); + } +} + + +/** + Sends the config to the board (airframe type) + + We do all the tasks common to all airframes, or family of airframes, and + we call additional methods for specific frames, so that we do not have a code + that is too heavy. +*/ +void ConfigVehicleTypeWidget::updateObjectsFromWidgets() +{ + qDebug()<<"updateObjectsFromWidgets"; + QString airframeType = "Custom"; //Sets airframe type default to "Custom" + if (m_aircraft->aircraftType->currentText() == "Fixed Wing") { + if(1){ + airframeType = updateFixedWingObjectsFromWidgets(); + } + else{ + // // Save the curve (common to all Fixed wing frames) +// UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// // Remove Feed Forward, it is pointless on a plane: +// UAVObjectField* field = obj->getField(QString("FeedForward")); +// field->setDouble(0); +// field = obj->getField("ThrottleCurve1"); +// QList curve = m_aircraft->fixedWingThrottle->getCurve(); +// for (int i=0;isetValue(curve.at(i),i); +// } +// +// if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) { +// airframeType = "FixedWing"; +// setupFrameFixedWing(); +// } else if (m_aircraft->fixedWingType->currentText() == "Elevon") { +// airframeType = "FixedWingElevon"; +// setupFrameElevon(); +// } else { // "Vtail" +// airframeType = "FixedWingVtail"; +// setupFrameVtail(); +// } +// // Now reflect those settings in the "Custom" panel as well +// updateCustomAirframeUI(); + } + } else if (m_aircraft->aircraftType->currentText() == "Multirotor") { + + //update the mixer + if(1){ + airframeType = updateMultiRotorObjectsFromWidgets(); + } + else{ +// +// QList motorList; +// +// // We can already setup the feedforward here, as it is common to all platforms +// UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// UAVObjectField* field = obj->getField(QString("FeedForward")); +// field->setDouble((double)m_aircraft->feedForwardSlider->value()/100); +// field = obj->getField(QString("AccelTime")); +// field->setDouble(m_aircraft->accelTime->value()); +// field = obj->getField(QString("DecelTime")); +// field->setDouble(m_aircraft->decelTime->value()); +// field = obj->getField(QString("MaxAccel")); +// field->setDouble(m_aircraft->maxAccelSlider->value()); +// +// // Curve is also common to all quads: +// field = obj->getField("ThrottleCurve1"); +// QList curve = m_aircraft->multiThrottleCurve->getCurve(); +// for (int i=0;isetValue(curve.at(i),i); +// } +// +// if (m_aircraft->multirotorFrameType->currentText() == "Quad +") { +// airframeType = "QuadP"; +// setupQuad(true); +// } else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") { +// airframeType = "QuadX"; +// setupQuad(false); +// } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") { +// airframeType = "Hexa"; +// setupHexa(true); +// } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") { +// airframeType = "Octo"; +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None" || +// m_aircraft->multiMotor5->currentText() == "None" || +// m_aircraft->multiMotor6->currentText() == "None" || +// m_aircraft->multiMotor7->currentText() == "None" || +// m_aircraft->multiMotor8->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); +// return; +// } +// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" +// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; +// setupMotors(motorList); +// // Motor 1 to 8: +// // pitch roll yaw +// double mixer [8][3] = { +// { 1, 0, -1}, +// { 1, -1, 1}, +// { 0, -1, -1}, +// { -1, -1, 1}, +// { -1, 0, -1}, +// { -1, 1, 1}, +// { 0, 1, -1}, +// { 1, 1, 1} +// }; +// setupMultiRotorMixer(mixer); +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// +// } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") { +// airframeType = "HexaX"; +// setupHexa(false); +// } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") { +// airframeType = "OctoV"; +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None" || +// m_aircraft->multiMotor5->currentText() == "None" || +// m_aircraft->multiMotor6->currentText() == "None" || +// m_aircraft->multiMotor7->currentText() == "None" || +// m_aircraft->multiMotor8->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); +// return; +// } +// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" +// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; +// setupMotors(motorList); +// // Motor 1 to 8: +// // IMPORTANT: Assumes evenly spaced engines +// // pitch roll yaw +// double mixer [8][3] = { +// { 0.33, -1, -1}, +// { 1 , -1, 1}, +// { -1 , -1, -1}, +// { -0.33, -1, 1}, +// { -0.33, 1, -1}, +// { -1 , 1, 1}, +// { 1 , 1, -1}, +// { 0.33, 1, 1} +// }; +// setupMultiRotorMixer(mixer); +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// +// } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") { +// airframeType = "OctoCoaxP"; +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None" || +// m_aircraft->multiMotor5->currentText() == "None" || +// m_aircraft->multiMotor6->currentText() == "None" || +// m_aircraft->multiMotor7->currentText() == "None" || +// m_aircraft->multiMotor8->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); +// return; +// } +// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE" +// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW"; +// setupMotors(motorList); +// // Motor 1 to 8: +// // pitch roll yaw +// double mixer [8][3] = { +// { 1, 0, -1}, +// { 1, 0, 1}, +// { 0, -1, -1}, +// { 0, -1, 1}, +// { -1, 0, -1}, +// { -1, 0, 1}, +// { 0, 1, -1}, +// { 0, 1, 1} +// }; +// setupMultiRotorMixer(mixer); +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// +// } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") { +// airframeType = "OctoCoaxX"; +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None" || +// m_aircraft->multiMotor5->currentText() == "None" || +// m_aircraft->multiMotor6->currentText() == "None" || +// m_aircraft->multiMotor7->currentText() == "None" || +// m_aircraft->multiMotor8->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels"); +// return; +// } +// motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" +// << "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW"; +// setupMotors(motorList); +// // Motor 1 to 8: +// // pitch roll yaw +// double mixer [8][3] = { +// { 1, 1, -1}, +// { 1, 1, 1}, +// { 1, -1, -1}, +// { 1, -1, 1}, +// { -1, -1, -1}, +// { -1, -1, 1}, +// { -1, 1, -1}, +// { -1, 1, 1} +// }; +// setupMultiRotorMixer(mixer); +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// +// } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") { +// airframeType = "HexaCoax"; +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" || +// m_aircraft->multiMotor4->currentText() == "None" || +// m_aircraft->multiMotor5->currentText() == "None" || +// m_aircraft->multiMotor6->currentText() == "None" ) { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels"); +// return; +// } +// motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE" +// << "VTOLMotorS" << "VTOLMotorSE"; +// setupMotors(motorList); +// +// // Motor 1 to 6, Y6 Layout: +// // pitch roll yaw +// double mixer [8][3] = { +// { 0.5, 1, -1}, +// { 0.5, 1, 1}, +// { 0.5, -1, -1}, +// { 0.5, -1, 1}, +// { -1, 0, -1}, +// { -1, 0, 1}, +// { 0, 0, 0}, +// { 0, 0, 0} +// }; +// setupMultiRotorMixer(mixer); +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// +// } else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") { +// airframeType = "Tri"; +// if (m_aircraft->multiMotor1->currentText() == "None" || +// m_aircraft->multiMotor2->currentText() == "None" || +// m_aircraft->multiMotor3->currentText() == "None" ) { +// m_aircraft->mrStatusLabel->setText("ERROR: Assign 3 motor channels"); +// return; +// } +// if (m_aircraft->triYawChannelBoxBox->currentText() == "None") { +// m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel"); +// return; +// } +// motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS"; +// setupMotors(motorList); +// obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); +// Q_ASSERT(obj); +// field = obj->getField("FixedWingYaw1"); +// field->setValue(m_aircraft->triYawChannelBoxBox->currentText()); +// +// // Motor 1 to 6, Y6 Layout: +// // pitch roll yaw +// double mixer [8][3] = { +// { 0.5, 1, 0}, +// { 0.5, -1, 0}, +// { -1, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0}, +// { 0, 0, 0} +// }; +// setupMultiRotorMixer(mixer); +// +// int tmpVal = m_aircraft->triYawChannelBoxBox->currentIndex()-1; +// obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// field = obj->getField(mixerTypes.at(tmpVal)); +// field->setValue("Servo"); +// field = obj->getField(mixerVectors.at(tmpVal)); +// resetField(field); +// int ti = field->getElementNames().indexOf("Yaw"); +// field->setValue(127,ti); +// +// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK"); +// +// } +// // Now reflect those settings in the "Custom" panel as well +// updateCustomAirframeUI(); + } + + } else if (m_aircraft->aircraftType->currentText() == "Helicopter") { + airframeType = "HeliCP"; + m_aircraft->widget_3->sendccpmUpdate(); + } else if (m_aircraft->aircraftType->currentText() == "Ground") { + if(1){ + airframeType = updateGroundVehicleObjectsFromWidgets(); + } + else{ +// airframeType = "Ground"; +// // Save the curve (common to all ground vehicle frames) +// UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); +// UAVObjectField* field; +// +// if (0){ //DON'T REMOVE FEEDFORWARD +// // Remove Feed Forward, it is pointless on a plane: +// field = obj->getField(QString("FeedForward")); +// field->setDouble(0); +// } +// +// field = obj->getField("ThrottleCurve1"); +// QList curve = m_aircraft->groundVehicleThrottle->getCurve(); +// for (int i=0;isetValue(curve.at(i),i); +// } +// +// if (m_aircraft->groundVehicleType->currentText() == "Turnable (car)" ) { +// airframeType = "GroundVehicleCar"; +// setupGroundVehicle(); +// } else if (m_aircraft->groundVehicleType->currentText() == "Differential (tank)") { +// airframeType = "GroundVehicleDifferential"; +// setupGroundVehicle(); +// } else { // "Motorcycle" +// airframeType = "GroundVehicleMotorcycle"; +// setupGroundVehicle(); +// } +// +// +// // Now reflect those settings in the "Custom" panel as well +// updateCustomAirframeUI(); +// +//// m_aircraft->widget_3->sendccpmUpdate(); + } + } else { + airframeType = "Custom"; + + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + UAVObjectField* field = obj->getField(QString("FeedForward")); + + // Curve is also common to all quads: + field = obj->getField("ThrottleCurve1"); + QList curve = m_aircraft->customThrottle1Curve->getCurve(); + for (int i=0;isetValue(curve.at(i),i); + } + + field = obj->getField("ThrottleCurve2"); + curve.clear(); + curve = m_aircraft->customThrottle2Curve->getCurve(); + for (int i=0;isetValue(curve.at(i),i); + } + + // Update the table: + for (int i=0; i<8; i++) { + field = obj->getField(mixerTypes.at(i)); + QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i); + field->setValue(q->currentText()); + field = obj->getField(mixerVectors.at(i)); + int ti = field->getElementNames().indexOf("ThrottleCurve1"); + field->setValue(m_aircraft->customMixerTable->item(1,i)->text(),ti); + ti = field->getElementNames().indexOf("ThrottleCurve2"); + field->setValue(m_aircraft->customMixerTable->item(2,i)->text(),ti); + ti = field->getElementNames().indexOf("Roll"); + field->setValue(m_aircraft->customMixerTable->item(3,i)->text(),ti); + ti = field->getElementNames().indexOf("Pitch"); + field->setValue(m_aircraft->customMixerTable->item(4,i)->text(),ti); + ti = field->getElementNames().indexOf("Yaw"); + field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti); + } + + } + + //WHAT DOES THIS DO? + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); + UAVObjectField* field = obj->getField(QString("AirframeType")); + field->setValue(airframeType); + +} + +/** + Opens the wiki from the user's default browser + */ +void ConfigVehicleTypeWidget::openHelp() +{ + + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) ); +} + + +/** + WHAT DOES THIS DO??? + */ +void ConfigVehicleTypeWidget::addToDirtyMonitor() +{ + addWidget(m_aircraft->customMixerTable); + addWidget(m_aircraft->customThrottle1Curve); + addWidget(m_aircraft->customThrottle2Curve); + addWidget(m_aircraft->multiThrottleCurve); + addWidget(m_aircraft->fixedWingThrottle); + addWidget(m_aircraft->fixedWingType); + addWidget(m_aircraft->groundVehicleThrottle1); + addWidget(m_aircraft->groundVehicleThrottle2); + addWidget(m_aircraft->groundVehicleType); + addWidget(m_aircraft->feedForwardSlider); + addWidget(m_aircraft->accelTime); + addWidget(m_aircraft->decelTime); + addWidget(m_aircraft->maxAccelSlider); + addWidget(m_aircraft->multirotorFrameType); + addWidget(m_aircraft->multiMotorChannelBox1); + addWidget(m_aircraft->multiMotorChannelBox2); + addWidget(m_aircraft->multiMotorChannelBox3); + addWidget(m_aircraft->multiMotorChannelBox4); + addWidget(m_aircraft->multiMotorChannelBox5); + addWidget(m_aircraft->multiMotorChannelBox6); + addWidget(m_aircraft->multiMotorChannelBox7); + addWidget(m_aircraft->multiMotorChannelBox8); + addWidget(m_aircraft->triYawChannelBox); + addWidget(m_aircraft->aircraftType); + addWidget(m_aircraft->fwEngineChannelBox); + addWidget(m_aircraft->fwAileron1ChannelBox); + addWidget(m_aircraft->fwAileron2ChannelBox); + addWidget(m_aircraft->fwElevator1ChannelBox); + addWidget(m_aircraft->fwElevator2ChannelBox); + addWidget(m_aircraft->fwRudder1ChannelBox); + addWidget(m_aircraft->fwRudder2ChannelBox); + addWidget(m_aircraft->elevonSlider1); + addWidget(m_aircraft->elevonSlider2); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmType); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox); + addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider); + addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox); + addWidget(m_aircraft->widget_3->m_ccpm->CurveType); + addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints); + addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1); + addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2); + addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3); + addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate); + addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings); + addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve); + addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve); + addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable); +} + diff --git a/ground/openpilotgcs/src/plugins/config/configairframewidget.h b/ground/openpilotgcs/src/plugins/config/configvehicletypewidget.h similarity index 71% rename from ground/openpilotgcs/src/plugins/config/configairframewidget.h rename to ground/openpilotgcs/src/plugins/config/configvehicletypewidget.h index 5305e92f2..ad9a6a2e0 100644 --- a/ground/openpilotgcs/src/plugins/config/configairframewidget.h +++ b/ground/openpilotgcs/src/plugins/config/configvehicletypewidget.h @@ -24,8 +24,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef CONFIGAIRFRAMEWIDGET_H -#define CONFIGAIRFRAMEWIDGET_H +#ifndef CONFIGVEHICLETYPEWIDGET_H +#define CONFIGVEHICLETYPEWIDGET_H #include "ui_airframe.h" #include "../uavobjectwidgetutils/configtaskwidget.h" @@ -39,24 +39,27 @@ class Ui_Widget; -class ConfigAirframeWidget: public ConfigTaskWidget +class ConfigVehicleTypeWidget: public ConfigTaskWidget { Q_OBJECT public: - ConfigAirframeWidget(QWidget *parent = 0); - ~ConfigAirframeWidget(); + ConfigVehicleTypeWidget(QWidget *parent = 0); + ~ConfigVehicleTypeWidget(); private: Ui_AircraftWidget *m_aircraft; - bool setupFrameFixedWing(); - bool setupFrameElevon(); - bool setupFrameVtail(); + bool setupFrameFixedWing(QString airframeType); + bool setupFrameElevon(QString airframeType); + bool setupFrameVtail(QString airframeType); bool setupQuad(bool pLayout); bool setupHexa(bool pLayout); bool setupOcto(); + bool setupGroundVehicleCar(QString airframeType); + bool setupGroundVehicleDifferential(QString airframeType); + bool setupGroundVehicleMotorcycle(QString airframeType); void updateCustomAirframeUI(); - bool setupMixer(double mixerFactors[8][3]); + bool setupMultiRotorMixer(double mixerFactors[8][3]); void setupMotors(QList motorList); void addToDirtyMonitor(); void resetField(UAVObjectField * field); @@ -74,19 +77,39 @@ private: private slots: virtual void refreshWidgetsValues(); + void refreshFixedWingWidgetsValues(QString frameType); + void refreshMultiRotorWidgetsValues(QString frameType); + void refreshGroundVehicleWidgetsValues(QString frameType); + void updateObjectsFromWidgets(); + QString updateFixedWingObjectsFromWidgets(); + QString updateMultiRotorObjectsFromWidgets(); + QString updateGroundVehicleObjectsFromWidgets(); // void saveAircraftUpdate(); + void setupAirframeUI(QString type); + void setupFixedWingUI(QString frameType); + void setupMultiRotorUI(QString frameType); + void setupGroundVehicleUI(QString frameType); + + void throwMultiRotorChannelConfigError(int numMotors); + void throwFixedWingChannelConfigError(QString airframeType); + void throwGroundVehicleChannelConfigError(QString airframeType); + void toggleAileron2(int index); void toggleElevator2(int index); void toggleRudder2(int index); void switchAirframeType(int index); void resetFwMixer(); void resetMrMixer(); + void resetGvFrontMixer(); + void resetGvRearMixer(); void resetCt1Mixer(); void resetCt2Mixer(); void updateFwThrottleCurveValue(QList list, double value); void updateMrThrottleCurveValue(QList list, double value); + void updateGvThrottle1CurveValue(QList list, double value); + void updateGvThrottle2CurveValue(QList list, double value); void updateCustomThrottle1CurveValue(QList list, double value); void updateCustomThrottle2CurveValue(QList list, double value); void enableFFTest(); @@ -117,4 +140,4 @@ public: const QStyleOptionViewItem &option, const QModelIndex &index) const; }; -#endif // CONFIGAIRFRAMEWIDGET_H +#endif // CONFIGVEHICLETYPEWIDGET_H diff --git a/shared/uavobjectdefinition/actuatorsettings.xml b/shared/uavobjectdefinition/actuatorsettings.xml index 1524797b4..dd64dad15 100644 --- a/shared/uavobjectdefinition/actuatorsettings.xml +++ b/shared/uavobjectdefinition/actuatorsettings.xml @@ -1,31 +1,35 @@ - - - Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared/uavobjectdefinition/systemsettings.xml b/shared/uavobjectdefinition/systemsettings.xml index 22c0e8fd4..ec092df8e 100644 --- a/shared/uavobjectdefinition/systemsettings.xml +++ b/shared/uavobjectdefinition/systemsettings.xml @@ -1,7 +1,7 @@ Select airframe type. Currently used by @ref ActuatorModule to choose mixing from @ref ActuatorDesired to @ref ActuatorCommand - +