|
|
|
/*=====================================================================
|
|
|
|
|
|
|
|
QGroundControl Open Source Ground Control Station
|
|
|
|
|
|
|
|
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
|
|
|
|
|
|
This file is part of the QGROUNDCONTROL project
|
|
|
|
|
|
|
|
QGROUNDCONTROL is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
QGROUNDCONTROL is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
======================================================================*/
|
|
|
|
|
|
|
|
/// @file
|
|
|
|
/// @author Don Gagne <don@thegagnes.com>
|
|
|
|
|
|
|
|
#include "FlightModesComponentController.h"
|
|
|
|
#include "QGCMAVLink.h"
|
|
|
|
#include "UASManager.h"
|
|
|
|
#include "AutoPilotPluginManager.h"
|
|
|
|
|
|
|
|
#include <QVariant>
|
|
|
|
#include <QQmlProperty>
|
|
|
|
|
|
|
|
FlightModesComponentController::FlightModesComponentController(QObject* parent) :
|
|
|
|
QObject(parent),
|
|
|
|
_liveRCValues(false),
|
|
|
|
_validConfiguration(false),
|
|
|
|
_channelCount(18),
|
|
|
|
_autoPilotPlugin(NULL)
|
|
|
|
{
|
|
|
|
_uas = UASManager::instance()->getActiveUAS();
|
|
|
|
Q_ASSERT(_uas);
|
|
|
|
|
|
|
|
_autoPilotPlugin = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(_uas);
|
|
|
|
Q_ASSERT(_autoPilotPlugin);
|
|
|
|
Q_ASSERT(_autoPilotPlugin->pluginReady());
|
|
|
|
|
|
|
|
_initRcValues();
|
|
|
|
_validateConfiguration();
|
|
|
|
}
|
|
|
|
|
|
|
|
FlightModesComponentController::~FlightModesComponentController()
|
|
|
|
{
|
|
|
|
setSendLiveRCSwitchRanges(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlightModesComponentController::_initRcValues(void)
|
|
|
|
{
|
|
|
|
for (int i=0; i<_chanMax; i++) {
|
|
|
|
_rcValues << 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This will look for parameter settings which would cause the config to not run correctly.
|
|
|
|
/// It will set _validConfiguration and _configurationErrors as needed.
|
|
|
|
void FlightModesComponentController::_validateConfiguration(void)
|
|
|
|
{
|
|
|
|
_validConfiguration = true;
|
|
|
|
|
|
|
|
_channelCount = _autoPilotPlugin->parameterExists("RC_CHAN_CNT") ?
|
|
|
|
_autoPilotPlugin->getParameterFact("RC_CHAN_CNT")->value().toInt() :
|
|
|
|
_chanMax;
|
|
|
|
if (_channelCount <= 0 || _channelCount > _chanMax) {
|
|
|
|
// Parameter exists, but has not yet been set or is invalid. Use default
|
|
|
|
_channelCount = _chanMax;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure switches are valid and within channel range
|
|
|
|
|
|
|
|
QStringList switchParams, switchNames;
|
|
|
|
QList<int> switchMappings;
|
|
|
|
|
|
|
|
switchParams << "RC_MAP_MODE_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_POSCTL_SW" << "RC_MAP_OFFB_SW";
|
|
|
|
switchNames << "Mode Switch" << "Return Switch" << "Loiter Switch" << "PosCtl Switch" << "Offboard Switch";
|
|
|
|
|
|
|
|
for(int i=0; i<switchParams.count(); i++) {
|
|
|
|
int map = _autoPilotPlugin->getParameterFact(switchParams[i])->value().toInt();
|
|
|
|
switchMappings << map;
|
|
|
|
|
|
|
|
if (map < 0 || map > _channelCount) {
|
|
|
|
_validConfiguration = false;
|
|
|
|
_configurationErrors += QString("%1 is set to %2. Mapping must between 0 and %3 (inclusive).\n").arg(switchNames[i]).arg(map).arg(_channelCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure switches are not double-mapped
|
|
|
|
|
|
|
|
QStringList attitudeParams, attitudeNames;
|
|
|
|
|
|
|
|
attitudeParams << "RC_MAP_THROTTLE" << "RC_MAP_YAW" << "RC_MAP_PITCH" << "RC_MAP_ROLL" << "RC_MAP_FLAPS" << "RC_MAP_AUX1" << "RC_MAP_AUX2" << "RC_MAP_ACRO_SW";
|
|
|
|
attitudeNames << "Throttle" << "Yaw" << "Pitch" << "Roll" << "Flaps" << "Aux1" << "Aux2" << "Acro";
|
|
|
|
|
|
|
|
for (int i=0; i<attitudeParams.count(); i++) {
|
|
|
|
int map = _autoPilotPlugin->getParameterFact(attitudeParams[i])->value().toInt();
|
|
|
|
|
|
|
|
for (int j=0; j<switchParams.count(); j++) {
|
|
|
|
if (map != 0 && map == switchMappings[j]) {
|
|
|
|
_validConfiguration = false;
|
|
|
|
_configurationErrors += QString("%1 is set to same channel as %2.\n").arg(switchNames[j]).arg(attitudeNames[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for switches that must be on their own channel
|
|
|
|
|
|
|
|
QStringList singleSwitchParams, singleSwitchNames;
|
|
|
|
|
|
|
|
singleSwitchParams << "RC_MAP_RETURN_SW" << "RC_MAP_OFFB_SW";
|
|
|
|
singleSwitchNames << "Return Switch" << "Offboard Switch";
|
|
|
|
|
|
|
|
for (int i=0; i<singleSwitchParams.count(); i++) {
|
|
|
|
int map = _autoPilotPlugin->getParameterFact(singleSwitchParams[i])->value().toInt();
|
|
|
|
|
|
|
|
for (int j=0; j<switchParams.count(); j++) {
|
|
|
|
if (map != 0 && singleSwitchParams[i] != switchParams[j] && map == switchMappings[j]) {
|
|
|
|
_validConfiguration = false;
|
|
|
|
_configurationErrors += QString("%1 must be on seperate channel, but is set to same channel as %2.\n").arg(singleSwitchNames[i]).arg(switchParams[j]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FlightModesComponentController::setSendLiveRCSwitchRanges(bool start)
|
|
|
|
{
|
|
|
|
if (start) {
|
|
|
|
|
|
|
|
// We need to know min and max for channel in order to calculate percentage range
|
|
|
|
for (int i=0; i<_chanMax; i++) {
|
|
|
|
QString rcMinParam, rcMaxParam, rcRevParam;
|
|
|
|
|
|
|
|
rcMinParam = QString("RC%1_MIN").arg(i+1);
|
|
|
|
rcMaxParam = QString("RC%1_MAX").arg(i+1);
|
|
|
|
rcRevParam = QString("RC%1_REV").arg(i+1);
|
|
|
|
|
|
|
|
QVariant value;
|
|
|
|
|
|
|
|
_rgRCMin[i] = _autoPilotPlugin->getParameterFact(rcMinParam)->value().toInt();
|
|
|
|
_rgRCMax[i] = _autoPilotPlugin->getParameterFact(rcMaxParam)->value().toInt();
|
|
|
|
|
|
|
|
float floatReversed = _autoPilotPlugin->getParameterFact(rcRevParam)->value().toFloat();
|
|
|
|
_rgRCReversed[i] = floatReversed == -1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
_uas->startRadioControlCalibration();
|
|
|
|
connect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
|
|
|
|
} else {
|
|
|
|
disconnect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
|
|
|
|
_uas->endRadioControlCalibration();
|
|
|
|
_initRcValues();
|
|
|
|
emit switchLiveRangeChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief This routine is called whenever a raw value for an RC channel changes.
|
|
|
|
/// @param chan RC channel on which signal is coming from (0-based)
|
|
|
|
/// @param fval Current value for channel
|
|
|
|
void FlightModesComponentController::_remoteControlChannelRawChanged(int chan, float fval)
|
|
|
|
{
|
|
|
|
Q_ASSERT(chan >= 0 && chan <= _chanMax);
|
|
|
|
|
|
|
|
if (fval < _rgRCMin[chan]) {
|
|
|
|
fval= _rgRCMin[chan];
|
|
|
|
}
|
|
|
|
if (fval > _rgRCMax[chan]) {
|
|
|
|
fval= _rgRCMax[chan];
|
|
|
|
}
|
|
|
|
|
|
|
|
float percentRange = (fval - _rgRCMin[chan]) / (float)(_rgRCMax[chan] - _rgRCMin[chan]);
|
|
|
|
if (_rgRCReversed[chan]) {
|
|
|
|
percentRange = 1.0 - percentRange;
|
|
|
|
}
|
|
|
|
|
|
|
|
_rcValues[chan] = percentRange;
|
|
|
|
emit switchLiveRangeChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
double FlightModesComponentController::_switchLiveRange(const QString& param)
|
|
|
|
{
|
|
|
|
QVariant value;
|
|
|
|
|
|
|
|
int channel = _autoPilotPlugin->getParameterFact(param)->value().toInt();
|
|
|
|
if (channel == 0) {
|
|
|
|
return 1.0;
|
|
|
|
} else {
|
|
|
|
return _rcValues[channel - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double FlightModesComponentController::modeSwitchLiveRange(void)
|
|
|
|
{
|
|
|
|
return _switchLiveRange("RC_MAP_MODE_SW");
|
|
|
|
}
|
|
|
|
|
|
|
|
double FlightModesComponentController::returnSwitchLiveRange(void)
|
|
|
|
{
|
|
|
|
return _switchLiveRange("RC_MAP_RETURN_SW");
|
|
|
|
}
|
|
|
|
|
|
|
|
double FlightModesComponentController::offboardSwitchLiveRange(void)
|
|
|
|
{
|
|
|
|
return _switchLiveRange("RC_MAP_OFFB_SW");
|
|
|
|
}
|
|
|
|
|
|
|
|
double FlightModesComponentController::loiterSwitchLiveRange(void)
|
|
|
|
{
|
|
|
|
return _switchLiveRange("RC_MAP_LOITER_SW");
|
|
|
|
}
|
|
|
|
|
|
|
|
double FlightModesComponentController::posCtlSwitchLiveRange(void)
|
|
|
|
{
|
|
|
|
return _switchLiveRange("RC_MAP_POSCTL_SW");
|
|
|
|
}
|
|
|
|
|