1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

Merge branch 'input_configuration' into next

This commit is contained in:
James Cotton 2011-09-11 18:52:35 -05:00
commit 6457276438
18 changed files with 1136 additions and 377 deletions

View File

@ -1028,6 +1028,13 @@ void PIOS_Board_Init(void) {
if (PIOS_SBUS_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) {
PIOS_Assert(0);
}
uint32_t pios_sbus_rcvr_id;
if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) {
PIOS_Assert(0);
}
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id;
}
#endif /* PIOS_INCLUDE_SBUS */
break;

View File

@ -42,7 +42,7 @@
#include "mixersettings.h"
#include "mixerstatus.h"
#include "cameradesired.h"
#include "manualcontrolcommand.h"
// Private constants
#define MAX_QUEUE_SIZE 2
@ -238,6 +238,10 @@ static void actuatorTask(void* parameters)
case MIXERSETTINGS_CURVE2SOURCE_YAW:
curve2 = MixerCurve(desired.Yaw,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
break;
case MIXERSETTINGS_CURVE2SOURCE_COLLECTIVE:
ManualControlCommandCollectiveGet(&curve2);
curve2 = MixerCurve(curve2,mixerSettings.ThrottleCurve2);
break;
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY2:

View File

@ -105,4 +105,11 @@ int32_t ManualControlInitialize();
( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_POSITIONHOLD == (int) FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD) \
)
#define assumptions_channelcount ( \
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM ) && \
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELNUMBER_NUMELEM ) && \
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELMIN_NUMELEM ) && \
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELMAX_NUMELEM ) && \
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELNEUTRAL_NUMELEM ) )
#endif // MANUALCONTROL_H

View File

