/** ****************************************************************************** * * @file configccpmwidget.cpp * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup ConfigPlugin Config Plugin * @{ * @brief ccpm configuration panel *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "configccpmwidget.h" #include "mixersettings.h" #include #include #include #include #include #include #include #include #include #define Pi 3.14159265358979323846 ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) { int i; m_ccpm = new Ui_ccpmWidget(); m_ccpm->setupUi(this); SwashLvlConfigurationInProgress=0; SwashLvlState=0; SwashLvlServoInterlock=0; updatingFromHardware=FALSE; updatingToHardware=FALSE; // Now connect the widget to the ManualControlCommand / Channel UAVObject //ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); //UAVObjectManager *objManager = pm->getObject(); // Initialization of the swashplaye widget m_ccpm->SwashplateImage->setScene(new QGraphicsScene(this)); m_ccpm->SwashLvlSwashplateImage->setScene(m_ccpm->SwashplateImage->scene()); m_ccpm->SwashLvlSwashplateImage->setSceneRect(-50,-50,500,500); //m_ccpm->SwashLvlSwashplateImage->scale(.85,.85); //m_ccpm->SwashplateImage->setSceneRect(SwashplateImg->boundingRect()); m_ccpm->SwashplateImage->setSceneRect(-50,-30,500,500); //m_ccpm->SwashplateImage->scale(.85,.85); QSvgRenderer *renderer = new QSvgRenderer(); renderer->load(QString(":/configgadget/images/ccpm_setup.svg")); SwashplateImg = new QGraphicsSvgItem(); SwashplateImg->setSharedRenderer(renderer); SwashplateImg->setElementId("Swashplate"); SwashplateImg->setObjectName("Swashplate"); //SwashplateImg->setScale(0.75); m_ccpm->SwashplateImage->scene()->addItem(SwashplateImg); QFont serifFont("Times", 24, QFont::Bold); QPen pen; // creates a default pen pen.setStyle(Qt::DotLine); pen.setWidth(2); pen.setBrush(Qt::gray); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); QBrush brush(Qt::darkBlue); QPen pen2; // creates a default pen //pen2.setStyle(Qt::DotLine); pen2.setWidth(1); pen2.setBrush(Qt::blue); //pen2.setCapStyle(Qt::RoundCap); //pen2.setJoinStyle(Qt::RoundJoin); //brush.setStyle(Qt::RadialGradientPattern); QList ServoNames; ServoNames << "ServoW" << "ServoX" << "ServoY" << "ServoZ" ; for (i=0;iSwashLvlSwashplateImage->scene()->addLine(0,0,100*i,i*i*100,pen); Servos[i] = new QGraphicsSvgItem(); Servos[i]->setSharedRenderer(renderer); Servos[i]->setElementId(ServoNames.at(i)); m_ccpm->SwashplateImage->scene()->addItem(Servos[i]); ServosText[i] = new QGraphicsTextItem(); ServosText[i]->setDefaultTextColor(Qt::yellow); ServosText[i]->setPlainText(QString("-")); ServosText[i]->setFont(serifFont); ServosTextCircles[i] = new QGraphicsEllipseItem(1,1,30,30); ServosTextCircles[i]->setBrush(brush); ServosTextCircles[i]->setPen(pen2); m_ccpm->SwashplateImage->scene()->addItem(ServosTextCircles[i]); m_ccpm->SwashplateImage->scene()->addItem(ServosText[i]); SwashLvlSpinBoxes[i] = new QSpinBox(m_ccpm->SwashLvlSwashplateImage); // use QGraphicsView m_ccpm->SwashLvlSwashplateImage->scene()->addWidget(SwashLvlSpinBoxes[i]); //SwashLvlSpinBoxes[i]->move(i*50+50,20); //SwashLvlSpinBoxes[i]->resize(40,20); //SwashLvlSpinBoxes[i]->heightForWidth() SwashLvlSpinBoxes[i]->setFixedSize(50,20); SwashLvlSpinBoxes[i]->setMaximum(10000); SwashLvlSpinBoxes[i]->setMinimum(0); SwashLvlSpinBoxes[i]->setValue(0); } /* Servos[0] = new QGraphicsSvgItem(); Servos[0]->setSharedRenderer(renderer); Servos[0]->setElementId("ServoW"); m_ccpm->SwashplateImage->scene()->addItem(Servos[0]); Servos[1] = new QGraphicsSvgItem(); Servos[1]->setSharedRenderer(renderer); Servos[1]->setElementId("ServoX"); m_ccpm->SwashplateImage->scene()->addItem(Servos[1]); Servos[2] = new QGraphicsSvgItem(); Servos[2]->setSharedRenderer(renderer); Servos[2]->setElementId("ServoY"); m_ccpm->SwashplateImage->scene()->addItem(Servos[2]); Servos[3] = new QGraphicsSvgItem(); Servos[3]->setSharedRenderer(renderer); Servos[3]->setElementId("ServoZ"); m_ccpm->SwashplateImage->scene()->addItem(Servos[3]); ServosText[0] = new QGraphicsTextItem(); ServosText[0]->setDefaultTextColor(Qt::red); ServosText[0]->setPlainText(QString("-")); ServosText[0]->setFont(serifFont); m_ccpm->SwashplateImage->scene()->addItem(ServosText[0]); ServosText[1] = new QGraphicsTextItem(); ServosText[1]->setDefaultTextColor(Qt::red); ServosText[1]->setPlainText(QString("-")); ServosText[1]->setFont(serifFont); m_ccpm->SwashplateImage->scene()->addItem(ServosText[1]); ServosText[2] = new QGraphicsTextItem(); ServosText[2]->setDefaultTextColor(Qt::red); ServosText[2]->setPlainText(QString("-")); ServosText[2]->setFont(serifFont); m_ccpm->SwashplateImage->scene()->addItem(ServosText[2]); ServosText[3] = new QGraphicsTextItem(); ServosText[3]->setDefaultTextColor(Qt::red); ServosText[3]->setPlainText(QString("-")); ServosText[3]->setFont(serifFont); m_ccpm->SwashplateImage->scene()->addItem(ServosText[3]); */ m_ccpm->PitchCurve->setMin(-1); resetMixer(m_ccpm->PitchCurve, 5); resetMixer(m_ccpm->ThrottleCurve, 5); QStringList channels; channels << "Channel1" << "Channel2" << "Channel3" << "Channel4" << "Channel5" << "Channel6" << "Channel7" << "Channel8" ; m_ccpm->ccpmCollectiveChannel->addItems(channels); m_ccpm->ccpmCollectiveChannel->setCurrentIndex(8); channels << "None" ; m_ccpm->ccpmEngineChannel->addItems(channels); m_ccpm->ccpmEngineChannel->setCurrentIndex(8); m_ccpm->ccpmTailChannel->addItems(channels); m_ccpm->ccpmTailChannel->setCurrentIndex(8); m_ccpm->ccpmServoWChannel->addItems(channels); m_ccpm->ccpmServoWChannel->setCurrentIndex(8); m_ccpm->ccpmServoXChannel->addItems(channels); m_ccpm->ccpmServoXChannel->setCurrentIndex(8); m_ccpm->ccpmServoYChannel->addItems(channels); m_ccpm->ccpmServoYChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->addItems(channels); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); QStringList Types; Types << "CCPM 2 Servo 90º" << "CCPM 3 Servo 90º" << "CCPM 4 Servo 90º" << "CCPM 3 Servo 120º" << "CCPM 3 Servo 140º" << "FP 2 Servo 90º" << "Custom - User Angles" << "Custom - Advanced Settings" ; m_ccpm->ccpmType->addItems(Types); m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1); requestccpmUpdate(); UpdateCurveSettings(); //disable changing number of points in curves until UAVObjects have more than 5 m_ccpm->NumCurvePoints->setEnabled(0); UpdateType(); //connect(m_ccpm->saveccpmToSD, SIGNAL(clicked()), this, SLOT(saveccpmUpdate())); //connect(m_ccpm->saveccpmToRAM, SIGNAL(clicked()), this, SLOT(sendccpmUpdate())); //connect(m_ccpm->getccpmCurrent, SIGNAL(clicked()), this, SLOT(requestccpmUpdate())); connect(m_ccpm->ccpmGenerateCurve, SIGNAL(clicked()), this, SLOT(GenerateCurve())); connect(m_ccpm->NumCurvePoints, SIGNAL(valueChanged(int)), this, SLOT(UpdateCurveSettings())); connect(m_ccpm->CurveToGenerate, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings())); connect(m_ccpm->CurveType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings())); connect(m_ccpm->ccpmAngleW, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmAngleX, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmAngleY, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmAngleZ, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmCorrectionAngle, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmServoWChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmServoXChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmServoYChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmServoZChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate())); connect(m_ccpm->ccpmEngineChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer())); connect(m_ccpm->ccpmTailChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer())); connect(m_ccpm->ccpmRevoSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); connect(m_ccpm->ccpmREVOspinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); connect(m_ccpm->ccpmCollectiveSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); connect(m_ccpm->ccpmCollectivespinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer())); connect(m_ccpm->ccpmType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType())); connect(m_ccpm->ccpmSingleServo, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType())); connect(m_ccpm->CurveSettings, SIGNAL(cellChanged (int, int)), this, SLOT(UpdateCurveWidgets())); connect(m_ccpm->TabObject, SIGNAL(currentChanged ( QWidget * )), this, SLOT(UpdateType())); // connect(m_ccpm->SwashLvlSwashplateImage, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateRedraw())); connect(m_ccpm->PitchCurve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updatePitchCurveValue(QList,double))); connect(m_ccpm->ThrottleCurve, SIGNAL(curveUpdated(QList,double)), this, SLOT(updateThrottleCurveValue(QList,double))); connect(m_ccpm->SwashLvlStartButton, SIGNAL(clicked()), this, SLOT(SwashLvlStartButtonPressed())); connect(m_ccpm->SwashLvlNextButton, SIGNAL(clicked()), this, SLOT(SwashLvlNextButtonPressed())); connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed())); connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed())); connect(m_ccpm->ccpmCollectivePassthrough, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); ccpmSwashplateRedraw(); // connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestccpmUpdate())); } ConfigccpmWidget::~ConfigccpmWidget() { // Do nothing } void ConfigccpmWidget::UpdateType() { int TypeInt,SingleServoIndex,NumServosDefined; QString TypeText; double AdjustmentAngle=0; UpdatCCPMOptionsFromUI(); SetUIComponentVisibilities(); TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; TypeText = m_ccpm->ccpmType->currentText(); SingleServoIndex = m_ccpm->ccpmSingleServo->currentIndex(); //set visibility of user settings m_ccpm->ccpmAdvancedSettingsTable->setEnabled(TypeInt==0); m_ccpm->ccpmAdvancedSettingsTable->clearFocus();; m_ccpm->ccpmAngleW->setEnabled(TypeInt==1); m_ccpm->ccpmAngleX->setEnabled(TypeInt==1); m_ccpm->ccpmAngleY->setEnabled(TypeInt==1); m_ccpm->ccpmAngleZ->setEnabled(TypeInt==1); m_ccpm->ccpmCorrectionAngle->setEnabled(TypeInt!=0); m_ccpm->ccpmServoWChannel->setEnabled(TypeInt>0); m_ccpm->ccpmServoXChannel->setEnabled(TypeInt>0); m_ccpm->ccpmServoYChannel->setEnabled(TypeInt>0); m_ccpm->ccpmServoZChannel->setEnabled(TypeInt>0); m_ccpm->ccpmSingleServo->setEnabled(TypeInt>1); m_ccpm->ccpmEngineChannel->setEnabled(TypeInt>0); m_ccpm->ccpmTailChannel->setEnabled(TypeInt>0); m_ccpm->ccpmCollectiveSlider->setEnabled(TypeInt>0); m_ccpm->ccpmCollectivespinBox->setEnabled(TypeInt>0); m_ccpm->ccpmRevoSlider->setEnabled(TypeInt>0); m_ccpm->ccpmREVOspinBox->setEnabled(TypeInt>0); AdjustmentAngle=SingleServoIndex*90; m_ccpm->CurveToGenerate->setEnabled(1); m_ccpm->CurveSettings->setColumnHidden(1,0); m_ccpm->PitchCurve->setVisible(1); //m_ccpm->customThrottleCurve2Value->setVisible(1); //m_ccpm->label_41->setVisible(1); NumServosDefined=4; //set values for pre defined heli types if (TypeText.compare(QString("CCPM 2 Servo 90º"), Qt::CaseInsensitive)==0) { m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); m_ccpm->ccpmAngleY->setValue(0); m_ccpm->ccpmAngleZ->setValue(0); m_ccpm->ccpmAngleY->setEnabled(0); m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoYChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoYChannel->setEnabled(0); m_ccpm->ccpmServoZChannel->setEnabled(0); //m_ccpm->ccpmCorrectionAngle->setValue(0); NumServosDefined=2; } if (TypeText.compare(QString("CCPM 3 Servo 90º"), Qt::CaseInsensitive)==0) { m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360)); m_ccpm->ccpmAngleZ->setValue(0); m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setEnabled(0); //m_ccpm->ccpmCorrectionAngle->setValue(0); NumServosDefined=3; } if (TypeText.compare(QString("CCPM 4 Servo 90º"), Qt::CaseInsensitive)==0) { m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360)); m_ccpm->ccpmAngleZ->setValue(fmod(AdjustmentAngle + 270,360)); //m_ccpm->ccpmCorrectionAngle->setValue(0); m_ccpm->ccpmSingleServo->setEnabled(0); m_ccpm->ccpmSingleServo->setCurrentIndex(0); NumServosDefined=4; } if (TypeText.compare(QString("CCPM 3 Servo 120º"), Qt::CaseInsensitive)==0) { m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 120,360)); m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 240,360)); m_ccpm->ccpmAngleZ->setValue(0); m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setEnabled(0); //m_ccpm->ccpmCorrectionAngle->setValue(0); NumServosDefined=3; } if (TypeText.compare(QString("CCPM 3 Servo 140º"), Qt::CaseInsensitive)==0) { m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 140,360)); m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 220,360)); m_ccpm->ccpmAngleZ->setValue(0); m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setEnabled(0); //m_ccpm->ccpmCorrectionAngle->setValue(0); NumServosDefined=3; } if (TypeText.compare(QString("FP 2 Servo 90º"), Qt::CaseInsensitive)==0) { m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); m_ccpm->ccpmAngleY->setValue(0); m_ccpm->ccpmAngleZ->setValue(0); m_ccpm->ccpmAngleY->setEnabled(0); m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoYChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoYChannel->setEnabled(0); m_ccpm->ccpmServoZChannel->setEnabled(0); //m_ccpm->ccpmCorrectionAngle->setValue(0); m_ccpm->ccpmCollectivespinBox->setEnabled(0); m_ccpm->ccpmCollectiveSlider->setEnabled(0); m_ccpm->ccpmCollectivespinBox->setValue(0); m_ccpm->ccpmCollectiveSlider->setValue(0); m_ccpm->CurveToGenerate->setCurrentIndex(0); m_ccpm->CurveToGenerate->setEnabled(0); m_ccpm->CurveSettings->setColumnHidden(1,1); m_ccpm->PitchCurve->setVisible(0); //m_ccpm->customThrottleCurve2Value->setVisible(0); //m_ccpm->label_41->setVisible(0); NumServosDefined=2; } //set the visibility of the swashplate servo selection boxes m_ccpm->ccpmServoWLabel->setVisible(NumServosDefined>=1); m_ccpm->ccpmServoXLabel->setVisible(NumServosDefined>=2); m_ccpm->ccpmServoYLabel->setVisible(NumServosDefined>=3); m_ccpm->ccpmServoZLabel->setVisible(NumServosDefined>=4); m_ccpm->ccpmServoWChannel->setVisible(NumServosDefined>=1); m_ccpm->ccpmServoXChannel->setVisible(NumServosDefined>=2); m_ccpm->ccpmServoYChannel->setVisible(NumServosDefined>=3); m_ccpm->ccpmServoZChannel->setVisible(NumServosDefined>=4); //set the visibility of the swashplate angle selection boxes m_ccpm->ccpmServoWLabel_2->setVisible(NumServosDefined>=1); m_ccpm->ccpmServoXLabel_2->setVisible(NumServosDefined>=2); m_ccpm->ccpmServoYLabel_2->setVisible(NumServosDefined>=3); m_ccpm->ccpmServoZLabel_2->setVisible(NumServosDefined>=4); m_ccpm->ccpmAngleW->setVisible(NumServosDefined>=1); m_ccpm->ccpmAngleX->setVisible(NumServosDefined>=2); m_ccpm->ccpmAngleY->setVisible(NumServosDefined>=3); m_ccpm->ccpmAngleZ->setVisible(NumServosDefined>=4); m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); for (int i=0;i<6;i++) { m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); } //update UI ccpmSwashplateUpdate(); } /** Resets a mixer curve */ void ConfigccpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements) { mixer->initLinearCurve(numElements,(double)1); } void ConfigccpmWidget::UpdateCurveWidgets() { int NumCurvePoints,i,Changed; QList curveValues; QList OldCurveValues; double ThisValue; //get the user settings NumCurvePoints=m_ccpm->NumCurvePoints->value(); curveValues.clear(); Changed=0; OldCurveValues=m_ccpm->ThrottleCurve->getCurve(); for (i=0; iCurveSettings->item(i, 0 )->text().toDouble(); curveValues.append(ThisValue); if (ThisValue!=OldCurveValues.at(i))Changed=1; } // Setup all Throttle1 curves for all types of airframes if (Changed==1)m_ccpm->ThrottleCurve->setCurve(curveValues); curveValues.clear(); Changed=0; OldCurveValues=m_ccpm->PitchCurve->getCurve(); for (i=0; iCurveSettings->item(i, 1 )->text().toDouble(); curveValues.append(ThisValue); if (ThisValue!=OldCurveValues.at(i))Changed=1; } // Setup all Throttle1 curves for all types of airframes if (Changed==1)m_ccpm->PitchCurve->setCurve(curveValues); } void ConfigccpmWidget::updatePitchCurveValue(QList curveValues0,double Value0) { int NumCurvePoints,i; double CurrentValue; QList internalCurveValues; //get the user settings NumCurvePoints=m_ccpm->NumCurvePoints->value(); internalCurveValues=m_ccpm->PitchCurve->getCurve(); for (i=0; iCurveSettings->item(i, 1 )->text().toDouble(); if (CurrentValue!=internalCurveValues[i]) { m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",internalCurveValues.at(i))); } } } void ConfigccpmWidget::updateThrottleCurveValue(QList curveValues0,double Value0) { int NumCurvePoints,i; double CurrentValue; QList internalCurveValues; //get the user settings NumCurvePoints=m_ccpm->NumCurvePoints->value(); internalCurveValues=m_ccpm->ThrottleCurve->getCurve(); for (i=0; iCurveSettings->item(i, 1 )->text().toDouble(); if (CurrentValue!=internalCurveValues[i]) { m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",internalCurveValues.at(i))); } } } void ConfigccpmWidget::UpdateCurveSettings() { int NumCurvePoints,i; double scale; QString CurveType; QStringList vertHeaders; //get the user settings NumCurvePoints=m_ccpm->NumCurvePoints->value(); CurveType=m_ccpm->CurveType->currentText(); vertHeaders << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" ; for (i=0;iCurveSettings->setVerticalHeaderLabels( vertHeaders ); if (m_ccpm->CurveToGenerate->currentIndex()==0) { m_ccpm->CurveValue1->setMinimum(0.0); m_ccpm->CurveValue2->setMinimum(0.0); m_ccpm->CurveValue3->setMinimum(0.0); } else { m_ccpm->CurveValue1->setMinimum(-1.0); m_ccpm->CurveValue2->setMinimum(-1.0); m_ccpm->CurveValue3->setMinimum(0.0); } m_ccpm->CurveValue1->setMaximum(1.0); m_ccpm->CurveValue2->setMaximum(1.0); m_ccpm->CurveValue3->setMaximum(100.0); m_ccpm->CurveValue1->setSingleStep(0.1); m_ccpm->CurveValue2->setSingleStep(0.1); m_ccpm->CurveValue3->setSingleStep(1.0); m_ccpm->CurveValue1->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);; m_ccpm->CurveValue2->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue); m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue); if ( CurveType.compare("Flat")==0) { m_ccpm->CurveLabel1->setText("Value"); m_ccpm->CurveLabel1->setVisible(true); m_ccpm->CurveValue1->setVisible(true); m_ccpm->CurveLabel2->setVisible(false); m_ccpm->CurveValue2->setVisible(false); m_ccpm->CurveLabel3->setVisible(false); m_ccpm->CurveValue3->setVisible(false); m_ccpm->ccpmGenerateCurve->setVisible(true); m_ccpm->CurveToGenerate->setVisible(true); } if ( CurveType.compare("Linear")==0) { m_ccpm->CurveLabel1->setText("Min"); m_ccpm->CurveLabel1->setVisible(true); m_ccpm->CurveValue1->setVisible(true); m_ccpm->CurveLabel2->setText("Max"); m_ccpm->CurveLabel2->setVisible(true); m_ccpm->CurveValue2->setVisible(true); m_ccpm->CurveLabel3->setVisible(false); m_ccpm->CurveValue3->setVisible(false); m_ccpm->ccpmGenerateCurve->setVisible(true); m_ccpm->CurveToGenerate->setVisible(true); } if ( CurveType.compare("Step")==0) { m_ccpm->CurveLabel1->setText("Min"); m_ccpm->CurveLabel1->setVisible(true); m_ccpm->CurveValue1->setVisible(true); m_ccpm->CurveLabel2->setText("Max"); m_ccpm->CurveLabel2->setVisible(true); m_ccpm->CurveValue2->setVisible(true); m_ccpm->CurveLabel3->setText("Step at"); m_ccpm->CurveLabel3->setVisible(true); m_ccpm->CurveValue3->setVisible(true); m_ccpm->ccpmGenerateCurve->setVisible(true); m_ccpm->CurveToGenerate->setVisible(true); } if ( CurveType.compare("Exp")==0) { m_ccpm->CurveLabel1->setText("Min"); m_ccpm->CurveLabel1->setVisible(true); m_ccpm->CurveValue1->setVisible(true); m_ccpm->CurveLabel2->setText("Max"); m_ccpm->CurveLabel2->setVisible(true); m_ccpm->CurveValue2->setVisible(true); m_ccpm->CurveLabel3->setText("Strength"); m_ccpm->CurveLabel3->setVisible(true); m_ccpm->CurveValue3->setVisible(true); m_ccpm->CurveValue3->setMinimum(1.0); m_ccpm->CurveValue3->setMaximum(100.0); m_ccpm->CurveValue3->setSingleStep(1.0); m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);; m_ccpm->ccpmGenerateCurve->setVisible(true); m_ccpm->CurveToGenerate->setVisible(true); } if ( CurveType.compare("Log")==0) { m_ccpm->CurveLabel1->setText("Min"); m_ccpm->CurveLabel1->setVisible(true); m_ccpm->CurveValue1->setVisible(true); m_ccpm->CurveLabel2->setText("Max"); m_ccpm->CurveLabel2->setVisible(true); m_ccpm->CurveValue2->setVisible(true); m_ccpm->CurveLabel3->setText("Strength"); m_ccpm->CurveLabel3->setVisible(true); m_ccpm->CurveValue3->setVisible(true); m_ccpm->CurveValue3->setMinimum(1.0); m_ccpm->CurveValue3->setMaximum(100.0); m_ccpm->CurveValue3->setSingleStep(1.0); m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);; m_ccpm->ccpmGenerateCurve->setVisible(true); m_ccpm->CurveToGenerate->setVisible(true); } if ( CurveType.compare("Custom")==0) { m_ccpm->CurveLabel1->setVisible(false); m_ccpm->CurveValue1->setVisible(false); m_ccpm->CurveLabel2->setVisible(false); m_ccpm->CurveValue2->setVisible(false); m_ccpm->CurveLabel3->setVisible(false); m_ccpm->CurveValue3->setVisible(false); m_ccpm->ccpmGenerateCurve->setVisible(false); m_ccpm->CurveToGenerate->setVisible(false); } UpdateCurveWidgets(); } void ConfigccpmWidget::GenerateCurve() { int NumCurvePoints,CurveToGenerate,i; double value1, value2, value3, scale; QString CurveType; QTableWidgetItem *item; double newValue; //get the user settings NumCurvePoints=m_ccpm->NumCurvePoints->value(); value1=m_ccpm->CurveValue1->value(); value2=m_ccpm->CurveValue2->value(); value3=m_ccpm->CurveValue3->value(); CurveToGenerate=m_ccpm->CurveToGenerate->currentIndex(); CurveType=m_ccpm->CurveType->currentText(); for (i=0;iCurveSettings->item(i, CurveToGenerate ); if ( CurveType.compare("Flat")==0) { //item->setText( tr( "%1" ).arg( value1 ) ); item->setText(QString().sprintf("%.3f",value1)); } if ( CurveType.compare("Linear")==0) { newValue =value1 +(scale*(value2-value1)); //item->setText( tr( "%1" ).arg(value1 +(scale*(value2-value1))) ); item->setText(QString().sprintf("%.3f",newValue)); } if ( CurveType.compare("Step")==0) { if (scale*100setText( tr( "%1" ).arg(value1) ); item->setText(QString().sprintf("%.3f",value1)); } else { //item->setText( tr( "%1" ).arg(value2) ); item->setText(QString().sprintf("%.3f",value2)); } } if ( CurveType.compare("Exp")==0) { newValue =value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1)); //item->setText( tr( "%1" ).arg(value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1))) ); item->setText(QString().sprintf("%.3f",newValue)); } if ( CurveType.compare("Log")==0) { newValue = value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1)); //item->setText( tr( "%1" ).arg(value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1))) ); item->setText(QString().sprintf("%.3f",newValue)); } } for (i=NumCurvePoints;i<10;i++) { item =m_ccpm->CurveSettings->item(i, CurveToGenerate ); item->setText( tr( "" ) ); } UpdateCurveWidgets(); } void ConfigccpmWidget::ccpmSwashplateRedraw() { double angle[CCPM_MAX_SWASH_SERVOS],CorrectionAngle,x,y,w,h,radius,CenterX,CenterY; int used[CCPM_MAX_SWASH_SERVOS],defined[CCPM_MAX_SWASH_SERVOS],i; QRectF bounds; QRect size; double scale,xscale,yscale; size = m_ccpm->SwashplateImage->rect(); xscale=size.width(); yscale=size.height(); scale=xscale; if (yscaleSwashplateImage->resetTransform (); m_ccpm->SwashplateImage->scale(scale,scale); size = m_ccpm->SwashLvlSwashplateImage->rect(); xscale=size.width(); yscale=size.height(); scale=xscale; if (yscaleSwashLvlSwashplateImage->resetTransform (); m_ccpm->SwashLvlSwashplateImage->scale(scale,scale); CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value(); CenterX=200; CenterY=200; bounds=SwashplateImg->boundingRect(); SwashplateImg->setPos(CenterX-bounds.width()/2,CenterY-bounds.height()/2); defined[0]=(m_ccpm->ccpmServoWChannel->isEnabled()); defined[1]=(m_ccpm->ccpmServoXChannel->isEnabled()); defined[2]=(m_ccpm->ccpmServoYChannel->isEnabled()); defined[3]=(m_ccpm->ccpmServoZChannel->isEnabled()); used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled())); used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled())); used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled())); used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled())); angle[0]=(CorrectionAngle+180+m_ccpm->ccpmAngleW->value())*Pi/180.00; angle[1]=(CorrectionAngle+180+m_ccpm->ccpmAngleX->value())*Pi/180.00; angle[2]=(CorrectionAngle+180+m_ccpm->ccpmAngleY->value())*Pi/180.00; angle[3]=(CorrectionAngle+180+m_ccpm->ccpmAngleZ->value())*Pi/180.00; for (i=0;isetPos(x, y); Servos[i]->setVisible(used[i]!=0); radius=150; bounds=ServosText[i]->boundingRect(); x=CenterX-(radius*sin(angle[i]))-bounds.width()/2; y=CenterY+(radius*cos(angle[i]))-bounds.height()/2; ServosText[i]->setPos(x, y); ServosText[i]->setVisible(used[i]!=0); if (bounds.width()>bounds.height()) { bounds.setHeight(bounds.width()); } else { bounds.setWidth(bounds.height()); } x=CenterX-(radius*sin(angle[i]))-bounds.width()/2; y=CenterY+(radius*cos(angle[i]))-bounds.height()/2; ServosTextCircles[i]->setRect(bounds); ServosTextCircles[i]->setPos(x, y); ServosTextCircles[i]->setVisible(used[i]!=0); w=SwashLvlSpinBoxes[i]->width()/2; h=SwashLvlSpinBoxes[i]->height()/2; radius = (215.00+w+h); x=CenterX-(radius*sin(angle[i]))-w; y=CenterY+(radius*cos(angle[i]))-h; SwashLvlSpinBoxes[i]->move(m_ccpm->SwashLvlSwashplateImage->mapFromScene (x, y)); SwashLvlSpinBoxes[i]->setVisible(used[i]!=0); radius=220; x=CenterX-(radius*sin(angle[i])); y=CenterY+(radius*cos(angle[i])); ServoLines[i]->setLine(CenterX,CenterY,x,y); ServoLines[i]->setVisible(defined[i]!=0); } //m_ccpm->SwashplateImage->centerOn (CenterX, CenterY); //m_ccpm->SwashplateImage->fitInView(SwashplateImg, Qt::KeepAspectRatio); } void ConfigccpmWidget::ccpmSwashplateUpdate() { ccpmSwashplateRedraw(); SetUIComponentVisibilities(); UpdateMixer(); } void ConfigccpmWidget::ccpmChannelCheck() { if((m_ccpm->ccpmServoWChannel->currentIndex()==8)&&(m_ccpm->ccpmServoWChannel->isEnabled())) { m_ccpm->ccpmServoWLabel->setText("Servo W"); } else { m_ccpm->ccpmServoWLabel->setText("Servo W"); } if((m_ccpm->ccpmServoXChannel->currentIndex()==8)&&(m_ccpm->ccpmServoXChannel->isEnabled())) { m_ccpm->ccpmServoXLabel->setText("Servo X"); } else { m_ccpm->ccpmServoXLabel->setText("Servo X"); } if((m_ccpm->ccpmServoYChannel->currentIndex()==8)&&(m_ccpm->ccpmServoYChannel->isEnabled())) { m_ccpm->ccpmServoYLabel->setText("Servo Y"); } else { m_ccpm->ccpmServoYLabel->setText("Servo Y"); } if((m_ccpm->ccpmServoZChannel->currentIndex()==8)&&(m_ccpm->ccpmServoZChannel->isEnabled())) { m_ccpm->ccpmServoZLabel->setText("Servo Z"); } else { m_ccpm->ccpmServoZLabel->setText("Servo Z"); } if((m_ccpm->ccpmEngineChannel->currentIndex()==8)&&(m_ccpm->ccpmEngineChannel->isEnabled())) { m_ccpm->ccpmEngineLabel->setText("Engine"); } else { m_ccpm->ccpmEngineLabel->setText("Engine"); } if((m_ccpm->ccpmTailChannel->currentIndex()==8)&&(m_ccpm->ccpmTailChannel->isEnabled())) { m_ccpm->ccpmTailLabel->setText("Tail Rotor"); } else { m_ccpm->ccpmTailLabel->setText("Tail Rotor"); } } void ConfigccpmWidget::UpdateMixer() { bool useCCPM; bool useCyclic; int i,j,ThisEnable[6]; float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6]; //QTableWidgetItem *newItem;// = new QTableWidgetItem(); QString Channel; ccpmChannelCheck(); //Type = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; //CollectiveConstant=m_ccpm->ccpmCollectiveSlider->value()/100.0; //CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value(); UpdatCCPMOptionsFromUI(); 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++) { /* data.Mixer0Type = 0;//Disabled,Motor,Servo data.Mixer0Vector[0] = 0;//ThrottleCurve1 data.Mixer0Vector[1] = 0;//ThrottleCurve2 data.Mixer0Vector[2] = 0;//Roll data.Mixer0Vector[3] = 0;//Pitch data.Mixer0Vector[4] = 0;//Yaw */ 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::UpdatCCPMOptionsFromUI() { 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(); //CollectiveChannel GUIConfigData.heli.CollectiveChannel = m_ccpm->ccpmCollectiveChannel->currentIndex(); //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(); //GUIConfigData.heli.RevoSlider = m_ccpm->ccpmREVOScale->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::UpdatCCPMUIFromOptions() { //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); //CollectiveChannel m_ccpm->ccpmCollectiveChannel->setCurrentIndex(GUIConfigData.heli.CollectiveChannel); //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); //m_ccpm->ccpmREVOScale->setValue(GUIConfigData.heli.RevoSlider); //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() { UpdatCCPMOptionsFromUI(); //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->ccpmCollectiveChLabel->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState); m_ccpm->ccpmCollectiveChannel->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState); 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]; QString MixerOutputType[8]; int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],CalcAngles[4],ServoCurve2[4]; int NumServos=0; double Collective=0.0; double a1,a2; int HeadRotation,temp; int isCCPM=0; if (SwashLvlConfigurationInProgress)return; if (updatingToHardware)return; updatingFromHardware=TRUE; ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); int i,j; UAVObjectField *field; UAVDataObject* obj; obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); field = obj->getField(QString("GUIConfigData")); GUIConfigData.UAVObject[0]=field->getValue(0).toUInt(); GUIConfigData.UAVObject[1]=field->getValue(1).toUInt(); UpdatCCPMUIFromOptions(); obj = dynamic_cast(objManager->getObject(QString("MixerSettings"))); Q_ASSERT(obj); //go through the user data and update the mixer matrix for (i=0;i<8;i++) { field = obj->getField(tr( "Mixer%1Vector" ).arg(i+1)); //config the vector for (j=0;j<5;j++) { MixerDataFromHeli[i][j] = field->getValue(j).toInt(); //field->setValue(m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt(),j); } } for (i=0;i<8;i++) { field = obj->getField(tr( "Mixer%1Type" ).arg(i+1)); MixerOutputType[i] = field->getValue().toString(); } 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].compare("Motor")==0)&& (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].compare("Servo")==0)&& //(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].compare("Servo")==0)&& (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 //if (NumServos==0)m_ccpm->ccpmServoWChannel->setCurrentIndex(i); //if (NumServos==1)m_ccpm->ccpmServoXChannel->setCurrentIndex(i); //if (NumServos==2)m_ccpm->ccpmServoYChannel->setCurrentIndex(i); //if (NumServos==3)m_ccpm->ccpmServoZChannel->setCurrentIndex(i); NumServos++; } } //just call it user angles for now.... /* m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("Custom - User Angles")); if (NumServos>1) { if((ServoCurve2[0]==0)&&(ServoCurve2[1]==0)&&(ServoCurve2[2]==0)&&(ServoCurve2[3]==0)) { //fixed pitch heli isCCPM=0; m_ccpm->ccpmCollectiveSlider->setValue(0); Collective = 0.0; } if(ServoCurve2[0]==ServoCurve2[1]) { if ((NumServos<3)||(ServoCurve2[1]==ServoCurve2[2])) { if ((NumServos<4)||(ServoCurve2[2]==ServoCurve2[3])) {//all the servos have the same ThrottleCurve2 setting so this must be a CCPM config isCCPM=1; Collective = ((double)ServoCurve2[0]*100.00)/127.00; m_ccpm->ccpmCollectiveSlider->setValue((int)Collective); m_ccpm->ccpmCollectivespinBox->setValue((int)Collective); } } } } else {//must be a custom config... "Custom - Advanced Settings" m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("Custom - Advanced Settings")); } HeadRotation=0; HeadRotation=m_ccpm->ccpmSingleServo->currentIndex(); //calculate the angles for(j=0;jccpmSingleServo->setCurrentIndex(HeadRotation); //calculate the un rotated angles for(j=0;j CalcAngles[SortAngles[j+1]]) {//swap the sorted angles temp = SortAngles[j]; SortAngles[j]=SortAngles[j+1]; SortAngles[j+1]=temp; } } //m_ccpm->ccpmAngleW->setValue(ServoAngles[SortAngles[0]]); //m_ccpm->ccpmAngleX->setValue(ServoAngles[SortAngles[1]]); //m_ccpm->ccpmAngleY->setValue(ServoAngles[SortAngles[2]]); //m_ccpm->ccpmAngleZ->setValue(ServoAngles[SortAngles[3]]); //m_ccpm->ccpmServoWChannel->setCurrentIndex(ServoChannels[SortAngles[0]]); //m_ccpm->ccpmServoXChannel->setCurrentIndex(ServoChannels[SortAngles[1]]); //m_ccpm->ccpmServoYChannel->setCurrentIndex(ServoChannels[SortAngles[2]]); //m_ccpm->ccpmServoZChannel->setCurrentIndex(ServoChannels[SortAngles[3]]); m_ccpm->ccpmServoWChannel->setCurrentIndex(ServoChannels[0]); m_ccpm->ccpmServoXChannel->setCurrentIndex(ServoChannels[1]); m_ccpm->ccpmServoYChannel->setCurrentIndex(ServoChannels[2]); m_ccpm->ccpmServoZChannel->setCurrentIndex(ServoChannels[3]); //Types << "CCPM 2 Servo 90º" << "CCPM 3 Servo 120º" << "CCPM 3 Servo 140º" << "FP 2 Servo 90º" << "Custom - User Angles" << "Custom - Advanced Settings" ; //check this against known combinations if (NumServos==2) { if ((fabs(CalcAngles[SortAngles[0]])ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("CCPM 2 Servo 90º")); UpdateType(); } else { m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("FP 2 Servo 90º")); UpdateType(); } } } if (NumServos==3) { if ((fabs(CalcAngles[SortAngles[0]])ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("CCPM 3 Servo 120º")); UpdateType(); } else { m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("FP 3 Servo 120º")); UpdateType(); } } else if ((fabs(CalcAngles[SortAngles[0]])ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("CCPM 3 Servo 140º")); UpdateType(); } else { m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("FP 3 Servo 140º")); UpdateType(); } } } if (NumServos==4) { } */ //get the settings for the curve from the mixer settings field = obj->getField(QString("ThrottleCurve1")); for (i=0;i<5;i++) { m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",field->getValue(i).toDouble())); //m_ccpm->CurveSettings->item(i, 0)->setText(field->getValue(i).toString()); } field = obj->getField(QString("ThrottleCurve2")); for (i=0;i<5;i++) { m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",field->getValue(i).toDouble())); //m_ccpm->CurveSettings->item(i, 1)->setText(field->getValue(i).toString()); } updatingFromHardware=FALSE; UpdatCCPMUIFromOptions(); ccpmSwashplateUpdate(); } /** Sends the config to the board (ccpm type) */ void ConfigccpmWidget::sendccpmUpdate() { int i,j; UAVObjectField *field; UAVDataObject* obj; if (SwashLvlConfigurationInProgress)return; updatingToHardware=TRUE; //ShowDisclaimer(1); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); UpdatCCPMOptionsFromUI(); obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); field = obj->getField(QString("GUIConfigData")); field->setValue(GUIConfigData.UAVObject[0],0); field->setValue(GUIConfigData.UAVObject[1],1); obj->updated(); obj = dynamic_cast(objManager->getObject(QString("MixerSettings"))); Q_ASSERT(obj); UpdateMixer(); //clear the output types for (i=0;i<8;i++) { field = obj->getField(tr( "Mixer%1Type" ).arg( i+1 )); //clear the mixer type field->setValue("Disabled"); } //go through the user data and update the mixer matrix for (i=0;i<6;i++) { /* data.Mixer0Type = 0;//Disabled,Motor,Servo data.Mixer0Vector[0] = 0;//ThrottleCurve1 data.Mixer0Vector[1] = 0;//ThrottleCurve2 data.Mixer0Vector[2] = 0;//Roll data.Mixer0Vector[3] = 0;//Pitch data.Mixer0Vector[4] = 0;//Yaw */ if (MixerChannelData[i]<8) { //select the correct mixer for this config element field = obj->getField(tr( "Mixer%1Type" ).arg( MixerChannelData[i]+1 )); //set the mixer type if (i==0) { field->setValue("Motor"); } else { field->setValue("Servo"); } //select the correct mixer for this config element field = obj->getField(tr( "Mixer%1Vector" ).arg( MixerChannelData[i]+1 )); //config the vector for (j=0;j<5;j++) { field->setValue(m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt(),j); } } } //get the user data for the curve into the mixer settings field = obj->getField(QString("ThrottleCurve1")); for (i=0;i<5;i++) { field->setValue(m_ccpm->CurveSettings->item(i, 0)->text().toDouble(),i); } field = obj->getField(QString("ThrottleCurve2")); for (i=0;i<5;i++) { field->setValue(m_ccpm->CurveSettings->item(i, 1)->text().toDouble(),i); } obj->updated(); field = obj->getField(QString("Curve2Source")); //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) {// input channel field->setValue("Accessory0"); obj->updated(); obj = dynamic_cast(objManager->getObject(QString("ManualControlSettings"))); Q_ASSERT(obj); field = obj->getField(QString("Accessory0")); field->setValue(tr( "Channel%1" ).arg(GUIConfigData.heli.CollectiveChannel+1)); } else {// throttle field->setValue("Throttle"); } obj->updated(); updatingToHardware=FALSE; } /** Send ccpm type to the board and request saving to SD card */ void ConfigccpmWidget::saveccpmUpdate() { if (SwashLvlConfigurationInProgress)return; ShowDisclaimer(0); // Send update so that the latest value is saved sendccpmUpdate(); UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); Q_ASSERT(obj); saveObjectToSD(obj); } void ConfigccpmWidget::resizeEvent(QResizeEvent* event) { Q_UNUSED(event); // Make the custom table columns autostretch: m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); for (int i=0;i<6;i++) { m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); } ccpmSwashplateRedraw(); } void ConfigccpmWidget::showEvent(QShowEvent *event) { Q_UNUSED(event) m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); for (int i=0;i<6;i++) { m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); } ccpmSwashplateRedraw(); } void ConfigccpmWidget::SwashLvlStartButtonPressed() { QMessageBox msgBox; int i; msgBox.setText("

