mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-10 20:52:11 +01:00
671 lines
28 KiB
C++
671 lines
28 KiB
C++
/**
|
|
******************************************************************************
|
|
*
|
|
* @file outputcalibrationpage.cpp
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
|
* @addtogroup
|
|
* @{
|
|
* @addtogroup OutputCalibrationPage
|
|
* @{
|
|
* @brief
|
|
*****************************************************************************/
|
|
/*
|
|
* 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 "outputcalibrationpage.h"
|
|
#include "ui_outputcalibrationpage.h"
|
|
#include "systemalarms.h"
|
|
#include "uavobjectmanager.h"
|
|
|
|
const QString OutputCalibrationPage::MULTI_SVG_FILE = QString(":/setupwizard/resources/multirotor-shapes.svg");
|
|
const QString OutputCalibrationPage::FIXEDWING_SVG_FILE = QString(":/setupwizard/resources/fixedwing-shapes-wizard.svg");
|
|
const QString OutputCalibrationPage::GROUND_SVG_FILE = QString(":/setupwizard/resources/ground-shapes-wizard.svg");
|
|
|
|
OutputCalibrationPage::OutputCalibrationPage(SetupWizard *wizard, QWidget *parent) :
|
|
AbstractWizardPage(wizard, parent), ui(new Ui::OutputCalibrationPage), m_vehicleBoundsItem(0),
|
|
m_currentWizardIndex(-1), m_calibrationUtil(0)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
qDebug() << "calling output calibration page";
|
|
m_vehicleRenderer = new QSvgRenderer();
|
|
|
|
// move the code that was here to setupVehicle() so we can determine which image to use.
|
|
m_vehicleScene = new QGraphicsScene(this);
|
|
ui->vehicleView->setScene(m_vehicleScene);
|
|
}
|
|
|
|
OutputCalibrationPage::~OutputCalibrationPage()
|
|
{
|
|
if (m_calibrationUtil) {
|
|
delete m_calibrationUtil;
|
|
m_calibrationUtil = 0;
|
|
}
|
|
|
|
OutputCalibrationUtil::stopOutputCalibration();
|
|
delete ui;
|
|
}
|
|
|
|
void OutputCalibrationPage::loadSVGFile(QString file)
|
|
{
|
|
if (QFile::exists(file) && m_vehicleRenderer->load(file) && m_vehicleRenderer->isValid()) {
|
|
ui->vehicleView->setScene(m_vehicleScene);
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::setupActuatorMinMaxAndNeutral(int motorChannelStart, int motorChannelEnd, int totalUsedChannels)
|
|
{
|
|
// Default values for the actuator settings, extra important for
|
|
// servos since a value out of range can actually destroy the
|
|
// vehicle if unlucky.
|
|
// Motors are not that important. REMOVE propellers always!!
|
|
OutputCalibrationUtil::startOutputCalibration();
|
|
|
|
for (int servoid = 0; servoid < 12; servoid++) {
|
|
if (servoid >= motorChannelStart && servoid <= motorChannelEnd) {
|
|
// Set to motor safe values
|
|
m_actuatorSettings[servoid].channelMin = LOW_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].channelNeutral = LOW_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].channelMax = getHighOutputRate();
|
|
m_actuatorSettings[servoid].isReversableMotor = false;
|
|
// Car and Tank should use reversable Esc/motors
|
|
if ((getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_CAR)
|
|
|| (getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_DIFFERENTIAL)) {
|
|
m_actuatorSettings[servoid].channelNeutral = NEUTRAL_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].isReversableMotor = true;
|
|
// Set initial output value
|
|
m_calibrationUtil->startChannelOutput(servoid, NEUTRAL_OUTPUT_RATE_MILLISECONDS);
|
|
m_calibrationUtil->stopChannelOutput();
|
|
}
|
|
} else if (servoid < totalUsedChannels) {
|
|
// Set to servo safe values
|
|
m_actuatorSettings[servoid].channelMin = NEUTRAL_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].channelNeutral = NEUTRAL_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].channelMax = NEUTRAL_OUTPUT_RATE_MILLISECONDS;
|
|
// Set initial servo output value
|
|
m_calibrationUtil->startChannelOutput(servoid, NEUTRAL_OUTPUT_RATE_MILLISECONDS);
|
|
m_calibrationUtil->stopChannelOutput();
|
|
} else {
|
|
// "Disable" these channels
|
|
m_actuatorSettings[servoid].channelMin = LOW_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].channelNeutral = LOW_OUTPUT_RATE_MILLISECONDS;
|
|
m_actuatorSettings[servoid].channelMax = LOW_OUTPUT_RATE_MILLISECONDS;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::setupVehicle()
|
|
{
|
|
m_actuatorSettings = getWizard()->getActuatorSettings();
|
|
m_wizardIndexes.clear();
|
|
m_vehicleElementIds.clear();
|
|
m_vehicleHighlightElementIndexes.clear();
|
|
m_channelIndex.clear();
|
|
m_currentWizardIndex = 0;
|
|
m_vehicleScene->clear();
|
|
|
|
resetOutputCalibrationUtil();
|
|
|
|
switch (getWizard()->getVehicleSubType()) {
|
|
case SetupWizard::MULTI_ROTOR_TRI_Y:
|
|
// Loads the SVG file resourse and sets the scene
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
|
|
// The m_wizardIndexes array contains the index of the QStackedWidget
|
|
// in the page to use for each step.
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 2;
|
|
|
|
// All element ids to load from the svg file and manage.
|
|
m_vehicleElementIds << "tri" << "tri-frame" << "tri-m1" << "tri-m2" << "tri-m3" << "tri-s1";
|
|
|
|
// The index of the elementId to highlight ( not dim ) for each step
|
|
// this is the index in the m_vehicleElementIds - 1.
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4;
|
|
|
|
// The channel number to configure for each step.
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3;
|
|
|
|
setupActuatorMinMaxAndNeutral(0, 2, 4);
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
case SetupWizard::MULTI_ROTOR_QUAD_X:
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 1;
|
|
m_vehicleElementIds << "quad-x" << "quad-x-frame" << "quad-x-m1" << "quad-x-m2" << "quad-x-m3" << "quad-x-m4";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4;
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3;
|
|
setupActuatorMinMaxAndNeutral(0, 3, 4);
|
|
break;
|
|
case SetupWizard::MULTI_ROTOR_QUAD_PLUS:
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 1;
|
|
m_vehicleElementIds << "quad-p" << "quad-p-frame" << "quad-p-m1" << "quad-p-m2" << "quad-p-m3" << "quad-p-m4";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4;
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3;
|
|
setupActuatorMinMaxAndNeutral(0, 3, 4);
|
|
break;
|
|
case SetupWizard::MULTI_ROTOR_HEXA:
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
|
|
m_vehicleElementIds << "hexa" << "hexa-frame" << "hexa-m1" << "hexa-m2" << "hexa-m3" << "hexa-m4" << "hexa-m5" << "hexa-m6";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5 << 6;
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
|
|
setupActuatorMinMaxAndNeutral(0, 5, 6);
|
|
break;
|
|
case SetupWizard::MULTI_ROTOR_HEXA_COAX_Y:
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
|
|
m_vehicleElementIds << "hexa-y6" << "hexa-y6-frame" << "hexa-y6-m2" << "hexa-y6-m1" << "hexa-y6-m4" << "hexa-y6-m3" << "hexa-y6-m6" << "hexa-y6-m5";
|
|
m_vehicleHighlightElementIndexes << 0 << 2 << 1 << 4 << 3 << 6 << 5;
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
|
|
setupActuatorMinMaxAndNeutral(0, 5, 6);
|
|
break;
|
|
case SetupWizard::MULTI_ROTOR_HEXA_H:
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
|
|
m_vehicleElementIds << "hexa-h" << "hexa-h-frame" << "hexa-h-m1" << "hexa-h-m2" << "hexa-h-m3" << "hexa-h-m4" << "hexa-h-m5" << "hexa-h-m6";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5 << 6;
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
|
|
setupActuatorMinMaxAndNeutral(0, 5, 6);
|
|
break;
|
|
case SetupWizard::MULTI_ROTOR_HEXA_X:
|
|
loadSVGFile(MULTI_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
|
|
m_vehicleElementIds << "hexa-x" << "hexa-x-frame" << "hexa-x-m1" << "hexa-x-m2" << "hexa-x-m3" << "hexa-x-m4" << "hexa-x-m5" << "hexa-x-m6";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5 << 6;
|
|
m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
|
|
setupActuatorMinMaxAndNeutral(0, 5, 6);
|
|
break;
|
|
// Fixed Wing
|
|
case SetupWizard::FIXED_WING_DUAL_AILERON:
|
|
loadSVGFile(FIXEDWING_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 2 << 2 << 2 << 2;
|
|
m_vehicleElementIds << "aileron" << "aileron-frame" << "aileron-motor" << "aileron-ail-left" << "aileron-ail-right" << "aileron-elevator" << "aileron-rudder";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5;
|
|
m_channelIndex << 0 << 2 << 0 << 5 << 1 << 3;
|
|
|
|
setupActuatorMinMaxAndNeutral(2, 2, 6); // should be 5 instead 6 but output 5 is not used
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
case SetupWizard::FIXED_WING_AILERON:
|
|
loadSVGFile(FIXEDWING_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 2 << 2 << 2;
|
|
m_vehicleElementIds << "aileron-single" << "ail2-frame" << "ail2-motor" << "ail2-aileron" << "ail2-elevator" << "ail2-rudder";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4;
|
|
m_channelIndex << 0 << 2 << 0 << 1 << 3;
|
|
|
|
setupActuatorMinMaxAndNeutral(2, 2, 4);
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
case SetupWizard::FIXED_WING_ELEVON:
|
|
loadSVGFile(FIXEDWING_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 2 << 2;
|
|
m_vehicleElementIds << "elevon" << "elevon-frame" << "elevon-motor" << "elevon-left" << "elevon-right";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3;
|
|
m_channelIndex << 0 << 2 << 0 << 1;
|
|
|
|
setupActuatorMinMaxAndNeutral(2, 2, 3);
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
case SetupWizard::FIXED_WING_VTAIL:
|
|
loadSVGFile(FIXEDWING_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 2 << 2 << 2 << 2;
|
|
m_vehicleElementIds << "vtail" << "vtail-frame" << "vtail-motor" << "vtail-ail-left" << "vtail-ail-right" << "vtail-rudder-left" << "vtail-rudder-right";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5;
|
|
m_channelIndex << 0 << 2 << 0 << 5 << 3 << 1;
|
|
|
|
setupActuatorMinMaxAndNeutral(2, 2, 6); // should be 5 instead 6 but output 5 is not used
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
|
|
// Ground vehicles
|
|
case SetupWizard::GROUNDVEHICLE_CAR:
|
|
loadSVGFile(GROUND_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 2;
|
|
m_vehicleElementIds << "car" << "car-frame" << "car-motor" << "car-steering";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2;
|
|
m_channelIndex << 0 << 1 << 0;
|
|
|
|
setupActuatorMinMaxAndNeutral(1, 1, 2);
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
case SetupWizard::GROUNDVEHICLE_DIFFERENTIAL:
|
|
loadSVGFile(GROUND_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 1;
|
|
m_vehicleElementIds << "tank" << "tank-frame" << "tank-left-motor" << "tank-right-motor";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2;
|
|
m_channelIndex << 0 << 0 << 1;
|
|
|
|
setupActuatorMinMaxAndNeutral(0, 1, 2);
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
case SetupWizard::GROUNDVEHICLE_MOTORCYCLE:
|
|
loadSVGFile(GROUND_SVG_FILE);
|
|
m_wizardIndexes << 0 << 1 << 2;
|
|
m_vehicleElementIds << "motorbike" << "motorbike-frame" << "motorbike-motor" << "motorbike-steering";
|
|
m_vehicleHighlightElementIndexes << 0 << 1 << 2;
|
|
m_channelIndex << 0 << 1 << 0;
|
|
|
|
setupActuatorMinMaxAndNeutral(1, 1, 2);
|
|
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
setupVehicleItems();
|
|
}
|
|
|
|
void OutputCalibrationPage::setupVehicleItems()
|
|
{
|
|
m_vehicleItems.clear();
|
|
m_vehicleBoundsItem = new QGraphicsSvgItem();
|
|
m_vehicleBoundsItem->setSharedRenderer(m_vehicleRenderer);
|
|
m_vehicleBoundsItem->setElementId(m_vehicleElementIds[0]);
|
|
m_vehicleBoundsItem->setZValue(-1);
|
|
m_vehicleBoundsItem->setOpacity(0);
|
|
m_vehicleScene->addItem(m_vehicleBoundsItem);
|
|
|
|
QRectF parentBounds = m_vehicleRenderer->boundsOnElement(m_vehicleElementIds[0]);
|
|
|
|
for (int i = 1; i < m_vehicleElementIds.size(); i++) {
|
|
QGraphicsSvgItem *item = new QGraphicsSvgItem();
|
|
item->setSharedRenderer(m_vehicleRenderer);
|
|
item->setElementId(m_vehicleElementIds[i]);
|
|
item->setZValue(i);
|
|
item->setOpacity(1.0);
|
|
|
|
QRectF itemBounds = m_vehicleRenderer->boundsOnElement(m_vehicleElementIds[i]);
|
|
item->setPos(itemBounds.x() - parentBounds.x(), itemBounds.y() - parentBounds.y());
|
|
|
|
m_vehicleScene->addItem(item);
|
|
m_vehicleItems << item;
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::startWizard()
|
|
{
|
|
ui->calibrationStack->setCurrentIndex(m_wizardIndexes[0]);
|
|
setupVehicleHighlightedPart();
|
|
}
|
|
|
|
void OutputCalibrationPage::setupVehicleHighlightedPart()
|
|
{
|
|
qreal dimOpaque = m_currentWizardIndex == 0 ? 1.0 : 0.3;
|
|
qreal highlightOpaque = 1.0;
|
|
int highlightedIndex = m_vehicleHighlightElementIndexes[m_currentWizardIndex];
|
|
|
|
for (int i = 0; i < m_vehicleItems.size(); i++) {
|
|
QGraphicsSvgItem *item = m_vehicleItems[i];
|
|
item->setOpacity((highlightedIndex == i) ? highlightOpaque : dimOpaque);
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::setWizardPage()
|
|
{
|
|
qDebug() << "Wizard index: " << m_currentWizardIndex;
|
|
|
|
QApplication::processEvents();
|
|
|
|
int currentPageIndex = m_wizardIndexes[m_currentWizardIndex];
|
|
qDebug() << "Current page: " << currentPageIndex;
|
|
ui->calibrationStack->setCurrentIndex(currentPageIndex);
|
|
|
|
int currentChannel = getCurrentChannel();
|
|
qDebug() << "Current channel: " << currentChannel + 1;
|
|
if (currentChannel >= 0) {
|
|
if (currentPageIndex == 1) {
|
|
ui->motorNeutralSlider->setValue(m_actuatorSettings[currentChannel].channelNeutral);
|
|
ui->motorPWMValue->setText(QString(tr("Output value : <b>%1</b> µs")).arg(m_actuatorSettings[currentChannel].channelNeutral));
|
|
// Reversable motor found
|
|
if (m_actuatorSettings[currentChannel].isReversableMotor) {
|
|
ui->motorNeutralSlider->setMinimum(m_actuatorSettings[currentChannel].channelMin);
|
|
ui->motorNeutralSlider->setMaximum(m_actuatorSettings[currentChannel].channelMax);
|
|
ui->motorInfo->setText(tr("<html><head/><body><p><span style=\" font-size:10pt;\">To find </span><span style=\" font-size:10pt; font-weight:600;\">the neutral rate for this reversable motor</span><span style=\" font-size:10pt;\">, press the Start button below and slide the slider to the right or left until you find the value where the motor doesn't start. <br/><br/>When done press button again to stop.</span></p></body></html>"));
|
|
}
|
|
} else if (currentPageIndex == 2) {
|
|
ui->servoPWMValue->setText(tr("Output value : <b>%1</b> µs").arg(m_actuatorSettings[currentChannel].channelNeutral));
|
|
if (m_actuatorSettings[currentChannel].channelMax < m_actuatorSettings[currentChannel].channelMin &&
|
|
!ui->reverseCheckbox->isChecked()) {
|
|
ui->reverseCheckbox->setChecked(true);
|
|
} else {
|
|
ui->reverseCheckbox->setChecked(false);
|
|
}
|
|
enableServoSliders(false);
|
|
if (ui->reverseCheckbox->isChecked()) {
|
|
ui->servoMaxAngleSlider->setValue(m_actuatorSettings[currentChannel].channelMax);
|
|
ui->servoCenterAngleSlider->setValue(m_actuatorSettings[currentChannel].channelNeutral);
|
|
ui->servoMinAngleSlider->setValue(m_actuatorSettings[currentChannel].channelMin);
|
|
} else {
|
|
ui->servoMinAngleSlider->setValue(m_actuatorSettings[currentChannel].channelMin);
|
|
ui->servoCenterAngleSlider->setValue(m_actuatorSettings[currentChannel].channelNeutral);
|
|
ui->servoMaxAngleSlider->setValue(m_actuatorSettings[currentChannel].channelMax);
|
|
}
|
|
}
|
|
}
|
|
setupVehicleHighlightedPart();
|
|
}
|
|
|
|
void OutputCalibrationPage::initializePage()
|
|
{
|
|
if (m_vehicleScene) {
|
|
setupVehicle();
|
|
startWizard();
|
|
}
|
|
}
|
|
|
|
bool OutputCalibrationPage::validatePage()
|
|
{
|
|
if (isFinished()) {
|
|
getWizard()->setActuatorSettings(m_actuatorSettings);
|
|
return true;
|
|
} else {
|
|
m_currentWizardIndex++;
|
|
setWizardPage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::showEvent(QShowEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
if (m_vehicleBoundsItem) {
|
|
ui->vehicleView->setSceneRect(m_vehicleBoundsItem->boundingRect());
|
|
ui->vehicleView->fitInView(m_vehicleBoundsItem, Qt::KeepAspectRatio);
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::resizeEvent(QResizeEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
if (m_vehicleBoundsItem) {
|
|
ui->vehicleView->setSceneRect(m_vehicleBoundsItem->boundingRect());
|
|
ui->vehicleView->fitInView(m_vehicleBoundsItem, Qt::KeepAspectRatio);
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::customBackClicked()
|
|
{
|
|
if (m_currentWizardIndex > 0) {
|
|
m_currentWizardIndex--;
|
|
setWizardPage();
|
|
} else {
|
|
getWizard()->back();
|
|
}
|
|
}
|
|
|
|
quint16 OutputCalibrationPage::getCurrentChannel()
|
|
{
|
|
return m_channelIndex[m_currentWizardIndex];
|
|
}
|
|
|
|
void OutputCalibrationPage::enableButtons(bool enable)
|
|
{
|
|
getWizard()->button(QWizard::NextButton)->setEnabled(enable);
|
|
getWizard()->button(QWizard::CustomButton1)->setEnabled(enable);
|
|
getWizard()->button(QWizard::CancelButton)->setEnabled(enable);
|
|
getWizard()->button(QWizard::BackButton)->setEnabled(enable);
|
|
QApplication::processEvents();
|
|
}
|
|
|
|
void OutputCalibrationPage::on_motorNeutralButton_toggled(bool checked)
|
|
{
|
|
ui->motorNeutralButton->setText(checked ? tr("Stop") : tr("Start"));
|
|
ui->motorNeutralSlider->setEnabled(checked);
|
|
quint16 channel = getCurrentChannel();
|
|
quint16 safeValue = m_actuatorSettings[channel].channelMin;
|
|
|
|
if (m_actuatorSettings[channel].isReversableMotor) {
|
|
safeValue = m_actuatorSettings[channel].channelNeutral;
|
|
}
|
|
|
|
onStartButtonToggle(ui->motorNeutralButton, channel, m_actuatorSettings[channel].channelNeutral, safeValue, ui->motorNeutralSlider);
|
|
}
|
|
|
|
void OutputCalibrationPage::onStartButtonToggle(QAbstractButton *button, quint16 channel, quint16 value, quint16 safeValue, QSlider *slider)
|
|
{
|
|
if (button->isChecked()) {
|
|
if (checkAlarms()) {
|
|
enableButtons(false);
|
|
enableServoSliders(true);
|
|
m_calibrationUtil->startChannelOutput(channel, safeValue);
|
|
slider->setValue(value);
|
|
m_calibrationUtil->setChannelOutputValue(value);
|
|
} else {
|
|
button->setChecked(false);
|
|
}
|
|
} else {
|
|
// Servos and ReversableMotors
|
|
m_calibrationUtil->startChannelOutput(channel, m_actuatorSettings[channel].channelNeutral);
|
|
|
|
// Normal motor
|
|
if ((button == ui->motorNeutralButton) && !m_actuatorSettings[channel].isReversableMotor) {
|
|
m_calibrationUtil->startChannelOutput(channel, m_actuatorSettings[channel].channelMin);
|
|
}
|
|
|
|
m_calibrationUtil->stopChannelOutput();
|
|
|
|
enableServoSliders(false);
|
|
enableButtons(true);
|
|
}
|
|
debugLogChannelValues();
|
|
}
|
|
|
|
void OutputCalibrationPage::enableServoSliders(bool enabled)
|
|
{
|
|
ui->servoCenterAngleSlider->setEnabled(enabled);
|
|
ui->servoMinAngleSlider->setEnabled(enabled);
|
|
ui->servoMaxAngleSlider->setEnabled(enabled);
|
|
ui->reverseCheckbox->setEnabled(!enabled);
|
|
}
|
|
|
|
bool OutputCalibrationPage::checkAlarms()
|
|
{
|
|
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
|
UAVObjectManager *uavObjectManager = pm->getObject<UAVObjectManager>();
|
|
|
|
Q_ASSERT(uavObjectManager);
|
|
SystemAlarms *systemAlarms = SystemAlarms::GetInstance(uavObjectManager);
|
|
Q_ASSERT(systemAlarms);
|
|
SystemAlarms::DataFields data = systemAlarms->getData();
|
|
|
|
if (data.Alarm[SystemAlarms::ALARM_ACTUATOR] != SystemAlarms::ALARM_OK) {
|
|
QMessageBox mbox(this);
|
|
mbox.setText(QString(tr("The actuator module is in an error state.\n\n"
|
|
"Please make sure the correct firmware version is used then "
|
|
"restart the wizard and try again. If the problem persists please "
|
|
"consult the openpilot.org support forum.")));
|
|
mbox.setStandardButtons(QMessageBox::Ok);
|
|
mbox.setIcon(QMessageBox::Critical);
|
|
|
|
getWizard()->setWindowFlags(getWizard()->windowFlags() & ~Qt::WindowStaysOnTopHint);
|
|
|
|
mbox.exec();
|
|
|
|
getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
|
|
getWizard()->setWindowIcon(qApp->windowIcon());
|
|
getWizard()->show();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void OutputCalibrationPage::debugLogChannelValues()
|
|
{
|
|
quint16 channel = getCurrentChannel();
|
|
|
|
qDebug() << "ChannelMin : " << m_actuatorSettings[channel].channelMin;
|
|
qDebug() << "ChannelNeutral: " << m_actuatorSettings[channel].channelNeutral;
|
|
qDebug() << "ChannelMax : " << m_actuatorSettings[channel].channelMax;
|
|
}
|
|
|
|
int OutputCalibrationPage::getHighOutputRate()
|
|
{
|
|
if (getWizard()->getEscType() == SetupWizard::ESC_ONESHOT) {
|
|
return HIGH_OUTPUT_RATE_MILLISECONDS_ONESHOT125;
|
|
} else {
|
|
return HIGH_OUTPUT_RATE_MILLISECONDS_PWM;
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::on_motorNeutralSlider_valueChanged(int value)
|
|
{
|
|
Q_UNUSED(value);
|
|
ui->motorPWMValue->setText(tr("Output value : <b>%1</b> µs").arg(value));
|
|
|
|
if (ui->motorNeutralButton->isChecked()) {
|
|
quint16 value = ui->motorNeutralSlider->value();
|
|
m_calibrationUtil->setChannelOutputValue(value);
|
|
m_actuatorSettings[getCurrentChannel()].channelNeutral = value;
|
|
debugLogChannelValues();
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::on_servoButton_toggled(bool checked)
|
|
{
|
|
ui->servoButton->setText(checked ? tr("Stop") : tr("Start"));
|
|
quint16 channel = getCurrentChannel();
|
|
quint16 safeValue = m_actuatorSettings[channel].channelNeutral;
|
|
onStartButtonToggle(ui->servoButton, channel, safeValue, safeValue, ui->servoCenterAngleSlider);
|
|
}
|
|
|
|
void OutputCalibrationPage::on_servoCenterAngleSlider_valueChanged(int position)
|
|
{
|
|
Q_UNUSED(position);
|
|
quint16 value = ui->servoCenterAngleSlider->value();
|
|
m_calibrationUtil->setChannelOutputValue(value);
|
|
quint16 channel = getCurrentChannel();
|
|
m_actuatorSettings[channel].channelNeutral = value;
|
|
ui->servoPWMValue->setText(tr("Output value : <b>%1</b> µs").arg(value));
|
|
|
|
// Adjust min and max
|
|
if (ui->reverseCheckbox->isChecked()) {
|
|
if (value >= m_actuatorSettings[channel].channelMin) {
|
|
ui->servoMinAngleSlider->setValue(value);
|
|
}
|
|
if (value <= m_actuatorSettings[channel].channelMax) {
|
|
ui->servoMaxAngleSlider->setValue(value);
|
|
}
|
|
} else {
|
|
if (value <= m_actuatorSettings[channel].channelMin) {
|
|
ui->servoMinAngleSlider->setValue(value);
|
|
}
|
|
if (value >= m_actuatorSettings[channel].channelMax) {
|
|
ui->servoMaxAngleSlider->setValue(value);
|
|
}
|
|
}
|
|
debugLogChannelValues();
|
|
}
|
|
|
|
void OutputCalibrationPage::on_servoMinAngleSlider_valueChanged(int position)
|
|
{
|
|
Q_UNUSED(position);
|
|
quint16 value = ui->servoMinAngleSlider->value();
|
|
m_calibrationUtil->setChannelOutputValue(value);
|
|
m_actuatorSettings[getCurrentChannel()].channelMin = value;
|
|
|
|
// Adjust neutral and max
|
|
if (ui->reverseCheckbox->isChecked()) {
|
|
if (value <= m_actuatorSettings[getCurrentChannel()].channelNeutral) {
|
|
ui->servoCenterAngleSlider->setValue(value);
|
|
}
|
|
if (value <= m_actuatorSettings[getCurrentChannel()].channelMax) {
|
|
ui->servoMaxAngleSlider->setValue(value);
|
|
}
|
|
} else {
|
|
if (value >= m_actuatorSettings[getCurrentChannel()].channelNeutral) {
|
|
ui->servoCenterAngleSlider->setValue(value);
|
|
}
|
|
if (value >= m_actuatorSettings[getCurrentChannel()].channelMax) {
|
|
ui->servoMaxAngleSlider->setValue(value);
|
|
}
|
|
}
|
|
debugLogChannelValues();
|
|
}
|
|
|
|
void OutputCalibrationPage::on_servoMaxAngleSlider_valueChanged(int position)
|
|
{
|
|
Q_UNUSED(position);
|
|
quint16 value = ui->servoMaxAngleSlider->value();
|
|
m_calibrationUtil->setChannelOutputValue(value);
|
|
m_actuatorSettings[getCurrentChannel()].channelMax = value;
|
|
|
|
// Adjust neutral and min
|
|
if (ui->reverseCheckbox->isChecked()) {
|
|
if (value >= m_actuatorSettings[getCurrentChannel()].channelNeutral) {
|
|
ui->servoCenterAngleSlider->setValue(value);
|
|
}
|
|
if (value >= m_actuatorSettings[getCurrentChannel()].channelMin) {
|
|
ui->servoMinAngleSlider->setValue(value);
|
|
}
|
|
} else {
|
|
if (value <= m_actuatorSettings[getCurrentChannel()].channelNeutral) {
|
|
ui->servoCenterAngleSlider->setValue(value);
|
|
}
|
|
if (value <= m_actuatorSettings[getCurrentChannel()].channelMin) {
|
|
ui->servoMinAngleSlider->setValue(value);
|
|
}
|
|
}
|
|
debugLogChannelValues();
|
|
}
|
|
|
|
void OutputCalibrationPage::on_reverseCheckbox_toggled(bool checked)
|
|
{
|
|
if (checked && m_actuatorSettings[getCurrentChannel()].channelMax > m_actuatorSettings[getCurrentChannel()].channelMin) {
|
|
quint16 oldMax = m_actuatorSettings[getCurrentChannel()].channelMax;
|
|
m_actuatorSettings[getCurrentChannel()].channelMax = m_actuatorSettings[getCurrentChannel()].channelMin;
|
|
m_actuatorSettings[getCurrentChannel()].channelMin = oldMax;
|
|
} else if (!checked && m_actuatorSettings[getCurrentChannel()].channelMax < m_actuatorSettings[getCurrentChannel()].channelMin) {
|
|
quint16 oldMax = m_actuatorSettings[getCurrentChannel()].channelMax;
|
|
m_actuatorSettings[getCurrentChannel()].channelMax = m_actuatorSettings[getCurrentChannel()].channelMin;
|
|
m_actuatorSettings[getCurrentChannel()].channelMin = oldMax;
|
|
}
|
|
ui->servoCenterAngleSlider->setInvertedAppearance(checked);
|
|
ui->servoCenterAngleSlider->setInvertedControls(checked);
|
|
ui->servoMinAngleSlider->setInvertedAppearance(checked);
|
|
ui->servoMinAngleSlider->setInvertedControls(checked);
|
|
ui->servoMaxAngleSlider->setInvertedAppearance(checked);
|
|
ui->servoMaxAngleSlider->setInvertedControls(checked);
|
|
|
|
if (ui->reverseCheckbox->isChecked()) {
|
|
ui->servoMaxAngleSlider->setValue(m_actuatorSettings[getCurrentChannel()].channelMax);
|
|
ui->servoCenterAngleSlider->setValue(m_actuatorSettings[getCurrentChannel()].channelNeutral);
|
|
ui->servoMinAngleSlider->setValue(m_actuatorSettings[getCurrentChannel()].channelMin);
|
|
} else {
|
|
ui->servoMinAngleSlider->setValue(m_actuatorSettings[getCurrentChannel()].channelMin);
|
|
ui->servoCenterAngleSlider->setValue(m_actuatorSettings[getCurrentChannel()].channelNeutral);
|
|
ui->servoMaxAngleSlider->setValue(m_actuatorSettings[getCurrentChannel()].channelMax);
|
|
}
|
|
}
|
|
|
|
void OutputCalibrationPage::resetOutputCalibrationUtil()
|
|
{
|
|
if (m_calibrationUtil) {
|
|
delete m_calibrationUtil;
|
|
m_calibrationUtil = 0;
|
|
}
|
|
m_calibrationUtil = new OutputCalibrationUtil();
|
|
}
|