@ -101,7 +101,7 @@ static struct rcvr_activity_fsm activity_fsm;
static void resetRcvrActivity(struct rcvr_activity_fsm * fsm);
static bool updateRcvrActivity(struct rcvr_activity_fsm * fsm);
#define assumptions (assumptions1 && assumptions3 && assumptions5 && assumptions7 && assumptions8 && assumptions_flightmode)
#define assumptions (assumptions1 && assumptions3 && assumptions5 && assumptions7 && assumptions8 && assumptions_flightmode && assumptions_channelcount)
/**
* Module starting
@ -278,6 +278,7 @@ static void manualControlTask(void *parameters)
cmd.Roll = 0;
cmd.Yaw = 0;
cmd.Pitch = 0;
cmd.Collective = 0;
//cmd.FlightMode = MANUALCONTROLCOMMAND_FLIGHTMODE_AUTO; // don't do until AUTO implemented and functioning
// Important: Throttle < 0 will reset Stabilization coefficients among other things. Either change this,
// or leave throttle at IDLE speed or above when going into AUTO-failsafe.
@ -316,6 +317,11 @@ static void manualControlTask(void *parameters)
cmd.Throttle = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE];
flightMode = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE];
if(cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE] != PIOS_RCVR_INVALID &&
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE] != PIOS_RCVR_NODRIVER &&
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE] != PIOS_RCVR_TIMEOUT)
cmd.Collective = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE];
AccessoryDesiredData accessory;
// Set Accessory 0
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY0] !=
@ -398,8 +404,9 @@ static void resetRcvrActivity(struct rcvr_activity_fsm * fsm)
}
static void updateRcvrActivitySample(uint32_t rcvr_id, uint16_t samples[], uint8_t max_channels) {
for (uint8_t channel = 0; channel < max_channels; channel++) {
samples[channel] = PIOS_RCVR_Read(rcvr_id, channel);
for (uint8_t channel = 1; channel <= max_channels; channel++) {
// Subtract 1 because channels are 1 indexed
samples[channel - 1] = PIOS_RCVR_Read(rcvr_id, channel);
}
}
@ -408,12 +415,12 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm
bool activity_updated = false;
/* Compare the current value to the previous sampled value */
for (uint8_t channel = 0;
channel < RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP;
for (uint8_t channel = 1;
channel <= RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP;
channel++) {
uint16_t delta;
uint16_t prev = fsm->prev[channel];
uint16_t curr = PIOS_RCVR_Read(rcvr_id, channel);
uint16_t prev = fsm->prev[channel - 1]; // Subtract 1 because channels are 1 indexed
uint16_t curr = PIOS_RCVR_Read(rcvr_id, channel);
if (curr > prev) {
delta = curr - prev;
} else {

View File

@ -87,6 +87,12 @@ out_fail:
*/
int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel)
{
// Publicly facing API uses channel 1 for first channel
if(channel == 0)
return PIOS_RCVR_INVALID;
else
channel--;
if (rcvr_id == 0)
return PIOS_RCVR_NODRIVER;

View File

@ -34,8 +34,6 @@
#if defined(PIOS_INCLUDE_SBUS)
/* Global Variables */
/* Provide a RCVR driver */
static int32_t PIOS_SBUS_Get(uint32_t rcvr_id, uint8_t channel);
@ -65,21 +63,17 @@ static void reset_channels(void)
/**
* unroll_channels() function computes channel_data[] from received_data[]
* For efficiency it unrolls first 8 channels without loops. If other
* 8 channels are needed they can be unrolled using the same code
* starting from s[11] instead of s[0]. Two extra digital channels are
* accessible using (s[22] & SBUS_FLAG_DGx) logical expressions.
* For efficiency it unrolls first 8 channels without loops and does the
* same for other 8 channels. Also 2 discrete channels will be set.
*/
static void unroll_channels(void)
{
uint8_t *s = received_data;
uint16_t *d = channel_data;
#if (SBUS_NUMBER_OF_CHANNELS != 8)
#error Current S.Bus code unrolls only first 8 channels
#endif
#define F(v,s) ((v) >> s) & 0x7ff
/* unroll channels 1-8 */
*d++ = F(s[0] | s[1] << 8, 0);
*d++ = F(s[1] | s[2] << 8, 3);
*d++ = F(s[2] | s[3] << 8 | s[4] << 16, 6);
@ -88,6 +82,20 @@ static void unroll_channels(void)
*d++ = F(s[6] | s[7] << 8 | s[8] << 16, 7);
*d++ = F(s[8] | s[9] << 8, 2);
*d++ = F(s[9] | s[10] << 8, 5);
/* unroll channels 9-16 */
*d++ = F(s[11] | s[12] << 8, 0);
*d++ = F(s[12] | s[13] << 8, 3);
*d++ = F(s[13] | s[14] << 8 | s[15] << 16, 6);
*d++ = F(s[15] | s[16] << 8, 1);
*d++ = F(s[16] | s[17] << 8, 4);
*d++ = F(s[17] | s[18] << 8 | s[19] << 16, 7);
*d++ = F(s[19] | s[20] << 8, 2);
*d++ = F(s[20] | s[21] << 8, 5);
/* unroll discrete channels 17 and 18 */
*d++ = (s[22] & SBUS_FLAG_DC1) ? SBUS_VALUE_MAX : SBUS_VALUE_MIN;
*d++ = (s[22] & SBUS_FLAG_DC2) ? SBUS_VALUE_MAX : SBUS_VALUE_MIN;
}
/**

View File

@ -44,8 +44,8 @@
* 1 byte - 0x0f (start of frame byte)
* 22 bytes - channel data (11 bit/channel, 16 channels, LSB first)
* 1 byte - bit flags:
* 0x01 - digital channel 1,
* 0x02 - digital channel 2,
* 0x01 - discrete channel 1,
* 0x02 - discrete channel 2,
* 0x04 - lost frame flag,
* 0x08 - failsafe flag,
* 0xf0 - reserved
@ -54,16 +54,20 @@
#define SBUS_FRAME_LENGTH (1+22+1+1)
#define SBUS_SOF_BYTE 0x0f
#define SBUS_EOF_BYTE 0x00
#define SBUS_FLAG_DG1 0x01
#define SBUS_FLAG_DG2 0x02
#define SBUS_FLAG_DC1 0x01
#define SBUS_FLAG_DC2 0x02
#define SBUS_FLAG_FL 0x04
#define SBUS_FLAG_FS 0x08
/*
* S.Bus protocol provides up to 16 analog and 2 digital channels.
* Only 8 channels are currently supported by the OpenPilot.
* S.Bus protocol provides 16 proportional and 2 discrete channels.
* Do not change unless driver code is updated accordingly.
*/
#define SBUS_NUMBER_OF_CHANNELS 8
#define SBUS_NUMBER_OF_CHANNELS (16 + 2)
/* Discrete channels represented as bits, provide values for them */
#define SBUS_VALUE_MIN 352
#define SBUS_VALUE_MAX 1696
/*
* S.Bus configuration programmable invertor

View File

@ -169,6 +169,7 @@ void ConfigGadgetWidget::onAutopilotConnect() {
void ConfigGadgetWidget::tabAboutToChange(int i,bool * proceed)
{
Q_UNUSED(i);
*proceed=true;
ConfigTaskWidget * wid=qobject_cast<ConfigTaskWidget *>(ftw->currentWidget());
if(!wid)

View File

@ -46,7 +46,7 @@
#define STICK_MIN_MOVE -8
#define STICK_MAX_MOVE 8
ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent),wizardStep(wizardWelcome),loop(NULL),skipflag(false),goWizard(NULL)
ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent),wizardStep(wizardNone),loop(NULL),skipflag(false),transmitterType(heli)
{
manualCommandObj = ManualControlCommand::GetInstance(getObjectManager());
manualSettingsObj = ManualControlSettings::GetInstance(getObjectManager());
@ -56,11 +56,12 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent)
setupButtons(m_config->saveRCInputToRAM,m_config->saveRCInputToSD);
int index=0;
unsigned int index=0;
foreach(QString name,manualSettingsObj->getFields().at(0)->getElementNames())
{
Q_ASSERT(index < ManualControlSettings::CHANNELGROUPS_NUMELEM);
inputChannelForm * inp=new inputChannelForm(this,index==0);
m_config->advancedPage->layout()->addWidget(inp);
m_config->channelSettings->layout()->addWidget(inp);
inp->ui->channelName->setText(name);
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelGroups",inp->ui->channelGroup,index);
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNumber",inp->ui->channelNumber,index);
@ -69,12 +70,9 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent)
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMax",inp->ui->channelMax,index);
++index;
}
goWizard=new QPushButton(tr("Start Wizard"),this);
m_config->advancedPage->layout()->addWidget(goWizard);
connect(goWizard,SIGNAL(clicked()),this,SLOT(goToNormalWizard()));
goSimpleWizard=new QPushButton(tr("Start Simple Wizard"),this);
m_config->advancedPage->layout()->addWidget(goSimpleWizard);
connect(goSimpleWizard,SIGNAL(clicked()),this,SLOT(goToSimpleWizard()));
connect(m_config->configurationWizard,SIGNAL(clicked()),this,SLOT(goToWizard()));
connect(m_config->runCalibration,SIGNAL(toggled(bool)),this, SLOT(simpleCalibration(bool)));
connect(m_config->wzNext,SIGNAL(clicked()),this,SLOT(wzNext()));
connect(m_config->wzCancel,SIGNAL(clicked()),this,SLOT(wzCancel()));
@ -98,8 +96,6 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent)
addUAVObjectToWidgetRelation("ManualControlSettings","Arming",m_config->armControl);
addUAVObjectToWidgetRelation("ManualControlSettings","ArmedTimeout",m_config->armTimeout,0,1000);
connect( ManualControlCommand::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(moveFMSlider()));
addWidget(goWizard);
addWidget(goSimpleWizard);
enableControls(false);
populateWidgets();
@ -227,6 +223,25 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent)
m_config->graphicsView->fitInView(m_txMainBody, Qt::KeepAspectRatio );
animate=new QTimer(this);
connect(animate,SIGNAL(timeout()),this,SLOT(moveTxControls()));
heliChannelOrder << ManualControlSettings::CHANNELGROUPS_COLLECTIVE <<
ManualControlSettings::CHANNELGROUPS_THROTTLE <<
ManualControlSettings::CHANNELGROUPS_ROLL <<
ManualControlSettings::CHANNELGROUPS_PITCH <<
ManualControlSettings::CHANNELGROUPS_YAW <<
ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
ManualControlSettings::CHANNELGROUPS_ACCESSORY0 <<
ManualControlSettings::CHANNELGROUPS_ACCESSORY1 <<
ManualControlSettings::CHANNELGROUPS_ACCESSORY2;
acroChannelOrder << ManualControlSettings::CHANNELGROUPS_THROTTLE <<
ManualControlSettings::CHANNELGROUPS_ROLL <<
ManualControlSettings::CHANNELGROUPS_PITCH <<
ManualControlSettings::CHANNELGROUPS_YAW <<
ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
ManualControlSettings::CHANNELGROUPS_ACCESSORY0 <<
ManualControlSettings::CHANNELGROUPS_ACCESSORY1 <<
ManualControlSettings::CHANNELGROUPS_ACCESSORY2;
}
void ConfigInputWidget::resetTxControls()
{
@ -257,16 +272,6 @@ void ConfigInputWidget::openHelp()
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Input+Configuration", QUrl::StrictMode) );
}
void ConfigInputWidget::goToSimpleWizard()
{
isSimple=true;
goToWizard();
}
void ConfigInputWidget::goToNormalWizard()
{
isSimple=false;
goToWizard();
}
void ConfigInputWidget::goToWizard()
{
QMessageBox msgBox;
@ -275,7 +280,7 @@ void ConfigInputWidget::goToWizard()
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
setupWizardWidget(wizardWelcome);
wizardSetUpStep(wizardWelcome);
m_config->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio );
}
@ -284,228 +289,51 @@ void ConfigInputWidget::wzCancel()
dimOtherControls(false);
manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
m_config->stackedWidget->setCurrentIndex(0);
foreach (QWidget * wd, extraWidgets)
{
if(wd)
delete wd;
}
extraWidgets.clear();
switch(wizardStep)
{
case wizardWelcome:
break;
case wizardChooseMode:
break;
case wizardIdentifySticks:
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
break;
case wizardIdentifyCenter:
break;
case wizardIdentifyLimits:
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
manualSettingsObj->setData(manualSettingsData);
break;
case wizardIdentifyInverted:
break;
case wizardFinish:
break;
default:
break;
}
wizardStep=wizardWelcome;
if(wizardStep != wizardNone)
wizardTearDownStep(wizardStep);
wizardStep=wizardNone;
// Load settings back from beginning of wizard
manualSettingsObj->setData(previousManualSettingsData);
}
void ConfigInputWidget::wzNext()
{
setupWizardWidget(wizardStep+1);
}
// In identify sticks mode the next button can indicate
// channel advance
if(wizardStep != wizardNone &&
wizardStep != wizardIdentifySticks)
wizardTearDownStep(wizardStep);
void ConfigInputWidget::wzBack()
{
setupWizardWidget(wizardStep-1);
}
void ConfigInputWidget::setupWizardWidget(int step)
{
if(step==wizardWelcome)
{
m_config->graphicsView->setVisible(false);
setTxMovement(nothing);
if(wizardStep==wizardChooseMode)
{
delete extraWidgets.at(0);
delete extraWidgets.at(1);
extraWidgets.clear();
// State transitions for next button
switch(wizardStep) {
case wizardWelcome:
wizardSetUpStep(wizardChooseMode);
break;
case wizardChooseMode:
wizardSetUpStep(wizardChooseType);
break;
case wizardChooseType:
wizardSetUpStep(wizardIdentifySticks);
break;
case wizardIdentifySticks:
nextChannel();
if(currentChannelNum==-1) { // Gone through all channels
wizardTearDownStep(wizardIdentifySticks);
wizardSetUpStep(wizardIdentifyCenter);
}
manualSettingsData=manualSettingsObj->getData();
manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED;
manualSettingsObj->setData(manualSettingsData);
m_config->wzText->setText(tr("Welcome to the inputs configuration wizard.\n"
"Please follow the instructions on the screen and only move your controls when asked to.\n"
"Make sure you already configured your hardware settings on the proper tab and restarted your board.\n"
"At any time you can press 'back' to return to the previous screeen or 'Cancel' to cancel the wizard.\n"));
m_config->stackedWidget->setCurrentIndex(1);
m_config->wzBack->setEnabled(false);
wizardStep=wizardWelcome;
}
else if(step==wizardChooseMode)
{
m_config->graphicsView->setVisible(true);
setTxMovement(nothing);
if(wizardStep==wizardIdentifySticks)
{
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
m_config->wzNext->setEnabled(true);
}
m_config->wzText->setText(tr("Please choose your transmiter type.\n"
"Mode 1 means your throttle stick is on the right\n"
"Mode 2 means your throttle stick is on the left\n"));
m_config->wzBack->setEnabled(true);
QRadioButton * mode1=new QRadioButton(tr("Mode 1"),this);
QRadioButton * mode2=new QRadioButton(tr("Mode 2"),this);
mode2->setChecked(true);
extraWidgets.clear();
extraWidgets.append(mode1);
extraWidgets.append(mode2);
m_config->checkBoxesLayout->layout()->addWidget(mode1);
m_config->checkBoxesLayout->layout()->addWidget(mode2);
wizardStep=wizardChooseMode;
}
else if(step==wizardIdentifySticks && !isSimple)
{
usedChannels.clear();
if(wizardStep==wizardChooseMode)
{
QRadioButton * mode=qobject_cast<QRadioButton *>(extraWidgets.at(0));
if(mode->isChecked())
transmitterMode=mode1;
else
transmitterMode=mode2;
delete extraWidgets.at(0);
delete extraWidgets.at(1);
extraWidgets.clear();
}
wizardStep=wizardIdentifySticks;
currentCommand=0;
setMoveFromCommand(currentCommand);
m_config->wzText->setText(QString(tr("Please move each control once at a time according to the instructions and picture below.\n\n"
"Move the %1 stick")).arg(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(currentCommand)));
manualSettingsData=manualSettingsObj->getData();
connect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
m_config->wzNext->setEnabled(false);
}
else if(step==wizardIdentifyCenter || (isSimple && step==wizardIdentifySticks))
{
if(wizardStep==wizardChooseMode)
{
QRadioButton * mode=qobject_cast<QRadioButton *>(extraWidgets.at(0));
if(mode->isChecked())
transmitterMode=mode1;
else
transmitterMode=mode2;
delete extraWidgets.at(0);
delete extraWidgets.at(1);
extraWidgets.clear();
}
setTxMovement(centerAll);
if(wizardStep==wizardIdentifySticks)
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
else
{
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
manualSettingsObj->setData(manualSettingsData);
manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
}
wizardStep=wizardIdentifyCenter;
m_config->wzText->setText(QString(tr("Please center all control controls and press next when ready (if your FlightMode switch has only two positions, leave it on either position)")));
}
else if(step==wizardIdentifyLimits)
{
dimOtherControls(false);
setTxMovement(moveAll);
if(wizardStep==wizardIdentifyCenter)
{
wizardStep=wizardIdentifyLimits;
manualCommandData=manualCommandObj->getData();
manualSettingsData=manualSettingsObj->getData();
for(unsigned int i=0;i<ManualControlCommand::CHANNEL_NUMELEM;++i)
{
manualSettingsData.ChannelNeutral[i]=manualCommandData.Channel[i];
}
manualSettingsObj->setData(manualSettingsData);
}
if(wizardStep==wizardIdentifyInverted)
{
foreach(QWidget * wd,extraWidgets)
{
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
if(cb)
{
disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
delete cb;
}
}
}
extraWidgets.clear();
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
wizardStep=wizardIdentifyLimits;
m_config->wzText->setText(QString(tr("Please move all controls to their maximum extents on both directions and press next when ready")));
UAVObject::Metadata mdata= manualCommandObj->getMetadata();
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
mdata.flightTelemetryUpdatePeriod = 150;
manualCommandObj->setMetadata(mdata);
manualSettingsData=manualSettingsObj->getData();
for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
{
manualSettingsData.ChannelMin[i]=manualSettingsData.ChannelNeutral[i];
manualSettingsData.ChannelMax[i]=manualSettingsData.ChannelNeutral[i];
}
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
}
else if(step==wizardIdentifyInverted)
{
dimOtherControls(true);
setTxMovement(nothing);
if(wizardStep==wizardIdentifyLimits)
{
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
manualSettingsObj->setData(manualSettingsData);
}
extraWidgets.clear();
foreach(QString name,manualSettingsObj->getFields().at(0)->getElementNames())
{
if(!name.contains("Access") && !name.contains("Flight"))
{
QCheckBox * cb=new QCheckBox(name,this);
extraWidgets.append(cb);
m_config->checkBoxesLayout->layout()->addWidget(cb);
connect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
}
}
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
wizardStep=wizardIdentifyInverted;
m_config->wzText->setText(QString(tr("Please check the picture below and check all the sticks which show an inverted movement and press next when ready")));
}
else if(step==wizardFinish)
{
foreach(QWidget * wd,extraWidgets)
{
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
if(cb)
{
disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
delete cb;
}
}
wizardStep=wizardFinish;
extraWidgets.clear();
m_config->wzText->setText(QString(tr("You have completed this wizard, please check below if the picture below mimics your sticks movement.\n"
"This new settings aren't saved to the board yet, after pressing next you will go to the initial screen where you can do that.")));
}
else if(step==wizardFinish+1)
{
break;
case wizardIdentifyCenter:
wizardSetUpStep(wizardIdentifyLimits);
break;
case wizardIdentifyLimits:
wizardSetUpStep(wizardIdentifyInverted);
break;
case wizardIdentifyInverted:
wizardSetUpStep(wizardFinish);
break;
case wizardFinish:
setTxMovement(nothing);
manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
@ -522,14 +350,560 @@ void ConfigInputWidget::setupWizardWidget(int step)
}
manualSettingsObj->setData(manualSettingsData);
m_config->stackedWidget->setCurrentIndex(0);
wizardStep=wizardWelcome;
wizardStep=wizardNone;
break;
default:
Q_ASSERT(0);
}
}
void ConfigInputWidget::wzBack()
{
if(wizardStep != wizardNone &&
wizardStep != wizardIdentifySticks)
wizardTearDownStep(wizardStep);
// State transitions for next button
switch(wizardStep) {
case wizardChooseMode:
wizardSetUpStep(wizardWelcome);
break;
case wizardChooseType:
wizardSetUpStep(wizardChooseMode);
break;
case wizardIdentifySticks:
prevChannel();
if(currentChannelNum == -1) {
wizardTearDownStep(wizardIdentifySticks);
wizardSetUpStep(wizardChooseType);
}
break;
case wizardIdentifyCenter:
wizardSetUpStep(wizardIdentifySticks);
break;
case wizardIdentifyLimits:
wizardSetUpStep(wizardIdentifyCenter);
break;
case wizardIdentifyInverted:
wizardSetUpStep(wizardIdentifyLimits);
break;
case wizardFinish:
wizardSetUpStep(wizardIdentifyInverted);
break;
default:
Q_ASSERT(0);
}
}
void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step)
{
switch(step) {
case wizardWelcome:
m_config->graphicsView->setVisible(false);
setTxMovement(nothing);
manualSettingsData=manualSettingsObj->getData();
manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED;
previousManualSettingsData = manualSettingsData;
manualSettingsObj->setData(manualSettingsData);
m_config->wzText->setText(tr("Welcome to the inputs configuration wizard.\n"
"Please follow the instructions on the screen and only move your controls when asked to.\n"
"Make sure you already configured your hardware settings on the proper tab and restarted your board.\n"
"At any time you can press 'back' to return to the previous screeen or 'Cancel' to cancel the wizard.\n"));
m_config->stackedWidget->setCurrentIndex(1);
m_config->wzBack->setEnabled(false);
break;
case wizardChooseMode:
{
m_config->graphicsView->setVisible(true);
setTxMovement(nothing);
m_config->wzText->setText(tr("Please choose your transmiter type.\n"
"Mode 1 means your throttle stick is on the right\n"
"Mode 2 means your throttle stick is on the left\n"));
m_config->wzBack->setEnabled(true);
QRadioButton * mode1=new QRadioButton(tr("Mode 1"),this);
QRadioButton * mode2=new QRadioButton(tr("Mode 2"),this);
mode2->setChecked(true);
extraWidgets.clear();
extraWidgets.append(mode1);
extraWidgets.append(mode2);
m_config->checkBoxesLayout->layout()->addWidget(mode1);
m_config->checkBoxesLayout->layout()->addWidget(mode2);
}
break;
case wizardChooseType:
{
m_config->wzText->setText(tr("Please choose your transmiter mode.\n"
"Acro means normal transmitter\n"
"Heli means there is a collective pitch and throttle input\n"
"If you are using a heli transmitter please engage throttle hold now please.\n"));
m_config->wzBack->setEnabled(true);
QRadioButton * typeAcro=new QRadioButton(tr("Acro"),this);
QRadioButton * typeHeli=new QRadioButton(tr("Heli"),this);
typeAcro->setChecked(true);
typeHeli->setChecked(false);
extraWidgets.clear();
extraWidgets.append(typeAcro);
extraWidgets.append(typeHeli);
m_config->checkBoxesLayout->layout()->addWidget(typeAcro);
m_config->checkBoxesLayout->layout()->addWidget(typeHeli);
wizardStep=wizardChooseType;
}
break;
case wizardIdentifySticks:
usedChannels.clear();
currentChannelNum=-1;
nextChannel();
manualSettingsData=manualSettingsObj->getData();
connect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
m_config->wzNext->setEnabled(false);
break;
case wizardIdentifyCenter:
setTxMovement(centerAll);
m_config->wzText->setText(QString(tr("Please center all control controls and press next when ready (if your FlightMode switch has only two positions, leave it on either position)")));
break;
case wizardIdentifyLimits:
{
dimOtherControls(false);
setTxMovement(moveAll);
m_config->wzText->setText(QString(tr("Please move all controls to their maximum extents on both directions and press next when ready")));
fastMdata();
manualSettingsData=manualSettingsObj->getData();
for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
{
manualSettingsData.ChannelMin[i]=manualSettingsData.ChannelNeutral[i];
manualSettingsData.ChannelMax[i]=manualSettingsData.ChannelNeutral[i];
}
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
}
break;
case wizardIdentifyInverted:
dimOtherControls(true);
setTxMovement(nothing);
extraWidgets.clear();
foreach(QString name,manualSettingsObj->getFields().at(0)->getElementNames())
{
if(!name.contains("Access") && !name.contains("Flight"))
{
QCheckBox * cb=new QCheckBox(name,this);
extraWidgets.append(cb);
m_config->checkBoxesLayout->layout()->addWidget(cb);
connect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
}
}
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
m_config->wzText->setText(QString(tr("Please check the picture below and check all the sticks which show an inverted movement and press next when ready")));
fastMdata();
break;
case wizardFinish:
foreach(QWidget * wd,extraWidgets)
{
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
if(cb)
{
disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
delete cb;
}
}
extraWidgets.clear();
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
m_config->wzText->setText(QString(tr("You have completed this wizard, please check below if the picture below mimics your sticks movement.\n"
"This new settings aren't saved to the board yet, after pressing next you will go to the initial screen where you can do that.")));
fastMdata();
manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE]=
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]+
((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]-
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])*0.02);
if((abs(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100) ||
(abs(manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100))
{
manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE]=manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]+
(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE])/2;
}
manualSettingsObj->setData(manualSettingsData);
break;
default:
Q_ASSERT(0);
}
wizardStep = step;
}
void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step)
{
QRadioButton * mode, * type;
Q_ASSERT(step == wizardStep);
switch(step) {
case wizardWelcome:
break;
case wizardChooseMode:
mode=qobject_cast<QRadioButton *>(extraWidgets.at(0));
if(mode->isChecked())
transmitterMode=mode1;
else
transmitterMode=mode2;
delete extraWidgets.at(0);
delete extraWidgets.at(1);
extraWidgets.clear();
break;
case wizardChooseType:
type=qobject_cast<QRadioButton *>(extraWidgets.at(0));
if(type->isChecked())
transmitterType=acro;
else
transmitterType=heli;
delete extraWidgets.at(0);
delete extraWidgets.at(1);
extraWidgets.clear();
break;
case wizardIdentifySticks:
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
m_config->wzNext->setEnabled(true);
break;
case wizardIdentifyCenter:
manualCommandData=manualCommandObj->getData();
manualSettingsData=manualSettingsObj->getData();
for(unsigned int i=0;i<ManualControlCommand::CHANNEL_NUMELEM;++i)
{
manualSettingsData.ChannelNeutral[i]=manualCommandData.Channel[i];
}
manualSettingsObj->setData(manualSettingsData);
break;
case wizardIdentifyLimits:
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
manualSettingsObj->setData(manualSettingsData);
restoreMdata();
break;
case wizardIdentifyInverted:
foreach(QWidget * wd,extraWidgets)
{
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
if(cb)
{
disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
delete cb;
}
}
extraWidgets.clear();
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
restoreMdata();
break;
case wizardFinish:
setTxMovement(nothing);
m_config->stackedWidget->setCurrentIndex(0);
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
restoreMdata();
break;
default:
Q_ASSERT(0);
}
}
/**
* Set manual control command to fast updates
*/
void ConfigInputWidget::fastMdata()
{
manualControlMdata = manualCommandObj->getMetadata();
UAVObject::Metadata mdata = manualControlMdata;
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
mdata.flightTelemetryUpdatePeriod = 150;
manualCommandObj->setMetadata(mdata);
}
/**
* Restore previous update settings for manual control data
*/
void ConfigInputWidget::restoreMdata()
{
manualCommandObj->setMetadata(manualControlMdata);
}
//void ConfigInputWidget::setupWizardWidget(int step)
//{
// if(step==wizardWelcome)
// {
// m_config->graphicsView->setVisible(false);
// setTxMovement(nothing);
// if(wizardStep==wizardChooseMode)
// {
// delete extraWidgets.at(0);
// delete extraWidgets.at(1);
// extraWidgets.clear();
// }
// manualSettingsData=manualSettingsObj->getData();
// manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED;
// manualSettingsObj->setData(manualSettingsData);
// m_config->wzText->setText(tr("Welcome to the inputs configuration wizard.\n"
// "Please follow the instructions on the screen and only move your controls when asked to.\n"
// "Make sure you already configured your hardware settings on the proper tab and restarted your board.\n"
// "At any time you can press 'back' to return to the previous screeen or 'Cancel' to cancel the wizard.\n"));
// m_config->stackedWidget->setCurrentIndex(1);
// m_config->wzBack->setEnabled(false);
// wizardStep=wizardWelcome;
// }
// else if(step==wizardChooseMode)
// {
// m_config->graphicsView->setVisible(true);
// setTxMovement(nothing);
// if(wizardStep==wizardIdentifySticks)
// {
// disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
// m_config->wzNext->setEnabled(true);
// }
// m_config->wzText->setText(tr("Please choose your transmiter type.\n"
// "Mode 1 means your throttle stick is on the right\n"
// "Mode 2 means your throttle stick is on the left\n"));
// m_config->wzBack->setEnabled(true);
// QRadioButton * mode1=new QRadioButton(tr("Mode 1"),this);
// QRadioButton * mode2=new QRadioButton(tr("Mode 2"),this);
// mode2->setChecked(true);
// extraWidgets.clear();
// extraWidgets.append(mode1);
// extraWidgets.append(mode2);
// m_config->checkBoxesLayout->layout()->addWidget(mode1);
// m_config->checkBoxesLayout->layout()->addWidget(mode2);
// wizardStep=wizardChooseMode;
// }
// else if(step==wizardChooseType)
// {
// if(wizardStep==wizardChooseMode)
// {
// QRadioButton * mode=qobject_cast<QRadioButton *>(extraWidgets.at(0));
// if(mode->isChecked())
// transmitterMode=mode1;
// else
// transmitterMode=mode2;
// delete extraWidgets.at(0);
// delete extraWidgets.at(1);
// extraWidgets.clear();
// }
// m_config->wzText->setText(tr("Please choose your transmiter mode.\n"
// "Acro means normal transmitter\n"
// "Heli means there is a collective pitch and throttle input\n"));
// m_config->wzBack->setEnabled(true);
// QRadioButton * typeAcro=new QRadioButton(tr("Acro"),this);
// QRadioButton * typeHeli=new QRadioButton(tr("Heli"),this);
// typeAcro->setChecked(true);
// typeHeli->setChecked(false);
// extraWidgets.clear();
// extraWidgets.append(typeAcro);
// extraWidgets.append(typeHeli);
// m_config->checkBoxesLayout->layout()->addWidget(typeAcro);
// m_config->checkBoxesLayout->layout()->addWidget(typeHeli);
// wizardStep=wizardChooseType;
// } else if(step==wizardIdentifySticks && !isSimple) {
// usedChannels.clear();
// if(wizardStep==wizardChooseType)
// {
// qDebug() << "Chosing type";
// QRadioButton * type=qobject_cast<QRadioButton *>(extraWidgets.at(0));
// if(type->isChecked())
// transmitterType=acro;
// else
// transmitterType=heli;
// qDebug() << "Checked: " << type->isChecked() << " " << "type is" << transmitterType;
// delete extraWidgets.at(0);
// delete extraWidgets.at(1);
// extraWidgets.clear();
// }
// wizardStep=wizardIdentifySticks;
// currentCommand=0;
// getChannelFromStep(currentCommand);
// manualSettingsData=manualSettingsObj->getData();
// connect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
// m_config->wzNext->setEnabled(false);
// }
// else if(step==wizardIdentifyCenter || (isSimple && step==wizardIdentifySticks))
// {
// setTxMovement(centerAll);
// if(wizardStep==wizardIdentifySticks)
// disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
// else
// {
// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
// manualSettingsObj->setData(manualSettingsData);
// manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
// }
// wizardStep=wizardIdentifyCenter;
// m_config->wzText->setText(QString(tr("Please center all control controls and press next when ready (if your FlightMode switch has only two positions, leave it on either position)")));
// }
// else if(step==wizardIdentifyLimits)
// {
// dimOtherControls(false);
// setTxMovement(moveAll);
// if(wizardStep==wizardIdentifyCenter)
// {
// wizardStep=wizardIdentifyLimits;
// manualCommandData=manualCommandObj->getData();
// manualSettingsData=manualSettingsObj->getData();
// for(unsigned int i=0;i<ManualControlCommand::CHANNEL_NUMELEM;++i)
// {
// manualSettingsData.ChannelNeutral[i]=manualCommandData.Channel[i];
// }
// manualSettingsObj->setData(manualSettingsData);
// }
// if(wizardStep==wizardIdentifyInverted)
// {
// foreach(QWidget * wd,extraWidgets)
// {
// QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
// if(cb)
// {
// disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
// delete cb;
// }
// }
// }
// extraWidgets.clear();
// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
// wizardStep=wizardIdentifyLimits;
// m_config->wzText->setText(QString(tr("Please move all controls to their maximum extents on both directions and press next when ready")));
// UAVObject::Metadata mdata= manualCommandObj->getMetadata();
// mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
// mdata.flightTelemetryUpdatePeriod = 150;
// manualCommandObj->setMetadata(mdata);
// manualSettingsData=manualSettingsObj->getData();
// for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
// {
// manualSettingsData.ChannelMin[i]=manualSettingsData.ChannelNeutral[i];
// manualSettingsData.ChannelMax[i]=manualSettingsData.ChannelNeutral[i];
// }
// connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
// }
// else if(step==wizardIdentifyInverted)
// {
// dimOtherControls(true);
// setTxMovement(nothing);
// if(wizardStep==wizardIdentifyLimits)
// {
// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
// manualSettingsObj->setData(manualSettingsData);
// }
// extraWidgets.clear();
// foreach(QString name,manualSettingsObj->getFields().at(0)->getElementNames())
// {
// if(!name.contains("Access") && !name.contains("Flight"))
// {
// QCheckBox * cb=new QCheckBox(name,this);
// extraWidgets.append(cb);
// m_config->checkBoxesLayout->layout()->addWidget(cb);
// connect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
// }
// }
// connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
// wizardStep=wizardIdentifyInverted;
// m_config->wzText->setText(QString(tr("Please check the picture below and check all the sticks which show an inverted movement and press next when ready")));
// }
// else if(step==wizardFinish)
// {
// foreach(QWidget * wd,extraWidgets)
// {
// QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
// if(cb)
// {
// disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
// delete cb;
// }
// }
// wizardStep=wizardFinish;
// extraWidgets.clear();
// m_config->wzText->setText(QString(tr("You have completed this wizard, please check below if the picture below mimics your sticks movement.\n"
// "This new settings aren't saved to the board yet, after pressing next you will go to the initial screen where you can do that.")));
// }
// else if(step==wizardFinish+1)
// {
// setTxMovement(nothing);
// manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
// manualSettingsData=manualSettingsObj->getData();
// manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE]=
// manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]+
// ((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]-
// manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])*0.02);
// if((abs(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100) ||
// (abs(manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100))
// {
// manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE]=manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]+
// (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE])/2;
// }
// manualSettingsObj->setData(manualSettingsData);
// m_config->stackedWidget->setCurrentIndex(0);
// wizardStep=wizardWelcome;
// }
//}
/**
* Set the display to indicate which channel the person should move
*/
void ConfigInputWidget::setChannel(int newChan)
{
if(newChan == ManualControlSettings::CHANNELGROUPS_COLLECTIVE)
m_config->wzText->setText(QString(tr("Please enable throttle hold mode and move the collective pitch stick")));
else if (newChan == ManualControlSettings::CHANNELGROUPS_FLIGHTMODE)
m_config->wzText->setText(QString(tr("Please flick the flight mode switch. For switches you may have to repeat this rapidly.")));
else
m_config->wzText->setText(QString(tr("Please move each control once at a time according to the instructions and picture below.\n\n"
"Move the %1 stick")).arg(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan)));
if(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan).contains("Accessory"))
m_config->wzNext->setEnabled(true);
setMoveFromCommand(newChan);
currentChannelNum = newChan;
}
/**
* Unfortunately order of channel should be different in different conditions. Selects
* next channel based on heli or acro mode
*/
void ConfigInputWidget::nextChannel()
{
QList <int> order = (transmitterType == heli) ? heliChannelOrder : acroChannelOrder;
if(currentChannelNum == -1) {
setChannel(order[0]);
return;
}
for (int i = 0; i < order.length() - 1; i++) {
if(order[i] == currentChannelNum) {
setChannel(order[i+1]);
return;
}
}
currentChannelNum = -1; // hit end of list
}
/**
* Unfortunately order of channel should be different in different conditions. Selects
* previous channel based on heli or acro mode
*/
void ConfigInputWidget::prevChannel()
{
QList <int> order = transmitterType == heli ? heliChannelOrder : acroChannelOrder;
// No previous from unset channel or next state
if(currentChannelNum == -1)
return;
for (int i = 1; i < order.length(); i++) {
if(order[i] == currentChannelNum) {
setChannel(order[i-1]);
usedChannels.removeLast();
return;
}
}
currentChannelNum = -1; // hit end of list
}
void ConfigInputWidget::identifyControls()
{
static int debounce=0;
receiverActivityData=receiverActivityObj->getData();
if(receiverActivityData.ActiveChannel==255)
return;
@ -547,26 +921,18 @@ void ConfigInputWidget::identifyControls()
debounce=0;
usedChannels.append(lastChannel);
manualSettingsData=manualSettingsObj->getData();
manualSettingsData.ChannelGroups[currentCommand]=currentChannel.group;
manualSettingsData.ChannelNumber[currentCommand]=currentChannel.number;
manualSettingsData.ChannelGroups[currentChannelNum]=currentChannel.group;
manualSettingsData.ChannelNumber[currentChannelNum]=currentChannel.number;
manualSettingsObj->setData(manualSettingsData);
}
else
return;
}
++currentCommand;
setMoveFromCommand(currentCommand);
if(currentCommand>ManualControlSettings::CHANNELGROUPS_NUMELEM-1)
{
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
m_config->wzNext->setEnabled(true);
}
m_config->wzText->setText(QString(tr("Please move each control once at a time according to the instructions and picture below.\n\n"
"Move the %1 stick")).arg(manualSettingsObj->getFields().at(0)->getElementNames().at(currentCommand)));
if(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(currentCommand).contains("Accessory"))
{
m_config->wzNext->setEnabled(true);
}
m_config->wzText->clear();
setTxMovement(nothing);
QTimer::singleShot(300, this, SLOT(wzNext()));
}
void ConfigInputWidget::identifyLimits()
@ -605,6 +971,13 @@ void ConfigInputWidget::setMoveFromCommand(int command)
else
setTxMovement(moveRightVerticalStick);
}
else if(command==ManualControlSettings::CHANNELNUMBER_COLLECTIVE)
{
if(transmitterMode==mode2)
setTxMovement(moveLeftVerticalStick);
else
setTxMovement(moveRightVerticalStick);
}
else if(command==ManualControlSettings::CHANNELNUMBER_FLIGHTMODE)
{
setTxMovement(moveFlightMode);
@ -912,11 +1285,9 @@ void ConfigInputWidget::dimOtherControls(bool value)
void ConfigInputWidget::enableControls(bool enable)
{
if(goWizard)
{
goWizard->setEnabled(enable);
goSimpleWizard->setEnabled(enable);
}
m_config->configurationWizard->setEnabled(enable);
m_config->runCalibration->setEnabled(enable);
ConfigTaskWidget::enableControls(enable);
}
@ -978,3 +1349,73 @@ void ConfigInputWidget::moveFMSlider()
m_config->fmsSlider->setValue(0);
}
}
void ConfigInputWidget::updateCalibration()
{
manualCommandData=manualCommandObj->getData();
for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
{
if((!reverse[i] && manualSettingsData.ChannelMin[i]>manualCommandData.Channel[i]) ||
(reverse[i] && manualSettingsData.ChannelMin[i]<manualCommandData.Channel[i]))
manualSettingsData.ChannelMin[i]=manualCommandData.Channel[i];
if((!reverse[i] && manualSettingsData.ChannelMax[i]<manualCommandData.Channel[i]) ||
(reverse[i] && manualSettingsData.ChannelMax[i]>manualCommandData.Channel[i]))
manualSettingsData.ChannelMax[i]=manualCommandData.Channel[i];
manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
}
manualSettingsObj->setData(manualSettingsData);
manualSettingsObj->updated();
}
void ConfigInputWidget::simpleCalibration(bool enable)
{
if (enable) {
QMessageBox msgBox;
msgBox.setText(tr("Arming Settings are now set to Always Disarmed for your safety."));
msgBox.setDetailedText(tr("You will have to reconfigure arming settings yourself afterwards."));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
manualCommandData = manualCommandObj->getData();
manualSettingsData=manualSettingsObj->getData();
manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED;
manualSettingsObj->setData(manualSettingsData);
for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) {
reverse[i] = manualSettingsData.ChannelMax[i] < manualSettingsData.ChannelMin[i];
manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i];
manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i];
}
fastMdata();
connect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject*)), this, SLOT(updateCalibration()));
} else {
manualCommandData = manualCommandObj->getData();
manualSettingsData = manualSettingsObj->getData();
restoreMdata();
for (int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++)
manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
// Force flight mode neutral to middle
manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE] =
(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE] +
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE]) / 2;
// Force throttle to be near min
manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE]=
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]+
((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]-
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])*0.02);
manualSettingsObj->setData(manualSettingsData);
disconnect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject*)), this, SLOT(updateCalibration()));
}
}

