2011-05-30 07:29:26 +02:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
*
|
|
|
|
* @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 <QDebug>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QtGui/QWidget>
|
|
|
|
#include <QtGui/QTextEdit>
|
|
|
|
#include <QtGui/QVBoxLayout>
|
|
|
|
#include <QtGui/QPushButton>
|
|
|
|
#include <math.h>
|
2011-05-31 09:16:01 +02:00
|
|
|
#include <QDesktopServices>
|
|
|
|
#include <QUrl>
|
2011-09-20 23:14:48 +02:00
|
|
|
#include "systemsettings.h"
|
|
|
|
#include "mixersettings.h"
|
|
|
|
#include "actuatorsettings.h"
|
2011-09-25 20:30:32 +02:00
|
|
|
#include <QEventLoop>
|
2011-05-30 07:29:26 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
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<QSpinBox*>(editor);
|
|
|
|
spinBox->setValue(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
|
|
|
const QModelIndex &index) const
|
|
|
|
{
|
|
|
|
QSpinBox *spinBox = static_cast<QSpinBox*>(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);
|
|
|
|
|
2011-07-26 21:35:38 +02:00
|
|
|
setupButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD);
|
2011-08-02 18:06:17 +02:00
|
|
|
|
2011-07-26 21:35:38 +02:00
|
|
|
addUAVObject("SystemSettings");
|
|
|
|
addUAVObject("MixerSettings");
|
|
|
|
addUAVObject("ActuatorSettings");
|
|
|
|
|
|
|
|
|
2011-05-30 07:29:26 +02:00
|
|
|
ffTuningInProgress = false;
|
|
|
|
ffTuningPhase = false;
|
|
|
|
|
2011-10-11 09:05:24 +02:00
|
|
|
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);
|
|
|
|
}
|
2011-05-30 07:29:26 +02:00
|
|
|
|
|
|
|
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<UAVDataObject*>(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>,double)), this, SLOT(updateFwThrottleCurveValue(QList<double>,double)));
|
|
|
|
connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateMrThrottleCurveValue(QList<double>,double)));
|
|
|
|
connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle1CurveValue(QList<double>,double)));
|
|
|
|
connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle2CurveValue(QList<double>,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()));
|
|
|
|
|
2011-06-07 16:56:16 +02:00
|
|
|
enableControls(false);
|
2011-07-26 21:35:38 +02:00
|
|
|
refreshWidgetsValues();
|
2011-06-07 16:56:16 +02:00
|
|
|
|
2011-05-30 07:29:26 +02:00
|
|
|
|
2011-05-31 09:16:01 +02:00
|
|
|
// Connect the help button
|
|
|
|
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
2011-08-02 18:06:17 +02:00
|
|
|
addToDirtyMonitor();
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
2011-06-08 19:17:14 +02:00
|
|
|
resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Resets Multirotor throttle mixer
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::resetMrMixer()
|
|
|
|
{
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
2011-06-20 15:39:01 +02:00
|
|
|
resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Resets Custom throttle 1 mixer
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::resetCt1Mixer()
|
|
|
|
{
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
2011-06-08 19:17:14 +02:00
|
|
|
resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Resets Custom throttle 2 mixer
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::resetCt2Mixer()
|
|
|
|
{
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
|
2011-06-08 19:17:14 +02:00
|
|
|
resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Resets a mixer curve
|
|
|
|
*/
|
2011-06-08 19:17:14 +02:00
|
|
|
void ConfigAirframeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue)
|
2011-05-30 07:29:26 +02:00
|
|
|
{
|
|
|
|
// Setup all Throttle1 curves for all types of airframes
|
2011-06-12 01:49:05 +02:00
|
|
|
mixer->initLinearCurve((quint32)numElements,maxvalue);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Updates the currently moved throttle curve item value
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::updateFwThrottleCurveValue(QList<double> 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<double> 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<double> 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<double> list, double value)
|
|
|
|
{
|
|
|
|
Q_UNUSED(list);
|
|
|
|
m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
* Aircraft settings
|
|
|
|
**************************/
|
|
|
|
/**
|
2011-06-07 16:56:16 +02:00
|
|
|
Refreshes the current value of the SystemSettings which holds the aircraft type
|
2011-05-30 07:29:26 +02:00
|
|
|
*/
|
2011-07-26 21:35:38 +02:00
|
|
|
void ConfigAirframeWidget::refreshWidgetsValues()
|
2011-05-30 07:29:26 +02:00
|
|
|
{
|
2011-09-20 23:14:48 +02:00
|
|
|
if(!allObjectsUpdated())
|
|
|
|
return;
|
2011-08-02 18:06:17 +02:00
|
|
|
bool dirty=isDirty();
|
2011-05-30 07:29:26 +02:00
|
|
|
// Get the Airframe type from the system settings:
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(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<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
Q_ASSERT(obj);
|
|
|
|
field = obj->getField(QString("ThrottleCurve1"));
|
|
|
|
Q_ASSERT(field);
|
|
|
|
QList<double> 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) {
|
2011-06-12 01:49:05 +02:00
|
|
|
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1);
|
|
|
|
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
double temp=0;
|
2011-06-08 19:17:14 +02:00
|
|
|
double value;
|
2011-05-30 07:29:26 +02:00
|
|
|
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
2011-06-08 19:17:14 +02:00
|
|
|
value=field->getValue(i).toDouble();
|
|
|
|
temp+=value;
|
|
|
|
curveValues.append(value);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
2011-06-12 01:49:05 +02:00
|
|
|
if(temp==0)
|
|
|
|
{
|
2011-06-20 15:39:01 +02:00
|
|
|
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);;
|
2011-06-12 01:49:05 +02:00
|
|
|
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
|
2011-06-08 19:17:14 +02:00
|
|
|
}
|
2011-06-12 01:49:05 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_aircraft->multiThrottleCurve->initCurve(curveValues);
|
|
|
|
m_aircraft->fixedWingThrottle->initCurve(curveValues);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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;
|
2011-07-26 21:35:38 +02:00
|
|
|
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);
|
|
|
|
}
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
} 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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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();
|
2011-08-02 18:06:17 +02:00
|
|
|
setDirty(dirty);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\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)
|
|
|
|
{
|
2011-08-02 18:06:17 +02:00
|
|
|
bool dirty=isDirty();
|
2011-05-30 07:29:26 +02:00
|
|
|
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);
|
2011-08-02 18:06:17 +02:00
|
|
|
setDirty(dirty);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Reset the contents of a field
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::resetField(UAVObjectField * field)
|
|
|
|
{
|
|
|
|
for (unsigned int i=0;i<field->getNumElements();i++) {
|
|
|
|
field->setValue(0,i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Reset actuator values
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::resetActuators()
|
|
|
|
{
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
|
|
|
Q_ASSERT(obj);
|
|
|
|
QList<UAVObjectField*> 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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(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])
|
|
|
|
{
|
2011-09-27 23:10:39 +02:00
|
|
|
qDebug()<<"Mixer factors";
|
|
|
|
qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
|
|
|
|
qDebug()<<mixerFactors[1][0]<<" "<<mixerFactors[1][1]<<" "<<mixerFactors[1][2];
|
|
|
|
qDebug()<<mixerFactors[2][0]<<" "<<mixerFactors[2][1]<<" "<<mixerFactors[2][2];
|
|
|
|
qDebug()<<mixerFactors[3][0]<<" "<<mixerFactors[3][1]<<" "<<mixerFactors[3][2];
|
|
|
|
qDebug()<<mixerFactors[4][0]<<" "<<mixerFactors[4][1]<<" "<<mixerFactors[4][2];
|
|
|
|
qDebug()<<mixerFactors[5][0]<<" "<<mixerFactors[5][1]<<" "<<mixerFactors[5][2];
|
|
|
|
qDebug()<<mixerFactors[6][0]<<" "<<mixerFactors[6][1]<<" "<<mixerFactors[6][2];
|
|
|
|
qDebug()<<mixerFactors[7][0]<<" "<<mixerFactors[7][1]<<" "<<mixerFactors[7][2];
|
|
|
|
|
2011-05-30 07:29:26 +02:00
|
|
|
UAVObjectField *field;
|
|
|
|
QList<QComboBox*> 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<UAVDataObject*>(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;
|
2011-09-27 23:10:39 +02:00
|
|
|
qDebug()<<QString("pFactor=%0 rFactor=%1 yFactor=%2").arg(pFactor).arg(rFactor).arg(yFactor);
|
2011-05-30 07:29:26 +02:00
|
|
|
for (int i=0 ; i<8; i++) {
|
2011-09-27 23:10:39 +02:00
|
|
|
if(mmList.at(i)->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]);
|
|
|
|
}
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
2011-06-02 16:08:19 +02:00
|
|
|
// obj->updated();
|
2011-05-30 07:29:26 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Help function: setupQuadMotor
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
|
|
|
|
{
|
2011-09-27 23:10:39 +02:00
|
|
|
qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
|
2011-05-30 07:29:26 +02:00
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(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);
|
2011-09-27 23:10:39 +02:00
|
|
|
qDebug()<<"Set roll="<<roll*127;
|
2011-05-30 07:29:26 +02:00
|
|
|
ti = field->getElementNames().indexOf("Pitch");
|
|
|
|
field->setValue(pitch*127,ti);
|
2011-09-27 23:10:39 +02:00
|
|
|
qDebug()<<"Set pitch="<<pitch*127;
|
2011-05-30 07:29:26 +02:00
|
|
|
ti = field->getElementNames().indexOf("Yaw");
|
|
|
|
field->setValue(yaw*127,ti);
|
2011-09-27 23:10:39 +02:00
|
|
|
qDebug()<<"Set yaw="<<yaw*127;
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Helper function: setup motors. Takes a list of channel names in input.
|
|
|
|
*/
|
|
|
|
void ConfigAirframeWidget::setupMotors(QList<QString> motorList)
|
|
|
|
{
|
|
|
|
resetActuators();
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
|
|
|
Q_ASSERT(obj);
|
|
|
|
UAVObjectField *field;
|
|
|
|
QList<QComboBox*> 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());
|
|
|
|
}
|
2011-06-02 16:08:19 +02:00
|
|
|
//obj->updated(); // Save...
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
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<QString> 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<QString> 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<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
|
|
|
QList<double> 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) {
|
2011-06-12 01:49:05 +02:00
|
|
|
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
2011-05-30 07:29:26 +02:00
|
|
|
} else {
|
2011-06-12 01:49:05 +02:00
|
|
|
double temp=0;
|
2011-06-11 20:39:24 +02:00
|
|
|
double value;
|
2011-05-30 07:29:26 +02:00
|
|
|
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
2011-06-11 20:39:24 +02:00
|
|
|
value=field->getValue(i).toDouble();
|
|
|
|
temp+=value;
|
|
|
|
curveValues.append(value);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
2011-06-12 01:49:05 +02:00
|
|
|
if(temp==0)
|
|
|
|
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
|
|
|
else
|
|
|
|
m_aircraft->customThrottle1Curve->initCurve(curveValues);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
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) {
|
2011-06-12 01:49:05 +02:00
|
|
|
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
|
2011-05-30 07:29:26 +02:00
|
|
|
} else {
|
|
|
|
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
|
|
|
curveValues.append(field->getValue(i).toDouble());
|
|
|
|
}
|
2011-06-12 01:49:05 +02:00
|
|
|
m_aircraft->customThrottle2Curve->initCurve(curveValues);
|
2011-05-30 07:29:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
*/
|
2011-07-26 21:35:38 +02:00
|
|
|
void ConfigAirframeWidget::updateObjectsFromWidgets()
|
2011-05-30 07:29:26 +02:00
|
|
|
{
|
2011-07-26 21:35:38 +02:00
|
|
|
qDebug()<<"updateObjectsFromWidgets";
|
2011-05-30 07:29:26 +02:00
|
|
|
QString airframeType = "Custom";
|
|
|
|
if (m_aircraft->aircraftType->currentText() == "Fixed Wing") {
|
|
|
|
// Save the curve (common to all Fixed wing frames)
|
|
|
|
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(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<double> curve = m_aircraft->fixedWingThrottle->getCurve();
|
|
|
|
for (int i=0;i<curve.length();i++) {
|
|
|
|
field->setValue(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<QString> motorList;
|
|
|
|
|
|
|
|
// We can already setup the feedforward here, as it is common to all platforms
|
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(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<double> curve = m_aircraft->multiThrottleCurve->getCurve();
|
|
|
|
for (int i=0;i<curve.length();i++) {
|
|
|
|
field->setValue(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;
|
|
|
|
}
|
2011-06-02 16:08:19 +02:00
|
|
|
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
|
|
|
|
setupMotors(motorList);
|
2011-05-30 07:29:26 +02:00
|
|
|
obj = dynamic_cast<UAVDataObject*>(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<UAVDataObject*>(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<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
|
|
|
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
|
|
|
|
|
|
|
// Curve is also common to all quads:
|
|
|
|
field = obj->getField("ThrottleCurve1");
|
|
|
|
QList<double> curve = m_aircraft->customThrottle1Curve->getCurve();
|
|
|
|
for (int i=0;i<curve.length();i++) {
|
|
|
|
field->setValue(curve.at(i),i);
|
|
|
|
}
|
|
|
|
|
|
|
|
field = obj->getField("ThrottleCurve2");
|
|
|
|
curve.clear();
|
|
|
|
curve = m_aircraft->customThrottle2Curve->getCurve();
|
|
|
|
for (int i=0;i<curve.length();i++) {
|
|
|
|
field->setValue(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2011-07-26 21:35:38 +02:00
|
|
|
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
2011-05-30 07:29:26 +02:00
|
|
|
UAVObjectField* field = obj->getField(QString("AirframeType"));
|
|
|
|
field->setValue(airframeType);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-05-31 09:16:01 +02:00
|
|
|
void ConfigAirframeWidget::openHelp()
|
|
|
|
{
|
|
|
|
|
|
|
|
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
|
|
|
|
}
|
|
|
|
|
2011-08-01 14:28:58 +02:00
|
|
|
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->TabObject);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|