/** ****************************************************************************** * * @file configahrswidget.h * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup ConfigPlugin Config Plugin * @{ * @brief The Configuration Gadget used to update settings in the firmware *****************************************************************************/ /* * 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 "configahrswidget.h" #include "math.h" #include #include #include #include #include #include #include ConfigAHRSWidget::ConfigAHRSWidget(QWidget *parent) : ConfigTaskWidget(parent) { m_ahrs = new Ui_AHRSWidget(); m_ahrs->setupUi(this); m_ahrs->ahrsBargraph->setScene(new QGraphicsScene(this)); QSvgRenderer *renderer = new QSvgRenderer(); ahrsbargraph = new QGraphicsSvgItem(); renderer->load(QString(":/configgadget/images/ahrs-calib.svg")); ahrsbargraph->setSharedRenderer(renderer); ahrsbargraph->setElementId("background"); ahrsbargraph->setObjectName("background"); m_ahrs->ahrsBargraph->scene()->addItem(ahrsbargraph); m_ahrs->ahrsBargraph->setSceneRect(ahrsbargraph->boundingRect()); // Initialize the 9 bargraph values: QMatrix lineMatrix = renderer->matrixForElement("accel_x"); QRectF rect = lineMatrix.mapRect(renderer->boundsOnElement("accel_x")); qreal startX = rect.x(); qreal startY = rect.y()+ rect.height(); // maxBarHeight will be used for scaling it later. maxBarHeight = rect.height(); // Then once we have the initial location, we can put it // into a QGraphicsSvgItem which we will display at the same // place: we do this so that the heading scale can be clipped to // the compass dial region. accel_x = new QGraphicsSvgItem(); accel_x->setSharedRenderer(renderer); accel_x->setElementId("accel_x"); m_ahrs->ahrsBargraph->scene()->addItem(accel_x); accel_x->setPos(startX, startY); accel_x->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("accel_y"); rect = lineMatrix.mapRect(renderer->boundsOnElement("accel_y")); startX = rect.x(); startY = rect.y()+ rect.height(); accel_y = new QGraphicsSvgItem(); accel_y->setSharedRenderer(renderer); accel_y->setElementId("accel_y"); m_ahrs->ahrsBargraph->scene()->addItem(accel_y); accel_y->setPos(startX,startY); accel_y->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("accel_z"); rect = lineMatrix.mapRect(renderer->boundsOnElement("accel_z")); startX = rect.x(); startY = rect.y()+ rect.height(); accel_z = new QGraphicsSvgItem(); accel_z->setSharedRenderer(renderer); accel_z->setElementId("accel_z"); m_ahrs->ahrsBargraph->scene()->addItem(accel_z); accel_z->setPos(startX,startY); accel_z->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("gyro_x"); rect = lineMatrix.mapRect(renderer->boundsOnElement("gyro_x")); startX = rect.x(); startY = rect.y()+ rect.height(); gyro_x = new QGraphicsSvgItem(); gyro_x->setSharedRenderer(renderer); gyro_x->setElementId("gyro_x"); m_ahrs->ahrsBargraph->scene()->addItem(gyro_x); gyro_x->setPos(startX,startY); gyro_x->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("gyro_y"); rect = lineMatrix.mapRect(renderer->boundsOnElement("gyro_y")); startX = rect.x(); startY = rect.y()+ rect.height(); gyro_y = new QGraphicsSvgItem(); gyro_y->setSharedRenderer(renderer); gyro_y->setElementId("gyro_y"); m_ahrs->ahrsBargraph->scene()->addItem(gyro_y); gyro_y->setPos(startX,startY); gyro_y->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("gyro_z"); rect = lineMatrix.mapRect(renderer->boundsOnElement("gyro_z")); startX = rect.x(); startY = rect.y()+ rect.height(); gyro_z = new QGraphicsSvgItem(); gyro_z->setSharedRenderer(renderer); gyro_z->setElementId("gyro_z"); m_ahrs->ahrsBargraph->scene()->addItem(gyro_z); gyro_z->setPos(startX,startY); gyro_z->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("mag_x"); rect = lineMatrix.mapRect(renderer->boundsOnElement("mag_x")); startX = rect.x(); startY = rect.y()+ rect.height(); mag_x = new QGraphicsSvgItem(); mag_x->setSharedRenderer(renderer); mag_x->setElementId("mag_x"); m_ahrs->ahrsBargraph->scene()->addItem(mag_x); mag_x->setPos(startX,startY); mag_x->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("mag_y"); rect = lineMatrix.mapRect(renderer->boundsOnElement("mag_y")); startX = rect.x(); startY = rect.y()+ rect.height(); mag_y = new QGraphicsSvgItem(); mag_y->setSharedRenderer(renderer); mag_y->setElementId("mag_y"); m_ahrs->ahrsBargraph->scene()->addItem(mag_y); mag_y->setPos(startX,startY); mag_y->setTransform(QTransform::fromScale(1,0),true); lineMatrix = renderer->matrixForElement("mag_z"); rect = lineMatrix.mapRect(renderer->boundsOnElement("mag_z")); startX = rect.x(); startY = rect.y()+ rect.height(); mag_z = new QGraphicsSvgItem(); mag_z->setSharedRenderer(renderer); mag_z->setElementId("mag_z"); m_ahrs->ahrsBargraph->scene()->addItem(mag_z); mag_z->setPos(startX,startY); mag_z->setTransform(QTransform::fromScale(1,0),true); // Fill the dropdown menus: UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSSettings"))); UAVObjectField *field = obj->getField(QString("Algorithm")); m_ahrs->algorithm->addItems(field->getOptions()); // Connect the signals connect(m_ahrs->ahrsCalibStart, SIGNAL(clicked()), this, SLOT(launchAHRSCalibration())); connect(m_ahrs->ahrsCalibSave, SIGNAL(clicked()), this, SLOT(saveAHRSCalibration())); connect(m_ahrs->ahrsSettingsRequest, SIGNAL(clicked()), this, SLOT(ahrsSettingsRequest())); connect(parent, SIGNAL(autopilotConnected()),this, SLOT(ahrsSettingsRequest())); } ConfigAHRSWidget::~ConfigAHRSWidget() { // Do nothing } void ConfigAHRSWidget::showEvent(QShowEvent *event) { m_ahrs->ahrsBargraph->fitInView(ahrsbargraph, Qt::KeepAspectRatio); } /** Launches the AHRS sensors calibration */ void ConfigAHRSWidget::launchAHRSCalibration() { m_ahrs->calibInstructions->setText("Calibration launched..."); m_ahrs->ahrsCalibStart->setEnabled(false); m_ahrs->ahrsCalibSave->setEnabled(false); UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSCalibration"))); UAVObjectField *field = obj->getField(QString("measure_var")); field->setValue("TRUE"); obj->updated(); QTimer::singleShot(15000, this, SLOT(calibPhase2())); phaseCounter = 0; progressBarIndex = 0; connect(&progressBarTimer, SIGNAL(timeout()), this, SLOT(incrementProgress())); progressBarTimer.start(1000); } /** Increment progress bar */ void ConfigAHRSWidget::incrementProgress() { m_ahrs->calibProgress->setValue(progressBarIndex++); if (progressBarIndex > m_ahrs->calibProgress->maximum()) { progressBarTimer.stop(); progressBarIndex = 0; } } /** Callback once calibration is done on the board. Currently we don't have a way to tell if calibration is finished, so we have to use a timer. calibPhase2 is also connected to the AHRSCalibration object update signal. */ void ConfigAHRSWidget::calibPhase2() { UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSCalibration"))); // This is a bit weird, but it is because we are expecting an update from the // OP board with the correct calibration values, and those only arrive on the object update // which comes back from the board, and not the first object update signal which is in fast // the object update we did ourselves... Clear ? switch (phaseCounter) { case 0: phaseCounter++; m_ahrs->calibInstructions->setText("Getting results..."); connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(calibPhase2())); obj->updated(); break; case 1: // this is where we end up with the update just above phaseCounter++; break; case 2: { // This is the update with the right values (coming from the board) disconnect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(calibPhase2())); // Now update size of all the graphs drawVariancesGraph(); // Now wait 15 more seconds before re-enabling the "Save" button QTimer::singleShot(15000, this, SLOT(calibPhase2())); m_ahrs->calibInstructions->setText(QString("Please review the results...")); progressBarIndex = 0; phaseCounter++; } break; case 3: // This step re-enables the "Save" button m_ahrs->calibInstructions->setText(QString("Press \"Save\" if OK.")); m_ahrs->ahrsCalibStart->setEnabled(true); m_ahrs->ahrsCalibSave->setEnabled(true); break; } } /** Saves the AHRS sensors calibration (to RAM only) */ void ConfigAHRSWidget::saveAHRSCalibration() { UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSCalibration"))); UAVObjectField *field = obj->getField(QString("measure_var")); field->setValue("FALSE"); obj->updated(); } /** Draws the sensor variances bargraph */ void ConfigAHRSWidget::drawVariancesGraph() { UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSCalibration"))); // Now update size of all the graphs // I have not found a way to do this elegantly... UAVObjectField *field = obj->getField(QString("accel_var")); // The expected range is from 1E-6 to 1E-1 double steps = 6; // 6 bars on the graph float accel_x_var = -1/steps*(1+steps+log10(field->getValue(0).toFloat())); accel_x->setTransform(QTransform::fromScale(1,accel_x_var),false); float accel_y_var = -1/steps*(1+steps+log10(field->getValue(1).toFloat())); accel_y->setTransform(QTransform::fromScale(1,accel_y_var),false); float accel_z_var = -1/steps*(1+steps+log10(field->getValue(2).toFloat())); accel_z->setTransform(QTransform::fromScale(1,accel_z_var),false); field = obj->getField(QString("gyro_var")); float gyro_x_var = -1/steps*(1+steps+log10(field->getValue(0).toFloat())); gyro_x->setTransform(QTransform::fromScale(1,gyro_x_var),false); float gyro_y_var = -1/steps*(1+steps+log10(field->getValue(1).toFloat())); gyro_y->setTransform(QTransform::fromScale(1,gyro_y_var),false); float gyro_z_var = -1/steps*(1+steps+log10(field->getValue(2).toFloat())); gyro_z->setTransform(QTransform::fromScale(1,gyro_z_var),false); field = obj->getField(QString("mag_var")); float mag_x_var = -1/steps*(1+steps+log10(field->getValue(0).toFloat())); mag_x->setTransform(QTransform::fromScale(1,mag_x_var),false); float mag_y_var = -1/steps*(1+steps+log10(field->getValue(1).toFloat())); mag_y->setTransform(QTransform::fromScale(1,mag_y_var),false); float mag_z_var = -1/steps*(1+steps+log10(field->getValue(2).toFloat())); mag_z->setTransform(QTransform::fromScale(1,mag_z_var),false); } /** Request current settings from the AHRS */ void ConfigAHRSWidget::ahrsSettingsRequest() { UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSSettings"))); obj->requestUpdate(); UAVObjectField *field = obj->getField(QString("Algorithm")); m_ahrs->algorithm->setCurrentIndex(m_ahrs->algorithm->findText(field->getValue().toString())); drawVariancesGraph(); }