地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
7.9 KiB

/*=====================================================================
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");
}