1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-29 14:52:12 +01:00

Merged in f5soh/librepilot/LP-551_Tx_Wizard_output (pull request #488)

LP-551 Tx Wizard output

Approved-by: Lalanne Laurent <f5soh@free.fr>
Approved-by: Philippe Renon <philippe_renon@yahoo.fr>
This commit is contained in:
Lalanne Laurent 2018-04-29 17:29:23 +00:00 committed by Philippe Renon
commit b0e309356c
8 changed files with 549 additions and 67 deletions

View File

@ -98,6 +98,7 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent)
widget = new ConfigInputWidget(this);
static_cast<ConfigTaskWidget *>(widget)->bind();
stackWidget->insertTab(ConfigGadgetWidget::Input, widget, *icon, QString("Input"));
QWidget *inputWidget = widget;
icon = new QIcon();
icon->addFile(":/configgadget/images/output_normal.png", QSize(), QIcon::Normal, QIcon::Off);
@ -105,6 +106,7 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent)
widget = new ConfigOutputWidget(this);
static_cast<ConfigTaskWidget *>(widget)->bind();
stackWidget->insertTab(ConfigGadgetWidget::Output, widget, *icon, QString("Output"));
QWidget *outputWidget = widget;
icon = new QIcon();
icon->addFile(":/configgadget/images/ins_normal.png", QSize(), QIcon::Normal, QIcon::Off);
@ -165,6 +167,12 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent)
onOPLinkConnect();
}
// Connect output tab and input tab
// Input tab do not start calibration if Output tab is not safe
// Output tab uses the signal from Input tab and freeze all output UI while calibrating inputs
connect(outputWidget, SIGNAL(outputConfigSafeChanged(bool)), inputWidget, SLOT(setOutputConfigSafe(bool)));
connect(inputWidget, SIGNAL(inputCalibrationStateChanged(bool)), outputWidget, SLOT(setInputCalibrationState(bool)));
help = 0;
connect(stackWidget, SIGNAL(currentAboutToShow(int, bool *)), this, SLOT(tabAboutToChange(int, bool *)));
}

View File