Swashplate Leveling Routine

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

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

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

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

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

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

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


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

Neutral levelling

Using adjustment of:

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

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

Max levelling

Using adjustment of:

  • Max timing spinboxes to the right ONLY

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

Min levelling

Using adjustment of:

  • Min timing spinboxes to the right ONLY

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

levelling verification

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

levelling complete

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

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

Levelling Cancelled

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

Levelling Completed

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

Warning!!!

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

This code has many configurations.

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

The CCPM mixer code needs more testing!

Use it at your own risk!

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

The CCPM swashplate levelling code is NOT complete!

DO NOT use it for flight!"); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setIcon(QMessageBox::Critical); ret = msgBox.exec(); return 0; break; default: // should never be reached break; } return -1; } /** Toggles the channel testing mode by making the GCS take over the ActuatorCommand objects */ void ConfigccpmWidget::enableSwashplateLevellingControl(bool state) { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorCommand"))); UAVObject::Metadata mdata = obj->getMetadata(); if (state) { SwashLvlaccInitialData = mdata; mdata.flightAccess = UAVObject::ACCESS_READONLY; mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE; mdata.gcsTelemetryAcked = false; mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE; mdata.gcsTelemetryUpdatePeriod = 100; SwashLvlConfigurationInProgress=1; connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),this, SLOT(FocusChanged(QWidget*,QWidget*))); 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; disconnect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),this, SLOT(FocusChanged(QWidget*,QWidget*))); 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; UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); UAVObjectField * channel = obj->getField("Channel"); if (level==0) { for (i=0;isetValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]); SwashLvlSpinBoxes[i]->setValue(newSwashLvlConfiguration.Neutral[i]); } } else if (level>0) { for (i=0;isetValue(value,newSwashLvlConfiguration.ServoChannels[i]); SwashLvlSpinBoxes[i]->setValue(value); } } else if (level<0) { for (i=0;isetValue(value,newSwashLvlConfiguration.ServoChannels[i]); SwashLvlSpinBoxes[i]->setValue(value); } } obj->updated(); SwashLvlServoInterlock=0; return; } void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value) { int i; if (SwashLvlServoInterlock==1)return; UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); UAVObjectField * channel = obj->getField("Channel"); switch (SwashLvlState) { case 0: break; case 1: //Neutral levelling for (i=0;ivalue(); channel->setValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]); } obj->updated(); break; case 2: //Max levelling for (i=0;ivalue(); channel->setValue(newSwashLvlConfiguration.Max[i],newSwashLvlConfiguration.ServoChannels[i]); } obj->updated(); break; case 3: //Min levelling for (i=0;ivalue(); channel->setValue(newSwashLvlConfiguration.Min[i],newSwashLvlConfiguration.ServoChannels[i]); } obj->updated(); break; case 4: //levelling verification break; case 5: //levelling complete break; default: break; } return; } void ConfigccpmWidget::FocusChanged(QWidget *oldFocus, QWidget *newFocus) { if (SwashLvlConfigurationInProgress!=1) return; QMessageBox msgBox; int ret; msgBox.setText("

Warning!!!

"); if ((this->isAncestorOf(oldFocus))&&(!this->isAncestorOf(newFocus))) { msgBox.setInformativeText("You are in the middle of the levelling routine
Changing focus will cancel all levelling and return the OP hardware to the state it was in before levelling began.

Do you want to continue the levelling routine?"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); msgBox.setIcon(QMessageBox::Information); ret = msgBox.exec(); if (ret == QMessageBox::Yes) { //m_ccpm->TabObject->setCurrentIndex(1); //m_ccpm->SwashPlateLevel->setFocus(Qt::MouseFocusReason); //m_ccpm->SwashLvlInstructionsBox->setFocus(Qt::MouseFocusReason); oldFocus->setFocus(Qt::MouseFocusReason); } if (ret == QMessageBox::No) { SwashLvlCancelButtonPressed(); } } }