View File

@ -52,22 +52,24 @@ class ConfigInputWidget: public ConfigTaskWidget
public:
ConfigInputWidget(QWidget *parent = 0);
~ConfigInputWidget();
enum wizardSteps{wizardWelcome,wizardChooseMode,wizardIdentifySticks,wizardIdentifyCenter,wizardIdentifyLimits,wizardIdentifyInverted,wizardFinish};
enum wizardSteps{wizardWelcome,wizardChooseMode,wizardChooseType,wizardIdentifySticks,wizardIdentifyCenter,wizardIdentifyLimits,wizardIdentifyInverted,wizardFinish,wizardNone};
enum txMode{mode1,mode2};
enum txMovements{moveLeftVerticalStick,moveRightVerticalStick,moveLeftHorizontalStick,moveRightHorizontalStick,moveAccess0,moveAccess1,moveAccess2,moveFlightMode,centerAll,moveAll,nothing};
enum txMovementType{vertical,horizontal,jump,mix};
enum txType {acro, heli};
public slots:
private:
bool growing;
bool reverse[ManualControlSettings::CHANNELNEUTRAL_NUMELEM];
txMovements currentMovement;
int movePos;
void setTxMovement(txMovements movement);
Ui_InputWidget *m_config;
wizardSteps wizardStep;
void setupWizardWidget(int step);
QList<QWidget*> extraWidgets;
txMode transmitterMode;
txType transmitterType;
struct channelsStruct
{
bool operator ==(const channelsStruct& rhs) const
@ -82,12 +84,16 @@ private:
QEventLoop * loop;
bool skipflag;
uint currentCommand;
int currentChannelNum;
QList<int> heliChannelOrder;
QList<int> acroChannelOrder;
ManualControlCommand * manualCommandObj;
ManualControlCommand::DataFields manualCommandData;
UAVObject::Metadata manualControlMdata;
ManualControlSettings * manualSettingsObj;
ManualControlSettings::DataFields manualSettingsData;
ManualControlSettings::DataFields previousManualSettingsData;
ReceiverActivity * receiverActivityObj;
ReceiverActivity::DataFields receiverActivityData;
@ -116,16 +122,22 @@ private:
QTimer * animate;
void resetTxControls();
void setMoveFromCommand(int command);
QPushButton * goWizard;
QPushButton * goSimpleWizard;
bool isSimple;
void goToWizard();
void fastMdata();
void restoreMdata();
void setChannel(int);
void nextChannel();
void prevChannel();
void wizardSetUpStep(enum wizardSteps);
void wizardTearDownStep(enum wizardSteps);
private slots:
void wzNext();
void wzBack();
void wzCancel();
void goToNormalWizard();
void goToSimpleWizard();
void goToWizard();
void openHelp();
void identifyControls();
void identifyLimits();
@ -134,6 +146,8 @@ private slots:
void dimOtherControls(bool value);
void moveFMSlider();
void invertControls();
void simpleCalibration(bool state);
void updateCalibration();
protected:
void resizeEvent(QResizeEvent *event);
virtual void enableControls(bool enable);

View File

@ -48,7 +48,9 @@ void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString fiel
UAVObject *obj=NULL;
UAVObjectField *_field=NULL;
obj = objManager->getObject(QString(object));
Q_ASSERT(obj);
_field = obj->getField(QString(field));
Q_ASSERT(_field);
addUAVObjectToWidgetRelation(object,field,widget,_field->getElementNames().indexOf(index));
}
@ -59,6 +61,7 @@ void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString fiel
if(!object.isEmpty())
{
obj = objManager->getObject(QString(object));
Q_ASSERT(obj);
connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues()));
}
//smartsave->addObject(obj);
@ -182,6 +185,10 @@ void ConfigTaskWidget::populateWidgets()
{
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
}
else if(QSlider * cb=qobject_cast<QSlider *>(ow->widget))
{
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
}
}
setDirty(dirtyBack);
}
@ -207,6 +214,10 @@ void ConfigTaskWidget::refreshWidgetsValues()
{
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
}
else if(QSlider * cb=qobject_cast<QSlider *>(ow->widget))
{
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
}
}
setDirty(dirtyBack);
}
@ -231,6 +242,10 @@ void ConfigTaskWidget::updateObjectsFromWidgets()
{
ow->field->setValue(cb->value()* ow->scale,ow->index);
}
else if(QSlider * cb=qobject_cast<QSlider *>(ow->widget))
{
ow->field->setValue(cb->value()* ow->scale,ow->index);
}
}
}