@ -497,6 +497,16 @@ void ConfigInputWidget::enableControls(bool enable)
} else {
// Hide configAlarmStatus when disconnected
ui->configAlarmStatus->setVisible(false);
if (wizardStep != wizardNone) {
// Close input wizard
wzCancel();
}
if (ui->runCalibration->isChecked()) {
// Close manual calibration
ui->runCalibration->setChecked(false);
ui->runCalibration->setText(tr("Start Manual Calibration"));
emit inputCalibrationStateChanged(false);
}
}
}
@ -509,6 +519,12 @@ void ConfigInputWidget::resizeEvent(QResizeEvent *event)
void ConfigInputWidget::goToWizard()
{
if (!outputConfigIsSafe) {
QMessageBox::warning(this, tr("Warning"), tr("There is something wrong in <b>Output</b> tab."
"<p>Please fix the issue before starting the Transmitter wizard.</p>"), QMessageBox::Ok);
return;
}
QMessageBox msgBox;
msgBox.setText(tr("Arming Settings are now set to 'Always Disarmed' for your safety."));
@ -519,6 +535,9 @@ void ConfigInputWidget::goToWizard()
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
// Tell Output tab we freeze actuators soon
emit inputCalibrationStateChanged(true);
// Set correct tab visible before starting wizard.
if (ui->tabWidget->currentIndex() != 0) {
ui->tabWidget->setCurrentIndex(0);
@ -587,6 +606,9 @@ void ConfigInputWidget::wzCancel()
flightModeSettingsObj->setData(memento.flightModeSettingsData);
actuatorSettingsObj->setData(memento.actuatorSettingsData);
systemSettingsObj->setData(memento.systemSettingsData);
// Tell Output tab the calibration is ended
emit inputCalibrationStateChanged(false);
}
void ConfigInputWidget::registerControlActivity()
@ -682,6 +704,9 @@ void ConfigInputWidget::wzNext()
// move to Arming Settings tab
ui->stackedWidget->setCurrentIndex(0);
ui->tabWidget->setCurrentIndex(3);
// Tell Output tab the calibration is ended
emit inputCalibrationStateChanged(false);
break;
default:
Q_ASSERT(0);
@ -1872,7 +1897,7 @@ void ConfigInputWidget::updateConfigAlarmStatus()
switch (systemAlarms.ExtendedAlarmStatus[SystemAlarms::EXTENDEDALARMSTATUS_SYSTEMCONFIGURATION]) {
case SystemAlarms::EXTENDEDALARMSTATUS_FLIGHTMODE:
message = tr("Config error");
tooltipMessage = tr("There is something wrong with your config,\nusually a Thrust mode or Assisted mode not supported.\n\n"
tooltipMessage = tr("There is something wrong in the current config,\nusually a Thrust mode or Assisted mode not supported.\n\n"
"Tip: Reduce the Flight Mode Count to find the culprit.");
bgColor = "red";
}
@ -1916,6 +1941,19 @@ void ConfigInputWidget::updateCalibration()
void ConfigInputWidget::simpleCalibration(bool enable)
{
if (!isConnected()) {
return;
}
if (!outputConfigIsSafe) {
if (enable) {
QMessageBox::warning(this, tr("Warning"), tr("There is something wrong in <b>Output</b> tab."
"<p>Please fix the issue before starting the Manual Calibration.</p>"), QMessageBox::Ok);
ui->runCalibration->setChecked(false);
}
return;
}
if (enable) {
ui->configurationWizard->setEnabled(false);
ui->applyButton->setEnabled(false);
@ -1932,6 +1970,9 @@ void ConfigInputWidget::simpleCalibration(bool enable)
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
// Tell Output tab we freeze actuators soon
emit inputCalibrationStateChanged(true);
manualCommandData = manualCommandObj->getData();
manualSettingsData = manualSettingsObj->getData();
@ -1999,6 +2040,9 @@ void ConfigInputWidget::simpleCalibration(bool enable)
ui->saveButton->setEnabled(true);
ui->runCalibration->setText(tr("Start Manual Calibration"));
// Tell Output tab the calibration is ended
emit inputCalibrationStateChanged(false);
disconnect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject *)), this, SLOT(updateCalibration()));
}
}
@ -2082,7 +2126,7 @@ void ConfigInputWidget::resetActuatorSettings()
QString mixerType;
// Clear all output data : Min, max, neutral at same value
// 1000 for motors and 1500 for all others (Reversable motor included)
// min value for motors and neutral for all others (Reversable motor, servo)
for (unsigned int output = 0; output < ActuatorSettings::CHANNELMAX_NUMELEM; output++) {
QString mixerNumType = QString("Mixer%1Type").arg(output + 1);
UAVObjectField *field = mixer->getField(mixerNumType);
@ -2092,13 +2136,13 @@ void ConfigInputWidget::resetActuatorSettings()
mixerType = field->getValue().toString();
}
if ((mixerType == "Motor") || (mixerType == "Disabled")) {
actuatorSettingsData.ChannelMax[output] = 1000;
actuatorSettingsData.ChannelMin[output] = 1000;
actuatorSettingsData.ChannelNeutral[output] = 1000;
// Apply current min setting to neutral/max values
actuatorSettingsData.ChannelMax[output] = actuatorSettingsData.ChannelMin[output];
actuatorSettingsData.ChannelNeutral[output] = actuatorSettingsData.ChannelMin[output];
} else {
actuatorSettingsData.ChannelMax[output] = 1500;
actuatorSettingsData.ChannelMin[output] = 1500;
actuatorSettingsData.ChannelNeutral[output] = 1500;
// Apply current neutral setting to min/max values
actuatorSettingsData.ChannelMax[output] = actuatorSettingsData.ChannelNeutral[output];
actuatorSettingsData.ChannelMin[output] = actuatorSettingsData.ChannelNeutral[output];
}
UAVObjectUpdaterHelper updateHelper;
actuatorSettingsObj->setData(actuatorSettingsData, false);
@ -2189,3 +2233,8 @@ void ConfigInputWidget::enableControlsChanged(bool enabled)
ui->failsafeBatteryWarningFlightModeCb->setEnabled(enabled && batteryModuleEnabled);
ui->failsafeBatteryCriticalFlightModeCb->setEnabled(enabled && batteryModuleEnabled);
}
void ConfigInputWidget::setOutputConfigSafe(bool status)
{
outputConfigIsSafe = status;
}

View File

@ -72,10 +72,17 @@ public:
void enableControls(bool enable);
bool shouldObjectBeSaved(UAVObject *object);
public slots:
void setOutputConfigSafe(bool status);
signals:
void inputCalibrationStateChanged(bool newState);
private:
bool throttleError;
bool growing;
bool reverse[ManualControlSettings::CHANNELNEUTRAL_NUMELEM];
bool outputConfigIsSafe;
txMovements currentMovement;
int movePos;
void setTxMovement(txMovements movement);

View File

