1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-09 20:46:07 +01:00
LibrePilot/ground/openpilotgcs/src/plugins/config/configccpmwidget.cpp

1811 lines
72 KiB
C++
Raw Normal View History

/**
******************************************************************************
*
* @file configccpmwidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief ccpm configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "configccpmwidget.h"
#include "mixersettings.h"
#include <QDebug>
#include <QStringList>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QBrush>
#include <math.h>
#include <QMessageBox>
#include "mixersettings.h"
#include "systemsettings.h"
#include "actuatorcommand.h"
#define Pi 3.14159265358979323846
ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
{
int i;
m_ccpm = new Ui_ccpmWidget();
m_ccpm->setupUi(this);
SwashLvlConfigurationInProgress=0;
SwashLvlState=0;
SwashLvlServoInterlock=0;
updatingFromHardware=FALSE;
updatingToHardware=FALSE;
// Now connect the widget to the ManualControlCommand / Channel UAVObject
//ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
//UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
// Initialization of the swashplaye widget
m_ccpm->SwashplateImage->setScene(new QGraphicsScene(this));
m_ccpm->SwashLvlSwashplateImage->setScene(m_ccpm->SwashplateImage->scene());
m_ccpm->SwashLvlSwashplateImage->setSceneRect(-50,-50,500,500);
//m_ccpm->SwashLvlSwashplateImage->scale(.85,.85);
//m_ccpm->SwashplateImage->setSceneRect(SwashplateImg->boundingRect());
m_ccpm->SwashplateImage->setSceneRect(-50,-30,500,500);
//m_ccpm->SwashplateImage->scale(.85,.85);
QSvgRenderer *renderer = new QSvgRenderer();
renderer->load(QString(":/configgadget/images/ccpm_setup.svg"));
SwashplateImg = new QGraphicsSvgItem();
SwashplateImg->setSharedRenderer(renderer);
SwashplateImg->setElementId("Swashplate");
SwashplateImg->setObjectName("Swashplate");
//SwashplateImg->setScale(0.75);
m_ccpm->SwashplateImage->scene()->addItem(SwashplateImg);
QFont serifFont("Times", 24, QFont::Bold);
QPen pen; // creates a default pen
pen.setStyle(Qt::DotLine);
pen.setWidth(2);
pen.setBrush(Qt::gray);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
QBrush brush(Qt::darkBlue);
QPen pen2; // creates a default pen
//pen2.setStyle(Qt::DotLine);
pen2.setWidth(1);
pen2.setBrush(Qt::blue);
//pen2.setCapStyle(Qt::RoundCap);
//pen2.setJoinStyle(Qt::RoundJoin);
//brush.setStyle(Qt::RadialGradientPattern);
QList<QString> ServoNames;
ServoNames << "ServoW" << "ServoX" << "ServoY" << "ServoZ" ;
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
ServoLines[i] = m_ccpm->SwashLvlSwashplateImage->scene()->addLine(0,0,100*i,i*i*100,pen);
Servos[i] = new QGraphicsSvgItem();
Servos[i]->setSharedRenderer(renderer);
Servos[i]->setElementId(ServoNames.at(i));
m_ccpm->SwashplateImage->scene()->addItem(Servos[i]);
ServosText[i] = new QGraphicsTextItem();
ServosText[i]->setDefaultTextColor(Qt::yellow);
ServosText[i]->setPlainText(QString("-"));
ServosText[i]->setFont(serifFont);
ServosTextCircles[i] = new QGraphicsEllipseItem(1,1,30,30);
ServosTextCircles[i]->setBrush(brush);
ServosTextCircles[i]->setPen(pen2);
m_ccpm->SwashplateImage->scene()->addItem(ServosTextCircles[i]);
m_ccpm->SwashplateImage->scene()->addItem(ServosText[i]);
SwashLvlSpinBoxes[i] = new QSpinBox(m_ccpm->SwashLvlSwashplateImage); // use QGraphicsView
m_ccpm->SwashLvlSwashplateImage->scene()->addWidget(SwashLvlSpinBoxes[i]);
SwashLvlSpinBoxes[i]->setMaximum(10000);
SwashLvlSpinBoxes[i]->setMinimum(0);
SwashLvlSpinBoxes[i]->setValue(0);
}
m_ccpm->PitchCurve->setMin(-1);
resetMixer(m_ccpm->PitchCurve, 5);
resetMixer(m_ccpm->ThrottleCurve, 5);
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
Q_ASSERT(mixerSettings);
UAVObjectField * curve2source = mixerSettings->getField("Curve2Source");
Q_ASSERT(curve2source);
QStringList channels;
channels << "Channel1" << "Channel2" << "Channel3" << "Channel4" <<
"Channel5" << "Channel6" << "Channel7" << "Channel8" << "None";
m_ccpm->ccpmEngineChannel->addItems(channels);
m_ccpm->ccpmEngineChannel->setCurrentIndex(8);
m_ccpm->ccpmTailChannel->addItems(channels);
m_ccpm->ccpmTailChannel->setCurrentIndex(8);
m_ccpm->ccpmServoWChannel->addItems(channels);
m_ccpm->ccpmServoWChannel->setCurrentIndex(8);
m_ccpm->ccpmServoXChannel->addItems(channels);
m_ccpm->ccpmServoXChannel->setCurrentIndex(8);
m_ccpm->ccpmServoYChannel->addItems(channels);
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->addItems(channels);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
QStringList Types;
2011-09-04 08:36:57 +02:00
Types << QString::fromUtf8("CCPM 2 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 90º") <<
QString::fromUtf8("CCPM 4 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 120º") <<
QString::fromUtf8("CCPM 3 Servo 140º") << QString::fromUtf8("FP 2 Servo 90º") <<
QString::fromUtf8("Custom - User Angles") << QString::fromUtf8("Custom - Advanced Settings");
m_ccpm->ccpmType->addItems(Types);
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1);
requestccpmUpdate();
UpdateCurveSettings();
//disable changing number of points in curves until UAVObjects have more than 5
m_ccpm->NumCurvePoints->setEnabled(0);
UpdateType();
//connect(m_ccpm->saveccpmToSD, SIGNAL(clicked()), this, SLOT(saveccpmUpdate()));
//connect(m_ccpm->saveccpmToRAM, SIGNAL(clicked()), this, SLOT(sendccpmUpdate()));
//connect(m_ccpm->getccpmCurrent, SIGNAL(clicked()), this, SLOT(requestccpmUpdate()));
connect(m_ccpm->ccpmGenerateCurve, SIGNAL(clicked()), this, SLOT(GenerateCurve()));
connect(m_ccpm->NumCurvePoints, SIGNAL(valueChanged(int)), this, SLOT(UpdateCurveSettings()));
connect(m_ccpm->CurveToGenerate, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings()));
connect(m_ccpm->CurveType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings()));
connect(m_ccpm->ccpmAngleW, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmAngleX, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmAngleY, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmAngleZ, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmCorrectionAngle, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoWChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoXChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoYChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoZChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmEngineChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmTailChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmRevoSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmREVOspinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmCollectiveSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmCollectivespinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType()));
connect(m_ccpm->ccpmSingleServo, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType()));
connect(m_ccpm->CurveSettings, SIGNAL(cellChanged (int, int)), this, SLOT(UpdateCurveWidgets()));
connect(m_ccpm->TabObject, SIGNAL(currentChanged ( QWidget * )), this, SLOT(UpdateType()));
// connect(m_ccpm->SwashLvlSwashplateImage, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateRedraw()));
connect(m_ccpm->PitchCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updatePitchCurveValue(QList<double>,double)));
connect(m_ccpm->ThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateThrottleCurveValue(QList<double>,double)));
connect(m_ccpm->SwashLvlStartButton, SIGNAL(clicked()), this, SLOT(SwashLvlStartButtonPressed()));
connect(m_ccpm->SwashLvlNextButton, SIGNAL(clicked()), this, SLOT(SwashLvlNextButtonPressed()));
connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed()));
connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed()));
connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
ccpmSwashplateRedraw();
}
ConfigccpmWidget::~ConfigccpmWidget()
{
// Do nothing
}
void ConfigccpmWidget::UpdateType()
{
int TypeInt,SingleServoIndex,NumServosDefined;
QString TypeText;
double AdjustmentAngle=0;
UpdateCCPMOptionsFromUI();
SetUIComponentVisibilities();
TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
TypeText = m_ccpm->ccpmType->currentText();
SingleServoIndex = m_ccpm->ccpmSingleServo->currentIndex();
//set visibility of user settings
m_ccpm->ccpmAdvancedSettingsTable->setEnabled(TypeInt==0);
m_ccpm->ccpmAdvancedSettingsTable->clearFocus();;
m_ccpm->ccpmAngleW->setEnabled(TypeInt==1);
m_ccpm->ccpmAngleX->setEnabled(TypeInt==1);
m_ccpm->ccpmAngleY->setEnabled(TypeInt==1);
m_ccpm->ccpmAngleZ->setEnabled(TypeInt==1);
m_ccpm->ccpmCorrectionAngle->setEnabled(TypeInt!=0);
m_ccpm->ccpmServoWChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmServoXChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmServoYChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmServoZChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmSingleServo->setEnabled(TypeInt>1);
m_ccpm->ccpmEngineChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmTailChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmCollectiveSlider->setEnabled(TypeInt>0);
m_ccpm->ccpmCollectivespinBox->setEnabled(TypeInt>0);
m_ccpm->ccpmRevoSlider->setEnabled(TypeInt>0);
m_ccpm->ccpmREVOspinBox->setEnabled(TypeInt>0);
AdjustmentAngle=SingleServoIndex*90;
m_ccpm->CurveToGenerate->setEnabled(1);
m_ccpm->CurveSettings->setColumnHidden(1,0);
m_ccpm->PitchCurve->setVisible(1);
//m_ccpm->customThrottleCurve2Value->setVisible(1);
//m_ccpm->label_41->setVisible(1);
NumServosDefined=4;
//set values for pre defined heli types
2011-09-04 08:36:57 +02:00
if (TypeText.compare(QString::fromUtf8("CCPM 2 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(0);
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleY->setEnabled(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoYChannel->setEnabled(0);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=2;
}
2011-09-04 08:36:57 +02:00
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360));
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=3;
}
2011-09-04 08:36:57 +02:00
if (TypeText.compare(QString::fromUtf8("CCPM 4 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360));
m_ccpm->ccpmAngleZ->setValue(fmod(AdjustmentAngle + 270,360));
//m_ccpm->ccpmCorrectionAngle->setValue(0);
m_ccpm->ccpmSingleServo->setEnabled(0);
m_ccpm->ccpmSingleServo->setCurrentIndex(0);
NumServosDefined=4;
}
2011-09-04 08:36:57 +02:00
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 120º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 120,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 240,360));
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=3;
}
2011-09-04 08:36:57 +02:00
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 140º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 140,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 220,360));
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=3;
}
2011-09-04 08:36:57 +02:00
if (TypeText.compare(QString::fromUtf8("FP 2 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(0);
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleY->setEnabled(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoYChannel->setEnabled(0);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
m_ccpm->ccpmCollectivespinBox->setEnabled(0);
m_ccpm->ccpmCollectiveSlider->setEnabled(0);
m_ccpm->ccpmCollectivespinBox->setValue(0);
m_ccpm->ccpmCollectiveSlider->setValue(0);
m_ccpm->CurveToGenerate->setCurrentIndex(0);
m_ccpm->CurveToGenerate->setEnabled(0);
m_ccpm->CurveSettings->setColumnHidden(1,1);
m_ccpm->PitchCurve->setVisible(0);
//m_ccpm->customThrottleCurve2Value->setVisible(0);
//m_ccpm->label_41->setVisible(0);
NumServosDefined=2;
}
//set the visibility of the swashplate servo selection boxes
m_ccpm->ccpmServoWLabel->setVisible(NumServosDefined>=1);
m_ccpm->ccpmServoXLabel->setVisible(NumServosDefined>=2);
m_ccpm->ccpmServoYLabel->setVisible(NumServosDefined>=3);
m_ccpm->ccpmServoZLabel->setVisible(NumServosDefined>=4);
m_ccpm->ccpmServoWChannel->setVisible(NumServosDefined>=1);
m_ccpm->ccpmServoXChannel->setVisible(NumServosDefined>=2);
m_ccpm->ccpmServoYChannel->setVisible(NumServosDefined>=3);
m_ccpm->ccpmServoZChannel->setVisible(NumServosDefined>=4);
//set the visibility of the swashplate angle selection boxes
m_ccpm->ccpmServoWLabel_2->setVisible(NumServosDefined>=1);
m_ccpm->ccpmServoXLabel_2->setVisible(NumServosDefined>=2);
m_ccpm->ccpmServoYLabel_2->setVisible(NumServosDefined>=3);
m_ccpm->ccpmServoZLabel_2->setVisible(NumServosDefined>=4);
m_ccpm->ccpmAngleW->setVisible(NumServosDefined>=1);
m_ccpm->ccpmAngleX->setVisible(NumServosDefined>=2);
m_ccpm->ccpmAngleY->setVisible(NumServosDefined>=3);
m_ccpm->ccpmAngleZ->setVisible(NumServosDefined>=4);
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
for (int i=0;i<6;i++) {
m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()-
m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6);
}
//update UI
ccpmSwashplateUpdate();
}
/**
Resets a mixer curve
*/
void ConfigccpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements)
{
2011-06-12 01:49:05 +02:00
mixer->initLinearCurve(numElements,(double)1);
}
void ConfigccpmWidget::UpdateCurveWidgets()
{
int NumCurvePoints,i,Changed;
QList<double> curveValues;
QList<double> OldCurveValues;
double ThisValue;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
curveValues.clear();
Changed=0;
OldCurveValues=m_ccpm->ThrottleCurve->getCurve();
for (i=0; i<NumCurvePoints; i++)
{
ThisValue=m_ccpm->CurveSettings->item(i, 0 )->text().toDouble();
curveValues.append(ThisValue);
if (ThisValue!=OldCurveValues.at(i))Changed=1;
}
// Setup all Throttle1 curves for all types of airframes
if (Changed==1)m_ccpm->ThrottleCurve->setCurve(curveValues);
curveValues.clear();
Changed=0;
OldCurveValues=m_ccpm->PitchCurve->getCurve();
for (i=0; i<NumCurvePoints; i++)
{
ThisValue=m_ccpm->CurveSettings->item(i, 1 )->text().toDouble();
curveValues.append(ThisValue);
if (ThisValue!=OldCurveValues.at(i))Changed=1;
}
// Setup all Throttle1 curves for all types of airframes
if (Changed==1)m_ccpm->PitchCurve->setCurve(curveValues);
}
void ConfigccpmWidget::updatePitchCurveValue(QList<double> curveValues0,double Value0)
{
Q_UNUSED(curveValues0);
Q_UNUSED(Value0);
int NumCurvePoints,i;
double CurrentValue;
QList<double> internalCurveValues;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
internalCurveValues=m_ccpm->PitchCurve->getCurve();
for (i=0; i<internalCurveValues.length(); i++)
{
CurrentValue=m_ccpm->CurveSettings->item(i, 1 )->text().toDouble();
if (CurrentValue!=internalCurveValues[i])
{
m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",internalCurveValues.at(i)));
}
}
}
void ConfigccpmWidget::updateThrottleCurveValue(QList<double> curveValues0,double Value0)
{
Q_UNUSED(curveValues0);
Q_UNUSED(Value0);
int NumCurvePoints,i;
double CurrentValue;
QList<double> internalCurveValues;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
internalCurveValues=m_ccpm->ThrottleCurve->getCurve();
for (i=0; i<internalCurveValues.length(); i++)
{
CurrentValue=m_ccpm->CurveSettings->item(i, 1 )->text().toDouble();
if (CurrentValue!=internalCurveValues[i])
{
m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",internalCurveValues.at(i)));
}
}
}
void ConfigccpmWidget::UpdateCurveSettings()
{
int NumCurvePoints,i;
double scale;
QString CurveType;
QStringList vertHeaders;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
CurveType=m_ccpm->CurveType->currentText();
vertHeaders << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" ;
for (i=0;i<NumCurvePoints;i++)
{
scale =((double)i/(double)(NumCurvePoints-1));
vertHeaders[i] = tr( "%1%" ).arg(100.00*scale, 0, 'f', 1);
}
m_ccpm->CurveSettings->setVerticalHeaderLabels( vertHeaders );
if (m_ccpm->CurveToGenerate->currentIndex()==0)
{
m_ccpm->CurveValue1->setMinimum(0.0);
m_ccpm->CurveValue2->setMinimum(0.0);
m_ccpm->CurveValue3->setMinimum(0.0);
}
else
{
m_ccpm->CurveValue1->setMinimum(-1.0);
m_ccpm->CurveValue2->setMinimum(-1.0);
m_ccpm->CurveValue3->setMinimum(0.0);
}
m_ccpm->CurveValue1->setMaximum(1.0);
m_ccpm->CurveValue2->setMaximum(1.0);
m_ccpm->CurveValue3->setMaximum(100.0);
m_ccpm->CurveValue1->setSingleStep(0.1);
m_ccpm->CurveValue2->setSingleStep(0.1);
m_ccpm->CurveValue3->setSingleStep(1.0);
m_ccpm->CurveValue1->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);;
m_ccpm->CurveValue2->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
if ( CurveType.compare("Flat")==0)
{
m_ccpm->CurveLabel1->setText("Value");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setVisible(false);
m_ccpm->CurveValue2->setVisible(false);
m_ccpm->CurveLabel3->setVisible(false);
m_ccpm->CurveValue3->setVisible(false);
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Linear")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setVisible(false);
m_ccpm->CurveValue3->setVisible(false);
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Step")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setText("Step at");
m_ccpm->CurveLabel3->setVisible(true);
m_ccpm->CurveValue3->setVisible(true);
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Exp")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setText("Strength");
m_ccpm->CurveLabel3->setVisible(true);
m_ccpm->CurveValue3->setVisible(true);
m_ccpm->CurveValue3->setMinimum(1.0);
m_ccpm->CurveValue3->setMaximum(100.0);
m_ccpm->CurveValue3->setSingleStep(1.0);
m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);;
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Log")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setText("Strength");
m_ccpm->CurveLabel3->setVisible(true);
m_ccpm->CurveValue3->setVisible(true);
m_ccpm->CurveValue3->setMinimum(1.0);
m_ccpm->CurveValue3->setMaximum(100.0);
m_ccpm->CurveValue3->setSingleStep(1.0);
m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);;
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Custom")==0)
{
m_ccpm->CurveLabel1->setVisible(false);
m_ccpm->CurveValue1->setVisible(false);
m_ccpm->CurveLabel2->setVisible(false);
m_ccpm->CurveValue2->setVisible(false);
m_ccpm->CurveLabel3->setVisible(false);
m_ccpm->CurveValue3->setVisible(false);
m_ccpm->ccpmGenerateCurve->setVisible(false);
m_ccpm->CurveToGenerate->setVisible(false);
}
UpdateCurveWidgets();
}
void ConfigccpmWidget::GenerateCurve()
{
int NumCurvePoints,CurveToGenerate,i;
double value1, value2, value3, scale;
QString CurveType;
QTableWidgetItem *item;
double newValue;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
value1=m_ccpm->CurveValue1->value();
value2=m_ccpm->CurveValue2->value();
value3=m_ccpm->CurveValue3->value();
CurveToGenerate=m_ccpm->CurveToGenerate->currentIndex();
CurveType=m_ccpm->CurveType->currentText();
for (i=0;i<NumCurvePoints;i++)
{
scale =((double)i/(double)(NumCurvePoints-1));
item =m_ccpm->CurveSettings->item(i, CurveToGenerate );
if ( CurveType.compare("Flat")==0)
{
//item->setText( tr( "%1" ).arg( value1 ) );
item->setText(QString().sprintf("%.3f",value1));
}
if ( CurveType.compare("Linear")==0)
{
newValue =value1 +(scale*(value2-value1));
//item->setText( tr( "%1" ).arg(value1 +(scale*(value2-value1))) );
item->setText(QString().sprintf("%.3f",newValue));
}
if ( CurveType.compare("Step")==0)
{
if (scale*100<value3)
{
//item->setText( tr( "%1" ).arg(value1) );
item->setText(QString().sprintf("%.3f",value1));
}
else
{
//item->setText( tr( "%1" ).arg(value2) );
item->setText(QString().sprintf("%.3f",value2));
}
}
if ( CurveType.compare("Exp")==0)
{
newValue =value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1));
//item->setText( tr( "%1" ).arg(value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1))) );
item->setText(QString().sprintf("%.3f",newValue));
}
if ( CurveType.compare("Log")==0)
{
newValue = value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1));
//item->setText( tr( "%1" ).arg(value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1))) );
item->setText(QString().sprintf("%.3f",newValue));
}
}
for (i=NumCurvePoints;i<10;i++)
{
item =m_ccpm->CurveSettings->item(i, CurveToGenerate );
item->setText( tr( "" ) );
}
UpdateCurveWidgets();
}
void ConfigccpmWidget::ccpmSwashplateRedraw()
{
double angle[CCPM_MAX_SWASH_SERVOS],CorrectionAngle,x,y,w,h,radius,CenterX,CenterY;
int used[CCPM_MAX_SWASH_SERVOS],defined[CCPM_MAX_SWASH_SERVOS],i;
QRectF bounds;
QRect size;
double scale,xscale,yscale;
size = m_ccpm->SwashplateImage->rect();
xscale=size.width();
yscale=size.height();
scale=xscale;
if (yscale<scale)scale=yscale;
scale/=460.00;
m_ccpm->SwashplateImage->resetTransform ();
m_ccpm->SwashplateImage->scale(scale,scale);
size = m_ccpm->SwashLvlSwashplateImage->rect();
xscale=size.width();
yscale=size.height();
scale=xscale;
if (yscale<scale)scale=yscale;
scale/=590.00;
m_ccpm->SwashLvlSwashplateImage->resetTransform ();
m_ccpm->SwashLvlSwashplateImage->scale(scale,scale);
CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value();
CenterX=200;
CenterY=200;
bounds=SwashplateImg->boundingRect();
SwashplateImg->setPos(CenterX-bounds.width()/2,CenterY-bounds.height()/2);
defined[0]=(m_ccpm->ccpmServoWChannel->isEnabled());
defined[1]=(m_ccpm->ccpmServoXChannel->isEnabled());
defined[2]=(m_ccpm->ccpmServoYChannel->isEnabled());
defined[3]=(m_ccpm->ccpmServoZChannel->isEnabled());
used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
angle[0]=(CorrectionAngle+180+m_ccpm->ccpmAngleW->value())*Pi/180.00;
angle[1]=(CorrectionAngle+180+m_ccpm->ccpmAngleX->value())*Pi/180.00;
angle[2]=(CorrectionAngle+180+m_ccpm->ccpmAngleY->value())*Pi/180.00;
angle[3]=(CorrectionAngle+180+m_ccpm->ccpmAngleZ->value())*Pi/180.00;
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
radius=210;
x=CenterX-(radius*sin(angle[i]))-10.00;
y=CenterY+(radius*cos(angle[i]))-10.00;
Servos[i]->setPos(x, y);
Servos[i]->setVisible(used[i]!=0);
radius=150;
bounds=ServosText[i]->boundingRect();
x=CenterX-(radius*sin(angle[i]))-bounds.width()/2;
y=CenterY+(radius*cos(angle[i]))-bounds.height()/2;
ServosText[i]->setPos(x, y);
ServosText[i]->setVisible(used[i]!=0);
if (bounds.width()>bounds.height())
{
bounds.setHeight(bounds.width());
}
else
{
bounds.setWidth(bounds.height());
}
x=CenterX-(radius*sin(angle[i]))-bounds.width()/2;
y=CenterY+(radius*cos(angle[i]))-bounds.height()/2;
ServosTextCircles[i]->setRect(bounds);
ServosTextCircles[i]->setPos(x, y);
ServosTextCircles[i]->setVisible(used[i]!=0);
w=SwashLvlSpinBoxes[i]->width()/2;
h=SwashLvlSpinBoxes[i]->height()/2;
radius = (215.00+w+h);
x=CenterX-(radius*sin(angle[i]))-w;
y=CenterY+(radius*cos(angle[i]))-h;
SwashLvlSpinBoxes[i]->move(m_ccpm->SwashLvlSwashplateImage->mapFromScene (x, y));
SwashLvlSpinBoxes[i]->setVisible(used[i]!=0);
radius=220;
x=CenterX-(radius*sin(angle[i]));
y=CenterY+(radius*cos(angle[i]));
ServoLines[i]->setLine(CenterX,CenterY,x,y);
ServoLines[i]->setVisible(defined[i]!=0);
}
//m_ccpm->SwashplateImage->centerOn (CenterX, CenterY);
//m_ccpm->SwashplateImage->fitInView(SwashplateImg, Qt::KeepAspectRatio);
}
void ConfigccpmWidget::ccpmSwashplateUpdate()
{
ccpmSwashplateRedraw();
SetUIComponentVisibilities();
UpdateMixer();
}
void ConfigccpmWidget::ccpmChannelCheck()
{
if((m_ccpm->ccpmServoWChannel->currentIndex()==8)&&(m_ccpm->ccpmServoWChannel->isEnabled()))
{
m_ccpm->ccpmServoWLabel->setText("<font color=red>Servo W</font>");
}
else
{
m_ccpm->ccpmServoWLabel->setText("<font color=black>Servo W</font>");
}
if((m_ccpm->ccpmServoXChannel->currentIndex()==8)&&(m_ccpm->ccpmServoXChannel->isEnabled()))
{
m_ccpm->ccpmServoXLabel->setText("<font color=red>Servo X</font>");
}
else
{
m_ccpm->ccpmServoXLabel->setText("<font color=black>Servo X</font>");
}
if((m_ccpm->ccpmServoYChannel->currentIndex()==8)&&(m_ccpm->ccpmServoYChannel->isEnabled()))
{
m_ccpm->ccpmServoYLabel->setText("<font color=red>Servo Y</font>");
}
else
{
m_ccpm->ccpmServoYLabel->setText("<font color=black>Servo Y</font>");
}
if((m_ccpm->ccpmServoZChannel->currentIndex()==8)&&(m_ccpm->ccpmServoZChannel->isEnabled()))
{
m_ccpm->ccpmServoZLabel->setText("<font color=red>Servo Z</font>");
}
else
{
m_ccpm->ccpmServoZLabel->setText("<font color=black>Servo Z</font>");
}
if((m_ccpm->ccpmEngineChannel->currentIndex()==8)&&(m_ccpm->ccpmEngineChannel->isEnabled()))
{
m_ccpm->ccpmEngineLabel->setText("<font color=red>Engine</font>");
}
else
{
m_ccpm->ccpmEngineLabel->setText("<font color=black>Engine</font>");
}
if((m_ccpm->ccpmTailChannel->currentIndex()==8)&&(m_ccpm->ccpmTailChannel->isEnabled()))
{
m_ccpm->ccpmTailLabel->setText("<font color=red>Tail Rotor</font>");
}
else
{
m_ccpm->ccpmTailLabel->setText("<font color=black>Tail Rotor</font>");
}
}
void ConfigccpmWidget::UpdateMixer()
{
bool useCCPM;
bool useCyclic;
int i,j,ThisEnable[6];
float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6];
QString Channel;
ccpmChannelCheck();
UpdateCCPMOptionsFromUI();
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
CollectiveConstant = (float)GUIConfigData.heli.SliderValue0 / 100.00;
if (useCCPM)
{//cyclic = 1 - collective
PitchConstant = 1-CollectiveConstant;
RollConstant = PitchConstant;
}
else
{
PitchConstant = (float)GUIConfigData.heli.SliderValue1 / 100.00;;
if (useCyclic)
{
RollConstant = PitchConstant;
}
else
{
RollConstant = (float)GUIConfigData.heli.SliderValue2 / 100.00;;
}
}
if (GUIConfigData.heli.SwasplateType>0)
{//not advanced settings
//get the channel data from the ui
MixerChannelData[0] = m_ccpm->ccpmEngineChannel->currentIndex();
MixerChannelData[1] = m_ccpm->ccpmTailChannel->currentIndex();
MixerChannelData[2] = m_ccpm->ccpmServoWChannel->currentIndex();
MixerChannelData[3] = m_ccpm->ccpmServoXChannel->currentIndex();
MixerChannelData[4] = m_ccpm->ccpmServoYChannel->currentIndex();
MixerChannelData[5] = m_ccpm->ccpmServoZChannel->currentIndex();
//get the angle data from the ui
ThisAngle[2] = m_ccpm->ccpmAngleW->value();
ThisAngle[3] = m_ccpm->ccpmAngleX->value();
ThisAngle[4] = m_ccpm->ccpmAngleY->value();
ThisAngle[5] = m_ccpm->ccpmAngleZ->value();
//get the angle data from the ui
ThisEnable[2] = m_ccpm->ccpmServoWChannel->isEnabled();
ThisEnable[3] = m_ccpm->ccpmServoXChannel->isEnabled();
ThisEnable[4] = m_ccpm->ccpmServoYChannel->isEnabled();
ThisEnable[5] = m_ccpm->ccpmServoZChannel->isEnabled();
ServosText[0]->setPlainText(QString("%1").arg( MixerChannelData[2]+1 ));
ServosText[1]->setPlainText(QString("%1").arg( MixerChannelData[3]+1 ));
ServosText[2]->setPlainText(QString("%1").arg( MixerChannelData[4]+1 ));
ServosText[3]->setPlainText(QString("%1").arg( MixerChannelData[5]+1 ));
//go through the user data and update the mixer matrix
for (i=0;i<6;i++)
{
if ((MixerChannelData[i]<8)&&((ThisEnable[i])||(i<2)))
{
m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->setText(QString("%1").arg( MixerChannelData[i]+1 ));
//config the vector
if (i==0)
{//motor-engine
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(127));//ThrottleCurve1
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg(0));//ThrottleCurve2
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg(0));//Roll
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg(0));//Pitch
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw
}
if (i==1)
{//tailrotor
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg(0));//ThrottleCurve2
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg(0));//Roll
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg(0));//Pitch
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(127));//Yaw
}
if (i>1)
{//Swashplate
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg((int)(127.0*CollectiveConstant)));//ThrottleCurve2
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(RollConstant)*sin((180+GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(PitchConstant)*cos((GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw
}
}
else
{
for (j=0;j<6;j++) m_ccpm->ccpmAdvancedSettingsTable->item(i,j)->setText(QString("-"));
}
}
}
else
{//advanced settings
for (i=0;i<6;i++)
{
Channel =m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->text();
if (Channel == "-") Channel = QString("9");
MixerChannelData[i]= Channel.toInt();
}
}
}
/**************************
* ccpm settings
**************************/
/*
Get the state of the UI check boxes and change the visibility of sliders
typedef struct {
uint SwasplateType:3;
uint FirstServoIndex:2;
uint CorrectionAngle:9;
uint ccpmCollectivePassthroughState:1;
uint ccpmLinkCyclicState:1;
uint ccpmLinkRollState:1;
uint CollectiveChannel:3;
uint padding:12;
} __attribute__((packed)) heliGUISettingsStruct;
*/
void ConfigccpmWidget::UpdateCCPMOptionsFromUI()
{
bool useCCPM;
bool useCyclic;
if (updatingFromHardware) return;
//get the user options
//swashplate config
GUIConfigData.heli.SwasplateType = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
GUIConfigData.heli.FirstServoIndex = m_ccpm->ccpmSingleServo->currentIndex();
//ccpm mixing options
GUIConfigData.heli.ccpmCollectivePassthroughState = m_ccpm->ccpmCollectivePassthrough->isChecked();
GUIConfigData.heli.ccpmLinkCyclicState = m_ccpm->ccpmLinkCyclic->isChecked();
GUIConfigData.heli.ccpmLinkRollState = m_ccpm->ccpmLinkRoll->isChecked();
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
//correction angle
GUIConfigData.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value();
//update sliders
if (useCCPM)
{
GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveSlider->value();
}
else
{
GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveScale->value();
}
if (useCyclic)
{
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmCyclicScale->value();
}
else
{
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value();
}
GUIConfigData.heli.SliderValue2 = m_ccpm->ccpmRollScale->value();
//servo assignments
GUIConfigData.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex();
GUIConfigData.heli.ServoIndexX = m_ccpm->ccpmServoXChannel->currentIndex();
GUIConfigData.heli.ServoIndexY = m_ccpm->ccpmServoYChannel->currentIndex();
GUIConfigData.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex();
}
void ConfigccpmWidget::UpdateCCPMUIFromOptions()
{
//swashplate config
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - (GUIConfigData.heli.SwasplateType +1));
m_ccpm->ccpmSingleServo->setCurrentIndex(GUIConfigData.heli.FirstServoIndex);
//ccpm mixing options
m_ccpm->ccpmCollectivePassthrough->setChecked(GUIConfigData.heli.ccpmCollectivePassthroughState);
m_ccpm->ccpmLinkCyclic->setChecked(GUIConfigData.heli.ccpmLinkCyclicState);
m_ccpm->ccpmLinkRoll->setChecked(GUIConfigData.heli.ccpmLinkRollState);
//correction angle
m_ccpm->ccpmCorrectionAngle->setValue(GUIConfigData.heli.CorrectionAngle);
//update sliders
m_ccpm->ccpmCollectiveScale->setValue(GUIConfigData.heli.SliderValue0);
m_ccpm->ccpmCollectiveScaleBox->setValue(GUIConfigData.heli.SliderValue0);
m_ccpm->ccpmCyclicScale->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmCyclicScaleBox->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmPitchScale->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmPitchScaleBox->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmRollScale->setValue(GUIConfigData.heli.SliderValue2);
m_ccpm->ccpmRollScaleBox->setValue(GUIConfigData.heli.SliderValue2);
m_ccpm->ccpmCollectiveSlider->setValue(GUIConfigData.heli.SliderValue0);
m_ccpm->ccpmCollectivespinBox->setValue(GUIConfigData.heli.SliderValue0);
//servo assignments
m_ccpm->ccpmServoWChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexW);
m_ccpm->ccpmServoXChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexX);
m_ccpm->ccpmServoYChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexY);
m_ccpm->ccpmServoZChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexZ);
}
void ConfigccpmWidget::SetUIComponentVisibilities()
{
UpdateCCPMOptionsFromUI();
//set which sliders are user...
m_ccpm->ccpmRevoMixingBox->setVisible(0);
m_ccpm->ccpmPitchMixingBox->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState);
m_ccpm->ccpmCollectiveScalingBox->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
m_ccpm->ccpmLinkCyclic->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState);
m_ccpm->ccpmCyclicScalingBox->setVisible((GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState) && GUIConfigData.heli.ccpmLinkRollState);
if (!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState)
{
m_ccpm->ccpmPitchScalingBox->setVisible(0);
m_ccpm->ccpmRollScalingBox->setVisible(0);
m_ccpm->ccpmLinkRoll->setVisible(0);
}
else
{
m_ccpm->ccpmPitchScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState);
m_ccpm->ccpmRollScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState);
m_ccpm->ccpmLinkRoll->setVisible(1);
}
}
/**
Request the current value of the SystemSettings which holds the ccpm type
*/
void ConfigccpmWidget::requestccpmUpdate()
{
#define MaxAngleError 2
int MixerDataFromHeli[8][5];
quint8 MixerOutputType[8];
int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],ServoCurve2[4];
int NumServos=0;
if (SwashLvlConfigurationInProgress)return;
if (updatingToHardware)return;
updatingFromHardware=TRUE;
unsigned int i,j;
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
Q_ASSERT(systemSettings);
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM ==
(sizeof(GUIConfigData.UAVObject) / sizeof(GUIConfigData.UAVObject[0])));
for(i = 0; i < SystemSettings::GUICONFIGDATA_NUMELEM; i++)
GUIConfigData.UAVObject[i]=systemSettingsData.GUIConfigData[i];
UpdateCCPMUIFromOptions();
// Get existing mixer settings
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
//go through the user data and update the mixer matrix
for (j=0;j<5;j++)
{
MixerDataFromHeli[0][j] = mixerSettingsData.Mixer1Vector[j];
MixerDataFromHeli[1][j] = mixerSettingsData.Mixer2Vector[j];
MixerDataFromHeli[2][j] = mixerSettingsData.Mixer3Vector[j];
MixerDataFromHeli[3][j] = mixerSettingsData.Mixer4Vector[j];
MixerDataFromHeli[4][j] = mixerSettingsData.Mixer5Vector[j];
MixerDataFromHeli[5][j] = mixerSettingsData.Mixer6Vector[j];
MixerDataFromHeli[6][j] = mixerSettingsData.Mixer7Vector[j];
MixerDataFromHeli[7][j] = mixerSettingsData.Mixer8Vector[j];
}
MixerOutputType[0] = mixerSettingsData.Mixer1Type;
MixerOutputType[1] = mixerSettingsData.Mixer2Type;
MixerOutputType[2] = mixerSettingsData.Mixer3Type;
MixerOutputType[3] = mixerSettingsData.Mixer4Type;
MixerOutputType[4] = mixerSettingsData.Mixer5Type;
MixerOutputType[5] = mixerSettingsData.Mixer6Type;
MixerOutputType[6] = mixerSettingsData.Mixer7Type;
MixerOutputType[7] = mixerSettingsData.Mixer8Type;
EngineChannel =-1;
TailRotorChannel =-1;
for (j=0;j<5;j++)
{
ServoChannels[j]=8;
ServoCurve2[j]=0;
ServoAngles[j]=0;
SortAngles[j]=j;
}
NumServos=0;
//process the data from Heli and try to figure out the settings...
for (i=0;i<8;i++)
{
//check if this is the engine... Throttle only
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_MOTOR)&&
(MixerDataFromHeli[i][0]>0)&&//ThrottleCurve1
(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
(MixerDataFromHeli[i][2]==0)&&//Roll
(MixerDataFromHeli[i][3]==0)&&//Pitch
(MixerDataFromHeli[i][4]==0))//Yaw
{
EngineChannel = i;
m_ccpm->ccpmEngineChannel->setCurrentIndex(i);
}
//check if this is the tail rotor... REVO and YAW
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&&
//(MixerDataFromHeli[i][0]!=0)&&//ThrottleCurve1
(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
(MixerDataFromHeli[i][2]==0)&&//Roll
(MixerDataFromHeli[i][3]==0)&&//Pitch
(MixerDataFromHeli[i][4]!=0))//Yaw
{
TailRotorChannel = i;
m_ccpm->ccpmTailChannel->setCurrentIndex(i);
m_ccpm->ccpmRevoSlider->setValue((MixerDataFromHeli[i][0]*100)/127);
m_ccpm->ccpmREVOspinBox->setValue((MixerDataFromHeli[i][0]*100)/127);
}
//check if this is a swashplate servo... Throttle is zero
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&&
(MixerDataFromHeli[i][0]==0)&&//ThrottleCurve1
//(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
//(MixerDataFromHeli[i][2]==0)&&//Roll
//(MixerDataFromHeli[i][3]==0)&&//Pitch
(MixerDataFromHeli[i][4]==0))//Yaw
{
ServoChannels[NumServos] = i;//record the channel for this servo
ServoCurve2[NumServos]=MixerDataFromHeli[i][1];//record the ThrottleCurve2 contribution to this servo
ServoAngles[NumServos]=NumServos*45;//make this 0 for the final version
NumServos++;
}
}
//get the settings for the curve from the mixer settings
for (i=0;i<5;i++)
{
m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",
mixerSettingsData.ThrottleCurve1[i]));
m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",
mixerSettingsData.ThrottleCurve2[i]));
}
updatingFromHardware=FALSE;
UpdateCCPMUIFromOptions();
ccpmSwashplateUpdate();
}
/**
Sends the config to the board (ccpm type)
*/
void ConfigccpmWidget::sendccpmUpdate()
{
int i,j;
if (SwashLvlConfigurationInProgress)return;
updatingToHardware=TRUE;
//ShowDisclaimer(1);
UpdateCCPMOptionsFromUI();
// Store the data required to reconstruct
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
Q_ASSERT(systemSettings);
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
systemSettingsData.GUIConfigData[0] = GUIConfigData.UAVObject[0];
systemSettingsData.GUIConfigData[1] = GUIConfigData.UAVObject[1];
systemSettings->setData(systemSettingsData);
systemSettings->updated();
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
Q_ASSERT(mixerSettings);
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
UpdateMixer();
// Set up some helper pointers
qint8 * mixers[8] = {mixerSettingsData.Mixer1Vector,
mixerSettingsData.Mixer2Vector,
mixerSettingsData.Mixer3Vector,
mixerSettingsData.Mixer4Vector,
mixerSettingsData.Mixer5Vector,
mixerSettingsData.Mixer6Vector,
mixerSettingsData.Mixer7Vector,
mixerSettingsData.Mixer8Vector
};
quint8 * mixerTypes[8] = {
&mixerSettingsData.Mixer1Type,
&mixerSettingsData.Mixer2Type,
&mixerSettingsData.Mixer3Type,
&mixerSettingsData.Mixer4Type,
&mixerSettingsData.Mixer5Type,
&mixerSettingsData.Mixer6Type,
&mixerSettingsData.Mixer7Type,
&mixerSettingsData.Mixer8Type
};
//go through the user data and update the mixer matrix
for (i=0;i<6;i++)
{
if (MixerChannelData[i]<8)
{
//set the mixer type
*(mixerTypes[MixerChannelData[i]]) = i==0 ?
MixerSettings::MIXER1TYPE_MOTOR :
MixerSettings::MIXER1TYPE_SERVO;
//config the vector
for (j=0;j<5;j++)
mixers[MixerChannelData[i]][j] = m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt();
}
}
//get the user data for the curve into the mixer settings
for (i=0;i<5;i++)
mixerSettingsData.ThrottleCurve1[i] = m_ccpm->CurveSettings->item(i, 0)->text().toDouble();
for (i=0;i<5;i++)
mixerSettingsData.ThrottleCurve2[i] = m_ccpm->CurveSettings->item(i, 1)->text().toDouble();
//mapping of collective input to curve 2...
//MixerSettings.Curve2Source = Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5
//check if we are using throttle or directly from a channel...
if (GUIConfigData.heli.ccpmCollectivePassthroughState)
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_COLLECTIVE;
else
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_THROTTLE;
mixerSettings->setData(mixerSettingsData);
mixerSettings->updated();
updatingToHardware=FALSE;
}
/**
Send ccpm type to the board and request saving to SD card
*/
void ConfigccpmWidget::saveccpmUpdate()
{
if (SwashLvlConfigurationInProgress)return;
ShowDisclaimer(0);
// Send update so that the latest value is saved
sendccpmUpdate();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
saveObjectToSD(obj);
}
void ConfigccpmWidget::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
// Make the custom table columns autostretch:
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
for (int i=0;i<6;i++) {
m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()-
m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6);
}
ccpmSwashplateRedraw();
}
void ConfigccpmWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
for (int i=0;i<6;i++) {
m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()-
m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6);
}
ccpmSwashplateRedraw();
}
void ConfigccpmWidget::SwashLvlStartButtonPressed()
{
QMessageBox msgBox;
int i;
msgBox.setText("<h1>Swashplate Leveling Routine</h1>");
msgBox.setInformativeText("<b>You are about to start the Swashplate levelling routine.</b><p>This process will start by downloading the current configuration from the GCS to the OP hardware and will adjust your configuration at various stages.<p>The final state of your system should match the current configuration in the GCS config gadget.<p>Please ensure all ccpm settings in the GCS are correct before continuing.<p>If this process is interrupted, then the state of your OP board may not match the GCS configuration.<p><i>After completing this process, please check all settings before attempting to fly.</i><p><font color=red><b>Please disconnect your motor to ensure it will not spin up.</b></font><p><hr><i>Do you wish to proceed?</i>");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
msgBox.setIcon(QMessageBox::Information);
int ret = msgBox.exec();
UAVObjectField* MinField;
UAVObjectField* NeutralField;
UAVObjectField* MaxField;
UAVDataObject* obj;
ExtensionSystem::PluginManager *pm;
UAVObjectManager *objManager;
switch (ret) {
case QMessageBox::Yes:
// Yes was clicked
SwashLvlState=0;
//remove Flight control of ActuatorCommand
enableSwashplateLevellingControl(true);
m_ccpm->SwashLvlStartButton->setEnabled(false);
m_ccpm->SwashLvlNextButton->setEnabled(true);
m_ccpm->SwashLvlCancelButton->setEnabled(true);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
//clear status check boxes
m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Unchecked);
//download the current settings to the OP hw
sendccpmUpdate();
//change control mode to gcs control / disarmed
//set throttle to 0
//save off the old ActuatorSettings for the swashplate servos
pm = ExtensionSystem::PluginManager::instance();
objManager = pm->getObject<UAVObjectManager>();
// Get the channel assignements:
obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// obj->requestUpdate();
MinField = obj->getField(QString("ChannelMin"));
NeutralField = obj->getField(QString("ChannelNeutral"));
MaxField = obj->getField(QString("ChannelMax"));
//channel assignments
oldSwashLvlConfiguration.ServoChannels[0]=m_ccpm->ccpmServoWChannel->currentIndex();
oldSwashLvlConfiguration.ServoChannels[1]=m_ccpm->ccpmServoXChannel->currentIndex();
oldSwashLvlConfiguration.ServoChannels[2]=m_ccpm->ccpmServoYChannel->currentIndex();
oldSwashLvlConfiguration.ServoChannels[3]=m_ccpm->ccpmServoZChannel->currentIndex();
//if servos are used
oldSwashLvlConfiguration.Used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
oldSwashLvlConfiguration.Used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
oldSwashLvlConfiguration.Used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
oldSwashLvlConfiguration.Used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
//min,neutral,max values for the servos
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
oldSwashLvlConfiguration.Min[i]=MinField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt();
oldSwashLvlConfiguration.Neutral[i]=NeutralField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt();
oldSwashLvlConfiguration.Max[i]=MaxField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt();
}
//copy to new Actuator settings.
memcpy((void*)&newSwashLvlConfiguration,(void*)&oldSwashLvlConfiguration,sizeof(SwashplateServoSettingsStruct));
//goto the first step
SwashLvlNextButtonPressed();
break;
case QMessageBox::Cancel:
// Cancel was clicked
SwashLvlState=0;
//restore Flight control of ActuatorCommand
enableSwashplateLevellingControl(false);
m_ccpm->SwashLvlStartButton->setEnabled(true);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(false);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
break;
default:
// should never be reached
break;
}
}
void ConfigccpmWidget::SwashLvlNextButtonPressed()
{
//ShowDisclaimer(2);
SwashLvlState++;
int i;
switch (SwashLvlState)
{
case 0:
break;
case 1: //Neutral levelling
m_ccpm->SwashLvlStepList->setCurrentRow(0);
//set spin boxes and swashplate servos to Neutral values
setSwashplateLevel(50);
//disable position slider
m_ccpm->SwashLvlPositionSlider->setEnabled(false);
m_ccpm->SwashLvlPositionSpinBox->setEnabled(false);
//set position slider to 50%
m_ccpm->SwashLvlPositionSlider->setValue(50);
m_ccpm->SwashLvlPositionSpinBox->setValue(50);
//connect spinbox signals to slots and ebnable them
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
connect(SwashLvlSpinBoxes[i], SIGNAL(valueChanged(int)), this, SLOT(SwashLvlSpinBoxChanged(int)));
SwashLvlSpinBoxes[i]->setEnabled(true);
}
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setHtml("<h2>Neutral levelling</h2><p>Using adjustment of:<ul><li>servo horns<li>link lengths and<li>Neutral timing spinboxes to the right</ul><br>ensure that the swashplate is in the center of desired travel range and is level.");
break;
case 2: //Max levelling
//check Neutral status as complete
m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Checked);
m_ccpm->SwashLvlStepList->setCurrentRow(1);
//set spin boxes and swashplate servos to Max values
setSwashplateLevel(100);
//set position slider to 100%
m_ccpm->SwashLvlPositionSlider->setValue(100);
m_ccpm->SwashLvlPositionSpinBox->setValue(100);
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>Max levelling</h2><p>Using adjustment of:<ul><li>Max timing spinboxes to the right ONLY</ul><br>ensure that the swashplate is at the top of desired travel range and is level.");
break;
case 3: //Min levelling
//check Max status as complete
m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Checked);
m_ccpm->SwashLvlStepList->setCurrentRow(2);
//set spin boxes and swashplate servos to Min values
setSwashplateLevel(0);
//set position slider to 0%
m_ccpm->SwashLvlPositionSlider->setValue(0);
m_ccpm->SwashLvlPositionSpinBox->setValue(0);
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>Min levelling</h2><p>Using adjustment of:<ul><li>Min timing spinboxes to the right ONLY</ul><br>ensure that the swashplate is at the bottom of desired travel range and is level.");
break;
case 4: //levelling verification
//check Min status as complete
m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Checked);
m_ccpm->SwashLvlStepList->setCurrentRow(3);
//enable position slider
m_ccpm->SwashLvlPositionSlider->setEnabled(true);
m_ccpm->SwashLvlPositionSpinBox->setEnabled(true);
//make heli respond to slider movement
connect(m_ccpm->SwashLvlPositionSlider, SIGNAL(valueChanged(int)), this, SLOT(setSwashplateLevel(int)));
//disable spin boxes
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
SwashLvlSpinBoxes[i]->setEnabled(false);
}
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>levelling verification</h2><p>Adjust the slider to the right over it's full range and observe the swashplate motion. It should remain level over the entire range of travel.");
break;
case 5: //levelling complete
//check verify status as complete
m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Checked);
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>levelling complete</h2><p>Press the Finish button to save these settings to the SD card<p>Press the cancel button to return to the pre-levelling settings");
//disable position slider
m_ccpm->SwashLvlPositionSlider->setEnabled(false);
m_ccpm->SwashLvlPositionSpinBox->setEnabled(false);
//disconnect levelling slots from signals
disconnect(m_ccpm->SwashLvlPositionSlider, SIGNAL(valueChanged(int)), this, SLOT(setSwashplateLevel(int)));
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
disconnect(SwashLvlSpinBoxes[i], SIGNAL(valueChanged(int)), this, SLOT(SwashLvlSpinBoxChanged(int)));
}
m_ccpm->SwashLvlStartButton->setEnabled(false);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(true);
m_ccpm->SwashLvlFinishButton->setEnabled(true);
default:
//restore collective/cyclic setting
//restore pitch curve
//clear spin boxes
//change control mode to gcs control (OFF) / disarmed
//issue user confirmation
break;
}
}
void ConfigccpmWidget::SwashLvlCancelButtonPressed()
{
int i;
SwashLvlState=0;
UAVObjectField* MinField;
UAVObjectField* NeutralField;
UAVObjectField* MaxField;
m_ccpm->SwashLvlStartButton->setEnabled(true);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(false);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Unchecked);
//restore old Actuator Settings
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
//update settings to match our changes.
MinField = obj->getField(QString("ChannelMin"));
NeutralField = obj->getField(QString("ChannelNeutral"));
MaxField = obj->getField(QString("ChannelMax"));
//min,neutral,max values for the servos
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
MinField->setValue(oldSwashLvlConfiguration.Min[i],oldSwashLvlConfiguration.ServoChannels[i]);
NeutralField->setValue(oldSwashLvlConfiguration.Neutral[i],oldSwashLvlConfiguration.ServoChannels[i]);
MaxField->setValue(oldSwashLvlConfiguration.Max[i],oldSwashLvlConfiguration.ServoChannels[i]);
}
obj->updated();
//restore Flight control of ActuatorCommand
enableSwashplateLevellingControl(false);
m_ccpm->SwashLvlStepInstruction->setText("<h2>Levelling Cancelled</h2><p>Previous settings have been restored.");
}
void ConfigccpmWidget::SwashLvlFinishButtonPressed()
{
int i;
UAVObjectField* MinField;
UAVObjectField* NeutralField;
UAVObjectField* MaxField;
m_ccpm->SwashLvlStartButton->setEnabled(true);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(false);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
//save new Actuator Settings to memory and SD card
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
//update settings to match our changes.
MinField = obj->getField(QString("ChannelMin"));
NeutralField = obj->getField(QString("ChannelNeutral"));
MaxField = obj->getField(QString("ChannelMax"));
//min,neutral,max values for the servos
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
MinField->setValue(newSwashLvlConfiguration.Min[i],newSwashLvlConfiguration.ServoChannels[i]);
NeutralField->setValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]);
MaxField->setValue(newSwashLvlConfiguration.Max[i],newSwashLvlConfiguration.ServoChannels[i]);
}
obj->updated();
saveObjectToSD(obj);
//restore Flight control of ActuatorCommand
enableSwashplateLevellingControl(false);
m_ccpm->SwashLvlStepInstruction->setText("<h2>Levelling Completed</h2><p>New settings have been saved to the SD card");
ShowDisclaimer(0);
//ShowDisclaimer(2);
}
int ConfigccpmWidget::ShowDisclaimer(int messageID)
{
QMessageBox msgBox;
msgBox.setText("<font color=red><h1>Warning!!!</h2></font>");
int ret;
switch (messageID) {
case 0:
// Basic disclaimer
msgBox.setInformativeText("<h2>This code has many configurations.</h2><p>Please double check all settings before attempting flight!");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Information);
ret = msgBox.exec();
return 0;
break;
case 1:
// Not Tested disclaimer
msgBox.setInformativeText("<h2>The CCPM mixer code needs more testing!</h2><p><font color=red>Use it at your own risk!</font><p>Do you wish to continue?");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
msgBox.setIcon(QMessageBox::Warning);
ret = msgBox.exec();
switch (ret)
{
case QMessageBox::Cancel: return -1;
case QMessageBox::Yes: return 0;
}
break;
case 2:
// DO NOT use
msgBox.setInformativeText("<h2>The CCPM swashplate levelling code is NOT complete!</h2><p><font color=red>DO NOT use it for flight!</font>");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Critical);
ret = msgBox.exec();
return 0;
break;
default:
// should never be reached
break;
}
return -1;
}
/**
Toggles the channel testing mode by making the GCS take over
the ActuatorCommand objects
*/
void ConfigccpmWidget::enableSwashplateLevellingControl(bool state)
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorCommand")));
UAVObject::Metadata mdata = obj->getMetadata();
if (state)
{
SwashLvlaccInitialData = mdata;
mdata.flightAccess = UAVObject::ACCESS_READONLY;
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE;
mdata.gcsTelemetryAcked = false;
mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE;
mdata.gcsTelemetryUpdatePeriod = 100;
SwashLvlConfigurationInProgress=1;
m_ccpm->TabObject->setTabEnabled(0,0);
m_ccpm->TabObject->setTabEnabled(2,0);
m_ccpm->TabObject->setTabEnabled(3,0);
m_ccpm->ccpmType->setEnabled(0);
}
else
{
mdata = SwashLvlaccInitialData; // Restore metadata
SwashLvlConfigurationInProgress=0;
m_ccpm->TabObject->setTabEnabled(0,1);
m_ccpm->TabObject->setTabEnabled(2,1);
m_ccpm->TabObject->setTabEnabled(3,1);
m_ccpm->ccpmType->setEnabled(1);
}
obj->setMetadata(mdata);
}
/**
Sets the swashplate level to a given value based on current settings for Max, Neutral and Min values.
level ranges -1 to +1
*/
void ConfigccpmWidget::setSwashplateLevel(int percent)
{
if (percent<0)return;// -1;
if (percent>100)return;// -1;
if (SwashLvlConfigurationInProgress!=1)return;// -1;
int i;
double value;
double level = ((double)percent /50.00) - 1.00;
SwashLvlServoInterlock=1;
ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager());
ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData();
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++) {
if (level==0)
value = newSwashLvlConfiguration.Neutral[i];
else if (level > 0)
value = (newSwashLvlConfiguration.Max[i] - newSwashLvlConfiguration.Neutral[i])*level + newSwashLvlConfiguration.Neutral[i];
else if (level < 0)
value = (newSwashLvlConfiguration.Neutral[i] - newSwashLvlConfiguration.Min[i])*level + newSwashLvlConfiguration.Neutral[i];
actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value;
SwashLvlSpinBoxes[i]->setValue(value);
}
actuatorCommand->setData(actuatorCommandData);
actuatorCommand->updated();
SwashLvlServoInterlock=0;
return;
}
void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value)
{
Q_UNUSED(value);
int i;
if (SwashLvlServoInterlock==1)return;
ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager());
ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData();
for (i = 0; i < CCPM_MAX_SWASH_SERVOS; i++) {
value = SwashLvlSpinBoxes[i]->value();
switch (SwashLvlState)
{
case 1: //Neutral levelling
newSwashLvlConfiguration.Neutral[i]=value;
break;
case 2: //Max levelling
newSwashLvlConfiguration.Max[i] = value;
break;
case 3: //Min levelling
newSwashLvlConfiguration.Min[i]= value;
break;
case 4: //levelling verification
break;
case 5: //levelling complete
break;
default:
break;
}
actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value;
}
actuatorCommand->setData(actuatorCommandData);
actuatorCommand->updated();
return;
}