View File

@ -30,7 +30,38 @@
<number>1</number>
</property>
<widget class="QWidget" name="advancedPage">
<layout class="QVBoxLayout" name="verticalLayout_4"/>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QVBoxLayout" name="channelSettings"/>
</item>
<item>
<widget class="QPushButton" name="configurationWizard">
<property name="text">
<string>Start Configuration Wizard</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="runCalibration">
<property name="text">
<string>Run Calibration</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="wizard">
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -48,13 +79,6 @@
<height>70</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>

View File

@ -1,6 +1,8 @@
#include "inputchannelform.h"
#include "ui_inputchannelform.h"
#include "manualcontrolsettings.h"
inputChannelForm::inputChannelForm(QWidget *parent,bool showlegend) :
QWidget(parent),
ui(new Ui::inputChannelForm)
@ -21,9 +23,103 @@ inputChannelForm::inputChannelForm(QWidget *parent,bool showlegend) :
delete ui->legend4;
delete ui->legend5;
}
connect(ui->channelMin,SIGNAL(valueChanged(int)),this,SLOT(minMaxUpdated()));
connect(ui->channelMax,SIGNAL(valueChanged(int)),this,SLOT(minMaxUpdated()));
connect(ui->channelGroup,SIGNAL(currentIndexChanged(int)),this,SLOT(groupUpdated()));
connect(ui->channelNeutral,SIGNAL(valueChanged(int)), this, SLOT(neutralUpdated(int)));
// This is awkward but since we want the UI to be a dropdown but the field is not an enum
// it breaks the UAUVObject widget relation of the task gadget. Running the data through
// a spin box fixes this
connect(ui->channelNumberDropdown,SIGNAL(currentIndexChanged(int)),this,SLOT(channelDropdownUpdated(int)));
connect(ui->channelNumber,SIGNAL(valueChanged(int)),this,SLOT(channelNumberUpdated(int)));
}
inputChannelForm::~inputChannelForm()
{
delete ui;
}
/**
* Update the direction of the slider and boundaries
*/
void inputChannelForm::minMaxUpdated()
{
bool reverse = ui->channelMin->value() > ui->channelMax->value();
if(reverse) {
ui->channelNeutral->setMinimum(ui->channelMax->value());
ui->channelNeutral->setMaximum(ui->channelMin->value());
} else {
ui->channelNeutral->setMinimum(ui->channelMin->value());
ui->channelNeutral->setMaximum(ui->channelMax->value());
}
ui->channelRev->setChecked(reverse);
ui->channelNeutral->setInvertedAppearance(reverse);
ui->channelNeutral->setInvertedControls(reverse);
}
void inputChannelForm::neutralUpdated(int newval)
{
ui->neutral->setText(QString::number(newval));
}
/**
* Update the channel options based on the selected receiver type
*
* I fully admit this is terrible practice to embed data within UI
* like this. Open to suggestions. JC 2011-09-07
*/
void inputChannelForm::groupUpdated()
{
ui->channelNumberDropdown->clear();
ui->channelNumberDropdown->addItem("Disabled");
quint8 count = 0;
switch(ui->channelGroup->currentIndex()) {
case -1: // Nothing selected
count = 0;
break;
case ManualControlSettings::CHANNELGROUPS_PWM:
count = 8; // Need to make this 6 for CC
break;
case ManualControlSettings::CHANNELGROUPS_PPM:
case ManualControlSettings::CHANNELGROUPS_SPEKTRUM1:
case ManualControlSettings::CHANNELGROUPS_SPEKTRUM2:
count = 12;
break;
case ManualControlSettings::CHANNELGROUPS_SBUS:
count = 18;
break;
case ManualControlSettings::CHANNELGROUPS_GCS:
count = 5;
case ManualControlSettings::CHANNELGROUPS_NONE:
count = 0;
break;
default:
Q_ASSERT(0);
}
for (int i = 0; i < count; i++)
ui->channelNumberDropdown->addItem(QString(tr("Chan %1").arg(i+1)));
ui->channelNumber->setMaximum(count);
ui->channelNumber->setMinimum(0);
}
/**
* Update the dropdown from the hidden control
*/
void inputChannelForm::channelDropdownUpdated(int newval)
{
ui->channelNumber->setValue(newval);
}
/**
* Update the hidden control from the dropdown
*/
void inputChannelForm::channelNumberUpdated(int newval)
{
ui->channelNumberDropdown->setCurrentIndex(newval);
}

View File

@ -16,6 +16,13 @@ public:
~inputChannelForm();
friend class ConfigInputWidget;
private slots:
void minMaxUpdated();
void neutralUpdated(int);
void groupUpdated();
void channelDropdownUpdated(int);
void channelNumberUpdated(int);
private:
Ui::inputChannelForm *ui;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>404</width>
<height>43</height>
<width>543</width>
<height>49</height>
</rect>
</property>
<property name="windowTitle">
@ -26,47 +26,7 @@
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="3">
<widget class="QLabel" name="legend2">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Number</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="legend3">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Min</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="legend0">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Function</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="legend1">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Group</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QLabel" name="channelName">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
@ -85,41 +45,79 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="channelGroup"/>
</item>
<item row="1" column="3">
<widget class="QSpinBox" name="channelNumber">
<property name="maximum">
<number>255</number>
<item row="2" column="2">
<widget class="QComboBox" name="channelGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>6</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="legend4">
<item row="2" column="4">
<widget class="QSpinBox" name="channelMin">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="2" column="8">
<widget class="QSpinBox" name="channelMax">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="legend0">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Neutral</string>
<string>Function</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QSpinBox" name="channelMin">
<property name="maximum">
<number>9999</number>
<item row="0" column="3">
<widget class="QLabel" name="legend2">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Number</string>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QSpinBox" name="channelNeutral">
<property name="maximum">
<number>9999</number>
<item row="0" column="2">
<widget class="QLabel" name="legend1">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="0" column="6">
<item row="0" column="8">
<widget class="QLabel" name="legend5">
<property name="enabled">
<bool>true</bool>
@ -129,13 +127,132 @@
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QSpinBox" name="channelMax">
<property name="maximum">
<number>9999</number>
<item row="0" column="4">
<widget class="QLabel" name="legend3">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Min</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="legend4">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Neutral</string>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QSlider" name="channelNeutral">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="channelNumberDropdown">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>4</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="maxVisibleItems">
<number>7</number>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QSpinBox" name="channelNumber">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="2" column="10">
<widget class="QCheckBox" name="channelRev">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Rev</string>
</property>
</widget>
</item>
<item row="2" column="9">
<widget class="QLabel" name="neutral">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="5">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="7">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>

View File

@ -2,11 +2,12 @@
<object name="ManualControlCommand" singleinstance="true" settings="false">
<description>The output from the @ref ManualControlModule which descodes the receiver inputs. Overriden by GCS for fly-by-wire control.</description>
<field name="Connected" units="" type="enum" elements="1" options="False,True"/>
<field name="Roll" units="%" type="float" elements="1"/>
<field name="Throttle" units="%" type="float" elements="1"/>
<field name="Roll" units="%" type="float" elements="1"/>
<field name="Pitch" units="%" type="float" elements="1"/>
<field name="Yaw" units="%" type="float" elements="1"/>
<field name="Throttle" units="%" type="float" elements="1"/>
<field name="Channel" units="us" type="uint16" elements="8"/>
<field name="Collective" units="%" type="float" elements="1"/>
<field name="Channel" units="us" type="uint16" elements="9"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="2000"/>

View File

@ -2,16 +2,16 @@
<object name="ManualControlSettings" singleinstance="true" settings="true">
<description>Settings to indicate how to decode receiver input by @ref ManualControlModule.</description>
<field name="ChannelGroups" units="Channel Group" type="enum"
elementnames="Roll,Pitch,Yaw,Throttle,FlightMode,Accessory0,Accessory1,Accessory2"
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2"
options="PWM,PPM,Spektrum1,Spektrum2,S.Bus,GCS,None" defaultvalue="None"/>
<field name="ChannelNumber" units="channel" type="uint8" defaultvalue="255"
elementnames="Roll,Pitch,Yaw,Throttle,FlightMode,Accessory0,Accessory1,Accessory2"/>
<field name="ChannelNumber" units="channel" type="uint8" defaultvalue="0"
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2"/>
<field name="ChannelMin" units="us" type="int16" defaultvalue="1000"
elementnames="Roll,Pitch,Yaw,Throttle,FlightMode,Accessory0,Accessory1,Accessory2"/>
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2"/>
<field name="ChannelNeutral" units="us" type="int16" defaultvalue="1500"
elementnames="Roll,Pitch,Yaw,Throttle,FlightMode,Accessory0,Accessory1,Accessory2"/>
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2"/>
<field name="ChannelMax" units="us" type="int16" defaultvalue="2000"
elementnames="Roll,Pitch,Yaw,Throttle,FlightMode,Accessory0,Accessory1,Accessory2"/>
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2"/>
<field name="Arming" units="" type="enum" elements="1" options="Always Disarmed,Always Armed,Roll Left,Roll Right,Pitch Forward,Pitch Aft,Yaw Left,Yaw Right" defaultvalue="Always Disarmed"/>

View File

@ -6,7 +6,7 @@
<field name="AccelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="DecelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="ThrottleCurve1" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0,0,0,0"/>
<field name="Curve2Source" units="" type="enum" elements="1" options="Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Throttle"/>
<field name="Curve2Source" units="" type="enum" elements="1" options="Throttle,Roll,Pitch,Yaw,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Throttle"/>
<field name="ThrottleCurve2" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/>
<field name="Mixer1Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer1Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>