@ -51,8 +51,23 @@
#include <QTextEdit>
#include <QMessageBox>
#define MAXOUTPUT_VALUE 2500
#define MINOUTPUT_VALUE 500
// Motor settings
#define DSHOT_MAXOUTPUT_RANGE 2000
#define DSHOT_MINTOUTPUT_RANGE 0
#define PWMSYNC_MAXOUTPUT_RANGE 1900
#define DEFAULT_MAXOUTPUT_RANGE 2000
#define DEFAULT_MINOUTPUT_RANGE 900
#define DEFAULT_MINOUTPUT_VALUE 1000
#define REVMOTOR_NEUTRAL_TARGET_VALUE 1500
#define REVMOTOR_NEUTRAL_DIFF_VALUE 200
#define MOTOR_NEUTRAL_DIFF_VALUE 300
// Servo settings
#define SERVO_MAXOUTPUT_RANGE 2500
#define SERVO_MINOUTPUT_RANGE 500
#define SERVO_MAXOUTPUT_VALUE 2000
#define SERVO_MINOUTPUT_VALUE 1000
#define SERVO_NEUTRAL_VALUE 1500
ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(parent)
{
@ -64,7 +79,8 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren
addAutoBindings();
m_ui->gvFrame->setVisible(false);
m_ui->boardWarningFrame->setVisible(false);
m_ui->configWarningFrame->setVisible(false);
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVSettingsImportExportFactory *importexportplugin = pm->getObject<UAVSettingsImportExportFactory>();
@ -128,7 +144,10 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren
}
SystemAlarms *systemAlarmsObj = SystemAlarms::GetInstance(getObjectManager());
connect(systemAlarmsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateWarnings(UAVObject *)));
connect(systemAlarmsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateBoardWarnings(UAVObject *)));
inputCalibrationStarted = false;
channelTestsStarted = false;
// TODO why do we do that ?
disconnect(this, SLOT(refreshWidgetsValues(UAVObject *)));
@ -138,7 +157,7 @@ ConfigOutputWidget::~ConfigOutputWidget()
{
SystemAlarms *systemAlarmsObj = SystemAlarms::GetInstance(getObjectManager());
disconnect(systemAlarmsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateWarnings(UAVObject *)));
disconnect(systemAlarmsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateBoardWarnings(UAVObject *)));
foreach(OutputBankControls controls, m_banks) {
disconnect(controls.modeCombo(), SIGNAL(currentIndexChanged(int)), this, SLOT(onBankTypeChange()));
}
@ -150,6 +169,7 @@ void ConfigOutputWidget::enableControls(bool enable)
if (!enable) {
m_ui->channelOutTest->setChecked(false);
channelTestsStarted = false;
}
m_ui->channelOutTest->setEnabled(enable);
}
@ -203,6 +223,17 @@ void ConfigOutputWidget::runChannelTests(bool state)
}
}
channelTestsStarted = state;
// Emit signal to be received by Input tab
emit outputConfigSafeChanged(!state);
m_ui->spinningArmed->setEnabled(!state);
m_ui->alwaysStabilizedSwitch->setEnabled((m_ui->spinningArmed->isChecked()) && !state);
m_ui->alwayStabilizedLabel1->setEnabled((m_ui->spinningArmed->isChecked()) && !state);
m_ui->alwayStabilizedLabel2->setEnabled((m_ui->spinningArmed->isChecked()) && !state);
setBanksEnabled(!state);
ActuatorCommand *obj = ActuatorCommand::GetInstance(getObjectManager());
UAVObject::Metadata mdata = obj->getMetadata();
if (state) {
@ -390,6 +421,9 @@ void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject *obj)
}
}
// Store how many banks are active according to the board
activeBanksCount = bankLabels.count();
int i = 0;
foreach(QString banklabel, bankLabels) {
OutputBankControls controls = m_banks.at(i);
@ -399,10 +433,11 @@ void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject *obj)
if (index == -1) {
controls.rateCombo()->addItem(tr("%1 Hz").arg(actuatorSettingsData.BankUpdateFreq[i]), actuatorSettingsData.BankUpdateFreq[i]);
}
bool isPWM = (controls.modeCombo()->currentIndex() == ActuatorSettings::BANKMODE_PWM);
controls.rateCombo()->setCurrentIndex(index);
controls.rateCombo()->setEnabled(controls.modeCombo()->currentIndex() == ActuatorSettings::BANKMODE_PWM);
controls.rateCombo()->setEnabled(!inputCalibrationStarted && !channelTestsStarted && isPWM);
setColor(controls.rateCombo(), controls.color());
controls.modeCombo()->setEnabled(true);
controls.modeCombo()->setEnabled(!inputCalibrationStarted && !channelTestsStarted);
setColor(controls.modeCombo(), controls.color());
i++;
}
@ -430,6 +465,7 @@ void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject *obj)
}
updateSpinStabilizeCheckComboBoxes();
checkOutputConfig();
}
/**
@ -483,9 +519,9 @@ void ConfigOutputWidget::updateObjectsFromWidgetsImpl()
void ConfigOutputWidget::updateSpinStabilizeCheckComboBoxes()
{
m_ui->alwayStabilizedLabel1->setEnabled(m_ui->spinningArmed->isChecked());
m_ui->alwayStabilizedLabel2->setEnabled(m_ui->spinningArmed->isChecked());
m_ui->alwaysStabilizedSwitch->setEnabled(m_ui->spinningArmed->isChecked());
m_ui->alwayStabilizedLabel1->setEnabled((m_ui->spinningArmed->isChecked()) && (m_ui->spinningArmed->isEnabled()));
m_ui->alwayStabilizedLabel2->setEnabled((m_ui->spinningArmed->isChecked()) && (m_ui->spinningArmed->isEnabled()));
m_ui->alwaysStabilizedSwitch->setEnabled((m_ui->spinningArmed->isChecked()) && (m_ui->spinningArmed->isEnabled()));
if (!m_ui->spinningArmed->isChecked()) {
m_ui->alwaysStabilizedSwitch->setCurrentIndex(FlightModeSettings::ALWAYSSTABILIZEWHENARMEDSWITCH_DISABLED);
@ -506,23 +542,118 @@ void ConfigOutputWidget::updateAlwaysStabilizeStatus()
void ConfigOutputWidget::setChannelLimits(OutputChannelForm *channelForm, OutputBankControls *bankControls)
{
// Set UI limits according to the bankmode and destination
switch (bankControls->modeCombo()->currentIndex()) {
case ActuatorSettings::BANKMODE_DSHOT:
channelForm->setLimits(0, 0, 0, 2000);
// 0 - 2000 UI limits, DShot min value is fixed to zero
if (channelForm->isServoOutput()) {
// Driving a servo using DShot doest not make sense so break
break;
}
channelForm->setLimits(DSHOT_MINTOUTPUT_RANGE, DSHOT_MINTOUTPUT_RANGE, DSHOT_MINTOUTPUT_RANGE, DSHOT_MAXOUTPUT_RANGE);
channelForm->setRange(DSHOT_MINTOUTPUT_RANGE, DSHOT_MAXOUTPUT_RANGE);
channelForm->setNeutral(DSHOT_MINTOUTPUT_RANGE);
break;
// case ActuatorSettings::BANKMODE_BRUSHED:
// channelForm->setLimits(0, 0, 0, 100); // 0 to 100%
// break;
case ActuatorSettings::BANKMODE_PWMSYNC:
// 900 - 1900 UI limits
// Default values 1000 - 1900
channelForm->setLimits(DEFAULT_MINOUTPUT_RANGE, PWMSYNC_MAXOUTPUT_RANGE, DEFAULT_MINOUTPUT_RANGE, PWMSYNC_MAXOUTPUT_RANGE);
channelForm->setRange(DEFAULT_MINOUTPUT_VALUE, PWMSYNC_MAXOUTPUT_RANGE);
channelForm->setNeutral(DEFAULT_MINOUTPUT_VALUE);
if (channelForm->isServoOutput()) {
// Servo: Some of them can handle PWMSync, 500 - 1900 UI limits
// Default values 1000 - 1900 + neutral 1500
channelForm->setRange(SERVO_MINOUTPUT_VALUE, PWMSYNC_MAXOUTPUT_RANGE);
channelForm->setNeutral(SERVO_NEUTRAL_VALUE);
}
break;
case ActuatorSettings::BANKMODE_PWM:
if (channelForm->isServoOutput()) {
// Servo: 500 - 2500 UI limits
// Default values 1000 - 2000 + neutral 1500
channelForm->setLimits(SERVO_MINOUTPUT_RANGE, SERVO_MAXOUTPUT_RANGE, SERVO_MINOUTPUT_RANGE, SERVO_MAXOUTPUT_RANGE);
channelForm->setRange(SERVO_MINOUTPUT_VALUE, SERVO_MAXOUTPUT_VALUE);
channelForm->setNeutral(SERVO_NEUTRAL_VALUE);
break;
}
// PWM motor outputs fall to default
case ActuatorSettings::BANKMODE_ONESHOT125:
case ActuatorSettings::BANKMODE_ONESHOT42:
case ActuatorSettings::BANKMODE_MULTISHOT:
if (channelForm->isServoOutput()) {
// Driving a servo using this mode does not make sense so break
break;
}
default:
channelForm->setLimits(MINOUTPUT_VALUE, MAXOUTPUT_VALUE, MINOUTPUT_VALUE, MAXOUTPUT_VALUE);
// Motors 900 - 2000 UI limits
// Default values 1000 - 2000, neutral set to min
// This settings are used for PWM, OneShot125, OneShot42 and MultiShot
channelForm->setLimits(DEFAULT_MINOUTPUT_RANGE, DEFAULT_MAXOUTPUT_RANGE, DEFAULT_MINOUTPUT_RANGE, DEFAULT_MAXOUTPUT_RANGE);
channelForm->setRange(DEFAULT_MINOUTPUT_VALUE, DEFAULT_MAXOUTPUT_RANGE);
channelForm->setNeutral(DEFAULT_MINOUTPUT_VALUE);
break;
}
}
ConfigOutputWidget::ChannelConfigWarning ConfigOutputWidget::checkChannelConfig(OutputChannelForm *channelForm, OutputBankControls *bankControls)
{
ChannelConfigWarning warning = None;
int currentNeutralValue = channelForm->neutralValue();
// Check if RevMotor has neutral value around center
if (channelForm->isReversibleMotorOutput()) {
warning = IsReversibleMotorCheckNeutral;
int neutralDiff = qAbs(REVMOTOR_NEUTRAL_TARGET_VALUE - currentNeutralValue);
if (neutralDiff < REVMOTOR_NEUTRAL_DIFF_VALUE) {
// Reset warning
warning = None;
}
}
// Check if NormalMotor neutral is not too high
if (channelForm->isNormalMotorOutput()) {
warning = IsNormalMotorCheckNeutral;
int neutralDiff = currentNeutralValue - DEFAULT_MINOUTPUT_VALUE;
if (neutralDiff < MOTOR_NEUTRAL_DIFF_VALUE) {
// Reset warning
warning = None;
}
}
switch (bankControls->modeCombo()->currentIndex()) {
case ActuatorSettings::BANKMODE_DSHOT:
if (channelForm->isServoOutput()) {
// Driving a servo using DShot doest not make sense
warning = CannotDriveServo;
} else if (channelForm->isReversibleMotorOutput()) {
// Bi-directional DShot not yet supported
warning = BiDirectionalDShotNotSupported;
}
break;
case ActuatorSettings::BANKMODE_PWMSYNC:
case ActuatorSettings::BANKMODE_PWM:
break;
case ActuatorSettings::BANKMODE_ONESHOT125:
case ActuatorSettings::BANKMODE_ONESHOT42:
case ActuatorSettings::BANKMODE_MULTISHOT:
if (channelForm->isServoOutput()) {
warning = CannotDriveServo;
// Driving a servo using this mode does not make sense so break
}
default:
break;
}
return warning;
}
void ConfigOutputWidget::onBankTypeChange()
{
QComboBox *bankModeCombo = qobject_cast<QComboBox *>(sender());
ChannelConfigWarning new_warning = None;
if (bankModeCombo != NULL) {
int bankNumber = 1;
QList<OutputChannelForm *> outputChannelForms = findChildren<OutputChannelForm *>();
@ -534,6 +665,10 @@ void ConfigOutputWidget::onBankTypeChange()
foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
if (outputChannelForm->bank().toInt() == bankNumber) {
setChannelLimits(outputChannelForm, &controls);
ChannelConfigWarning warning = checkChannelConfig(outputChannelForm, &controls);
if (warning > None) {
new_warning = warning;
}
}
}
break;
@ -542,14 +677,46 @@ void ConfigOutputWidget::onBankTypeChange()
bankNumber++;
}
}
updateChannelConfigWarning(new_warning);
}
bool ConfigOutputWidget::checkOutputConfig()
{
ChannelConfigWarning new_warning = None;
int bankNumber = 1;
QList<OutputChannelForm *> outputChannelForms = findChildren<OutputChannelForm *>();
foreach(OutputBankControls controls, m_banks) {
foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
if (!outputChannelForm->isDisabledOutput() && (outputChannelForm->bank().toInt() == bankNumber)) {
ChannelConfigWarning warning = checkChannelConfig(outputChannelForm, &controls);
if (warning > None) {
new_warning = warning;
}
}
}
bankNumber++;
}
updateChannelConfigWarning(new_warning);
// Emit signal to be received by Input tab
emit outputConfigSafeChanged(new_warning == None);
return new_warning == None;
}
void ConfigOutputWidget::stopTests()
{
m_ui->channelOutTest->setChecked(false);
channelTestsStarted = false;
}
void ConfigOutputWidget::updateWarnings(UAVObject *)
void ConfigOutputWidget::updateBoardWarnings(UAVObject *)
{
SystemAlarms *systemAlarmsObj = SystemAlarms::GetInstance(getObjectManager());
SystemAlarms::DataFields systemAlarms = systemAlarmsObj->getData();
@ -557,23 +724,96 @@ void ConfigOutputWidget::updateWarnings(UAVObject *)
if (systemAlarms.Alarm[SystemAlarms::ALARM_SYSTEMCONFIGURATION] > SystemAlarms::ALARM_WARNING) {
switch (systemAlarms.ExtendedAlarmStatus[SystemAlarms::EXTENDEDALARMSTATUS_SYSTEMCONFIGURATION]) {
case SystemAlarms::EXTENDEDALARMSTATUS_UNSUPPORTEDCONFIG_ONESHOT:
setWarning(tr("OneShot and PWMSync output only works with Receiver Port settings marked with '+OneShot'<br>"
"When using Receiver Port setting 'PPM_PIN8+OneShot' "
"<b><font color='%1'>Bank %2</font></b> must be set to PWM")
.arg(m_banks.at(3).color().name()).arg(m_banks.at(3).label()->text()));
setBoardWarning(tr("OneShot and PWMSync output only works with Receiver Port settings marked with '+OneShot'<br>"
"When using Receiver Port setting 'PPM_PIN8+OneShot' "
"<b><font color='%1'>Bank %2</font></b> must be set to PWM")
.arg(m_banks.at(3).color().name()).arg(m_banks.at(3).label()->text()));
return;
}
}
setWarning(NULL);
setBoardWarning(NULL);
}
void ConfigOutputWidget::setWarning(QString message)
void ConfigOutputWidget::updateChannelConfigWarning(ChannelConfigWarning warning)
{
m_ui->gvFrame->setVisible(!message.isNull());
m_ui->picWarning->setPixmap(message.isNull() ? QPixmap() : QPixmap(":/configgadget/images/error.svg"));
m_ui->txtWarning->setText(message);
QString warning_str;
if (warning == BiDirectionalDShotNotSupported) {
// TODO: Implement bi-directional DShot
warning_str = "There is <b>one reversible motor</b> using DShot is configured.<br>"
"Bi-directional DShot is currently not supported. Please use PWM, OneShotXXX or MultiShot.";
}
if (warning == IsNormalMotorCheckNeutral) {
warning_str = "There is at least one pretty <b>high neutral value</b> set in your configuration.<br>"
"Make sure all ESCs are calibrated and no mechanical stress in all motors.";
}
if (warning == IsReversibleMotorCheckNeutral) {
warning_str = "A least one <b>reversible motor</b> is configured.<br>"
"Make sure a appropriate neutral value is set before saving and applying power to the vehicule.";
}
if (warning == CannotDriveServo) {
warning_str = "One bank cannot drive a <b>servo output</b>!<br>"
"You must use PWM for this bank or move the servo output to another compatible bank.";
}
setConfigWarning(warning_str);
}
void ConfigOutputWidget::setBanksEnabled(bool state)
{
// Disable/Enable banks
for (int i = 0; i < m_banks.count(); i++) {
OutputBankControls controls = m_banks.at(i);
if (i < activeBanksCount) {
controls.modeCombo()->setEnabled(state);
controls.rateCombo()->setEnabled(state);
} else {
controls.modeCombo()->setEnabled(false);
controls.rateCombo()->setEnabled(false);
}
}
}
void ConfigOutputWidget::setBoardWarning(QString message)
{
m_ui->boardWarningFrame->setVisible(!message.isNull());
m_ui->boardWarningPic->setPixmap(message.isNull() ? QPixmap() : QPixmap(":/configgadget/images/error.svg"));
m_ui->boardWarningTxt->setText(message);
}
void ConfigOutputWidget::setConfigWarning(QString message)
{
m_ui->configWarningFrame->setVisible(!message.isNull());
m_ui->configWarningPic->setPixmap(message.isNull() ? QPixmap() : QPixmap(":/configgadget/images/error.svg"));
m_ui->configWarningTxt->setText(message);
}
void ConfigOutputWidget::setInputCalibrationState(bool started)
{
inputCalibrationStarted = started;
// Disable UI when a input calibration is started
// so user cannot manipulate settings.
enableControls(!started);
setBanksEnabled(!started);
// Disable ASWA
m_ui->spinningArmed->setEnabled(!started);
m_ui->alwaysStabilizedSwitch->setEnabled((m_ui->spinningArmed->isChecked()) && !started);
m_ui->alwayStabilizedLabel1->setEnabled((m_ui->spinningArmed->isChecked()) && !started);
m_ui->alwayStabilizedLabel2->setEnabled((m_ui->spinningArmed->isChecked()) && !started);
// Disable every channel form when needed
for (unsigned int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) {
OutputChannelForm *form = getOutputChannelForm(i);
form->ui->actuatorRev->setChecked(false);
form->ui->actuatorLink->setChecked(false);
form->setChannelRangeEnabled(!started);
form->setControlsEnabled(!started);
}
}
OutputBankControls::OutputBankControls(MixerSettings *mixer, QLabel *label, QColor color, QComboBox *rateCombo, QComboBox *modeCombo) :
m_mixer(mixer), m_label(label), m_color(color), m_rateCombo(rateCombo), m_modeCombo(modeCombo)

View File

@ -85,9 +85,16 @@ public:
ConfigOutputWidget(QWidget *parent = 0);
~ConfigOutputWidget();
public slots:
void setInputCalibrationState(bool state);
signals:
void outputConfigSafeChanged(bool newStatus);
protected:
void enableControls(bool enable);
void setWarning(QString message);
void setBoardWarning(QString message);
void setConfigWarning(QString message);
virtual void refreshWidgetsValuesImpl(UAVObject *obj);
virtual void updateObjectsFromWidgetsImpl();
@ -98,16 +105,25 @@ private:
int m_mccDataRate;
UAVObject::Metadata m_accInitialData;
QList<OutputBankControls> m_banks;
int activeBanksCount;
void setBanksEnabled(bool state);
bool inputCalibrationStarted;
bool channelTestsStarted;
OutputChannelForm *getOutputChannelForm(const int index) const;
void updateChannelInSlider(QSlider *slider, QLabel *min, QLabel *max, QCheckBox *rev, int value);
void assignOutputChannel(UAVDataObject *obj, QString &str);
void setColor(QWidget *widget, const QColor color);
void sendAllChannelTests();
enum ChannelConfigWarning { None, CannotDriveServo, IsNormalMotorCheckNeutral, IsReversibleMotorCheckNeutral, BiDirectionalDShotNotSupported };
void setChannelLimits(OutputChannelForm *channelForm, OutputBankControls *bankControls);
ChannelConfigWarning checkChannelConfig(OutputChannelForm *channelForm, OutputBankControls *bankControls);
bool checkOutputConfig();
void updateChannelConfigWarning(ChannelConfigWarning warning);
private slots:
void updateWarnings(UAVObject *);
void updateBoardWarnings(UAVObject *);
void updateSpinStabilizeCheckComboBoxes();
void updateAlwaysStabilizeStatus();
void stopTests();

View File

@ -123,7 +123,7 @@
<x>0</x>
<y>0</y>
<width>743</width>
<height>668</height>
<height>666</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,0">
@ -147,7 +147,7 @@
<property name="title">
<string>Output Configuration</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0">
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0,0">
<property name="leftMargin">
<number>9</number>
</property>
@ -698,7 +698,7 @@
</widget>
</item>
<item>
<widget class="QFrame" name="gvFrame">
<widget class="QFrame" name="boardWarningFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -741,14 +741,14 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="picWarning">
<widget class="QLabel" name="boardWarningPic">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="txtWarning">
<widget class="QLabel" name="boardWarningTxt">
<property name="text">
<string/>
</property>
@ -770,6 +770,79 @@
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="configWarningFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>70</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="configWarningPic">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="configWarningTxt">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -28,9 +28,10 @@
#include "outputchannelform.h"
#include "ui_outputchannelform.h"
#include <QDebug>
OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) :
ChannelForm(index, parent), ui(new Ui::outputChannelForm), m_inChannelTest(false)
ChannelForm(index, parent), ui(new Ui::outputChannelForm), m_inChannelTest(false), m_updateChannelRangeEnabled(true)
{
ui->setupUi(this);
@ -110,15 +111,26 @@ void OutputChannelForm::enableChannelTest(bool state)
ui->actuatorMin->setEnabled(false);
ui->actuatorMax->setEnabled(false);
ui->actuatorRev->setEnabled(false);
} else if (m_mixerType != "Disabled") {
} else if (!isDisabledOutput()) {
ui->actuatorMin->setEnabled(true);
ui->actuatorMax->setEnabled(true);
if (m_mixerType != "Motor") {
if (!isNormalMotorOutput()) {
ui->actuatorRev->setEnabled(true);
}
}
}
/**
* Enable/Disable setChannelRange
*/
void OutputChannelForm::setChannelRangeEnabled(bool state)
{
if (m_updateChannelRangeEnabled == state) {
return;
}
m_updateChannelRangeEnabled = state;
}
/**
* Toggles the channel linked state for use in testing mode
*/
@ -212,6 +224,9 @@ void OutputChannelForm::setLimits(int actuatorMinMinimum, int actuatorMinMaximum
ui->actuatorMax->setMaximum(actuatorMaxMaximum);
ui->actuatorMin->setMinimum(actuatorMinMinimum);
ui->actuatorMax->setMinimum(actuatorMaxMinimum);
// Neutral slider limits
ui->actuatorNeutral->setMinimum(actuatorMinMinimum);
ui->actuatorNeutral->setMaximum(actuatorMaxMaximum);
}
/**
@ -233,16 +248,32 @@ void OutputChannelForm::setRange(int minimum, int maximum)
*/
void OutputChannelForm::setChannelRange()
{
// Disable outputs not already set in MixerSettings
if (isDisabledOutput()) {
setLimits(1000, 1000, 1000, 1000);
ui->actuatorMin->setValue(1000);
ui->actuatorMax->setValue(1000);
ui->actuatorRev->setChecked(false);
ui->actuatorLink->setChecked(false);
setControlsEnabled(false);
return;
}
if (!m_updateChannelRangeEnabled) {
// Nothing to do here
return;
}
setControlsEnabled(true);
int minValue = ui->actuatorMin->value();
int maxValue = ui->actuatorMax->value();
int oldMini = ui->actuatorNeutral->minimum();
int oldMaxi = ui->actuatorNeutral->maximum();
m_mixerType = outputMixerType();
// Red handle for Motors
if ((m_mixerType == "Motor") || (m_mixerType == "ReversableMotor")) {
if (isNormalMotorOutput() || isReversibleMotorOutput()) {
ui->actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(255, 100, 100); width: 18px; height: 28px;"
"margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
} else {
@ -251,8 +282,8 @@ void OutputChannelForm::setChannelRange()
}
// Normal motor will be *** never *** reversed : without arming a "Min" value (like 1900) can be applied !
if (m_mixerType == "Motor") {
if (minValue >= maxValue) {
if (isNormalMotorOutput()) {
if (minValue > maxValue) {
// Keep old values
ui->actuatorMin->setValue(oldMini);
ui->actuatorMax->setValue(oldMaxi);
@ -279,25 +310,6 @@ void OutputChannelForm::setChannelRange()
if (ui->actuatorNeutral->value() == oldMini) {
ui->actuatorNeutral->setValue(ui->actuatorNeutral->minimum());
}
// Enable only outputs already set in mixer
if (m_mixerType != "Disabled") {
ui->actuatorMin->setEnabled(true);
ui->actuatorMax->setEnabled(true);
ui->actuatorNeutral->setEnabled(true);
ui->actuatorValue->setEnabled(true);
ui->actuatorLink->setEnabled(true);
} else {
ui->actuatorMin->setEnabled(false);
ui->actuatorMax->setEnabled(false);
ui->actuatorRev->setEnabled(false);
ui->actuatorLink->setEnabled(false);
ui->actuatorMin->setValue(1000);
ui->actuatorMax->setValue(1000);
ui->actuatorNeutral->setRange(minValue, maxValue);
ui->actuatorNeutral->setValue(minValue);
ui->actuatorValue->setEnabled(false);
}
}
/**
@ -319,6 +331,28 @@ void OutputChannelForm::reverseChannel(bool state)
}
}
/**
* Enable/Disable UI controls
*/
void OutputChannelForm::setControlsEnabled(bool state)
{
if (isDisabledOutput()) {
state = false;
}
ui->actuatorMin->setEnabled(state);
ui->actuatorMax->setEnabled(state);
ui->actuatorValue->setEnabled(state);
ui->actuatorLink->setEnabled(state);
// Reverse checkbox will be never checked
// or enabled for normal motor
if (isNormalMotorOutput()) {
ui->actuatorRev->setChecked(false);
ui->actuatorRev->setEnabled(false);
} else {
ui->actuatorRev->setEnabled(state);
}
}
/**
* Emits the channel value which will be send to the UAV to move the servo.
* Returns immediately if we are not in testing mode.
@ -372,6 +406,15 @@ void OutputChannelForm::sendChannelTest(int value)
emit channelChanged(index(), value);
}
/**
*
* Returns current neutral value
*/
int OutputChannelForm::neutralValue()
{
return ui->actuatorNeutral->value();
}
/**
*
* Returns MixerType
@ -389,3 +432,39 @@ QString OutputChannelForm::outputMixerType()
return mixerType;
}
/**
*
* Returns true if a servo output
*/
bool OutputChannelForm::isServoOutput()
{
return !isNormalMotorOutput() && !isReversibleMotorOutput() && !isDisabledOutput();
}
/**
*
* Returns true if output is a normal Motor
*/
bool OutputChannelForm::isNormalMotorOutput()
{
return outputMixerType() == "Motor";
}
/**
*
* Returns true if output is a reversible Motor
*/
bool OutputChannelForm::isReversibleMotorOutput()
{
return outputMixerType() == "ReversableMotor";
}
/**
*
* Returns true if output is disabled
*/
bool OutputChannelForm::isDisabledOutput()
{
return outputMixerType() == "Disabled";
}

View File

@ -61,8 +61,17 @@ public slots:
void setNeutral(int value);
void setRange(int minimum, int maximum);
void enableChannelTest(bool state);
void setChannelRangeEnabled(bool state);
void setControlsEnabled(bool state);
QString outputMixerType();
void setLimits(int actuatorMinMinimum, int actuatorMinMaximum, int actuatorMaxMinimum, int actuatorMaxMaximum);
int neutralValue();
// output type helper methods
bool isServoOutput();
bool isNormalMotorOutput();
bool isReversibleMotorOutput();
bool isDisabledOutput();
signals:
void channelChanged(int index, int value);
@ -70,6 +79,7 @@ signals:
private:
Ui::outputChannelForm *ui;
bool m_inChannelTest;
bool m_updateChannelRangeEnabled;
QString m_mixerType;
private slots: