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.
740 lines
28 KiB
740 lines
28 KiB
10 years ago
|
/*=====================================================================
|
||
|
|
||
|
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/>.
|
||
|
|
||
|
======================================================================*/
|
||
|
|
||
|
#include "JoystickConfigController.h"
|
||
|
#include "JoystickManager.h"
|
||
|
#include "QGCMessageBox.h"
|
||
|
|
||
|
#include <QSettings>
|
||
|
|
||
|
QGC_LOGGING_CATEGORY(JoystickConfigControllerLog, "JoystickConfigControllerLog")
|
||
|
|
||
|
const int JoystickConfigController::_updateInterval = 150; ///< Interval for timer which updates radio channel widgets
|
||
|
const int JoystickConfigController::_calCenterPoint = 0;
|
||
|
const int JoystickConfigController::_calValidMinValue = -32768; ///< Largest valid minimum axis value
|
||
|
const int JoystickConfigController::_calValidMaxValue = 32768; ///< Smallest valid maximum axis value
|
||
|
const int JoystickConfigController::_calDefaultMinValue = -32768; ///< Default value for Min if not set
|
||
|
const int JoystickConfigController::_calDefaultMaxValue = 32768; ///< Default value for Max if not set
|
||
|
const int JoystickConfigController::_calRoughCenterDelta = 500; ///< Delta around center point which is considered to be roughly centered
|
||
|
const int JoystickConfigController::_calMoveDelta = 32768/2; ///< Amount of delta past center which is considered stick movement
|
||
|
const int JoystickConfigController::_calSettleDelta = 100; ///< Amount of delta which is considered no stick movement
|
||
|
const int JoystickConfigController::_calMinDelta = 1000; ///< Amount of delta allowed around min value to consider channel at min
|
||
|
|
||
|
const int JoystickConfigController::_stickDetectSettleMSecs = 500;
|
||
|
|
||
|
const char* JoystickConfigController::_imageFilePrefix = "calibration/";
|
||
|
const char* JoystickConfigController::_imageFileMode2Dir = "joystick/";
|
||
|
const char* JoystickConfigController::_imageCenter = "joystickCenter.png";
|
||
|
const char* JoystickConfigController::_imageThrottleUp = "joystickThrottleUp.png";
|
||
|
const char* JoystickConfigController::_imageThrottleDown = "joystickThrottleDown.png";
|
||
|
const char* JoystickConfigController::_imageYawLeft = "joystickYawLeft.png";
|
||
|
const char* JoystickConfigController::_imageYawRight = "joystickYawRight.png";
|
||
|
const char* JoystickConfigController::_imageRollLeft = "joystickRollLeft.png";
|
||
|
const char* JoystickConfigController::_imageRollRight = "joystickRollRight.png";
|
||
|
const char* JoystickConfigController::_imagePitchUp = "joystickPitchUp.png";
|
||
|
const char* JoystickConfigController::_imagePitchDown = "joystickPitchDown.png";
|
||
|
|
||
|
const char* JoystickConfigController::_settingsGroup = "Joysticks";
|
||
|
|
||
|
JoystickConfigController::JoystickConfigController(void) :
|
||
|
_currentStep(-1),
|
||
|
_axisCount(0),
|
||
|
_calState(calStateAxisWait),
|
||
|
_statusText(NULL),
|
||
|
_cancelButton(NULL),
|
||
|
_nextButton(NULL),
|
||
|
_skipButton(NULL)
|
||
|
{
|
||
|
// FIXME: Needs to handle active joystick change
|
||
|
connect(JoystickManager::instance()->activeJoystick(), &Joystick::rawAxisValueChanged, this, &JoystickConfigController::_axisValueChanged);
|
||
|
JoystickManager::instance()->activeJoystick()->startPolling();
|
||
|
_loadSettings();
|
||
|
|
||
|
_resetInternalCalibrationValues();
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::start(void)
|
||
|
{
|
||
|
_stopCalibration();
|
||
|
_setInternalCalibrationValuesFromSettings();
|
||
|
}
|
||
|
|
||
|
JoystickConfigController::~JoystickConfigController()
|
||
|
{
|
||
|
_storeSettings();
|
||
|
}
|
||
|
|
||
|
/// @brief Returns the state machine entry for the specified state.
|
||
|
const JoystickConfigController::stateMachineEntry* JoystickConfigController::_getStateMachineEntry(int step)
|
||
|
{
|
||
|
static const char* msgBegin = "Allow all sticks to center as shown in diagram.\n\nClick Next to continue";
|
||
|
static const char* msgThrottleUp = "Move the Throttle stick all the way up and hold it there...";
|
||
|
static const char* msgThrottleDown = "Move the Throttle stick all the way down and hold it there...";
|
||
|
static const char* msgYawLeft = "Move the Yaw stick all the way to the left and hold it there...";
|
||
|
static const char* msgYawRight = "Move the Yaw stick all the way to the right and hold it there...";
|
||
|
static const char* msgRollLeft = "Move the Roll stick all the way to the left and hold it there...";
|
||
|
static const char* msgRollRight = "Move the Roll stick all the way to the right and hold it there...";
|
||
|
static const char* msgPitchDown = "Move the Pitch stick all the way down and hold it there...";
|
||
|
static const char* msgPitchUp = "Move the Pitch stick all the way up and hold it there...";
|
||
|
static const char* msgPitchCenter = "Allow the Pitch stick to move back to center...";
|
||
|
static const char* msgComplete = "All settings have been captured. Click Next to Save.";
|
||
|
|
||
|
static const stateMachineEntry rgStateMachine[] = {
|
||
|
//Function
|
||
|
{ Joystick::maxFunction, msgBegin, _imageCenter, &JoystickConfigController::_inputCenterWaitBegin, &JoystickConfigController::_saveAllTrims, NULL },
|
||
|
{ Joystick::throttleFunction, msgThrottleUp, _imageThrottleUp, &JoystickConfigController::_inputStickDetect, NULL, NULL },
|
||
|
{ Joystick::throttleFunction, msgThrottleDown, _imageThrottleDown, &JoystickConfigController::_inputStickMin, NULL, NULL },
|
||
|
{ Joystick::yawFunction, msgYawRight, _imageYawRight, &JoystickConfigController::_inputStickDetect, NULL, NULL },
|
||
|
{ Joystick::yawFunction, msgYawLeft, _imageYawLeft, &JoystickConfigController::_inputStickMin, NULL, NULL },
|
||
|
{ Joystick::rollFunction, msgRollRight, _imageRollRight, &JoystickConfigController::_inputStickDetect, NULL, NULL },
|
||
|
{ Joystick::rollFunction, msgRollLeft, _imageRollLeft, &JoystickConfigController::_inputStickMin, NULL, NULL },
|
||
|
{ Joystick::pitchFunction, msgPitchUp, _imagePitchUp, &JoystickConfigController::_inputStickDetect, NULL, NULL },
|
||
|
{ Joystick::pitchFunction, msgPitchDown, _imagePitchDown, &JoystickConfigController::_inputStickMin, NULL, NULL },
|
||
|
{ Joystick::pitchFunction, msgPitchCenter, _imageCenter, &JoystickConfigController::_inputCenterWait, NULL, NULL },
|
||
|
{ Joystick::maxFunction, msgComplete, _imageCenter, NULL, &JoystickConfigController::_writeCalibration, NULL },
|
||
|
};
|
||
|
|
||
|
Q_ASSERT(step >=0 && step < (int)(sizeof(rgStateMachine) / sizeof(rgStateMachine[0])));
|
||
|
|
||
|
return &rgStateMachine[step];
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_advanceState(void)
|
||
|
{
|
||
|
_currentStep++;
|
||
|
_setupCurrentState();
|
||
|
}
|
||
|
|
||
|
|
||
|
/// @brief Sets up the state machine according to the current step from _currentStep.
|
||
|
void JoystickConfigController::_setupCurrentState(void)
|
||
|
{
|
||
|
const stateMachineEntry* state = _getStateMachineEntry(_currentStep);
|
||
|
|
||
|
_statusText->setProperty("text", state->instructions);
|
||
|
|
||
|
_setHelpImage(state->image);
|
||
|
|
||
|
_stickDetectAxis = _axisMax;
|
||
|
_stickDetectSettleStarted = false;
|
||
|
|
||
|
_calSaveCurrentValues();
|
||
|
|
||
|
_nextButton->setEnabled(state->nextFn != NULL);
|
||
|
_skipButton->setEnabled(state->skipFn != NULL);
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_axisValueChanged(int axis, int value)
|
||
|
{
|
||
|
if (axis >= 0 && axis <= _axisMax) {
|
||
|
// We always update raw values
|
||
|
_axisRawValue[axis] = value;
|
||
|
emit axisValueChanged(axis, _axisRawValue[axis]);
|
||
|
|
||
|
// Signal attitude axis values to Qml if mapped
|
||
|
if (_rgAxisInfo[axis].function != Joystick::maxFunction) {
|
||
|
switch (_rgAxisInfo[axis].function) {
|
||
|
case Joystick::rollFunction:
|
||
|
emit rollAxisValueChanged(_axisRawValue[axis]);
|
||
|
break;
|
||
|
case Joystick::pitchFunction:
|
||
|
emit pitchAxisValueChanged(_axisRawValue[axis]);
|
||
|
break;
|
||
|
case Joystick::yawFunction:
|
||
|
emit yawAxisValueChanged(_axisRawValue[axis]);
|
||
|
break;
|
||
|
case Joystick::throttleFunction:
|
||
|
emit throttleAxisValueChanged(_axisRawValue[axis]);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//qCDebug(JoystickConfigControllerLog) << "Raw value" << axis << value;
|
||
|
|
||
|
if (_currentStep == -1) {
|
||
|
// Track the axis count by keeping track of how many axes we see
|
||
|
if (axis + 1 > (int)_axisCount) {
|
||
|
_axisCount = axis + 1;
|
||
|
emit axisCountChanged(_axisCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_currentStep != -1) {
|
||
|
const stateMachineEntry* state = _getStateMachineEntry(_currentStep);
|
||
|
Q_ASSERT(state);
|
||
|
if (state->rcInputFn) {
|
||
|
(this->*state->rcInputFn)(state->function, axis, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::nextButtonClicked(void)
|
||
|
{
|
||
|
if (_currentStep == -1) {
|
||
|
// Need to have enough channels
|
||
|
if (_axisCount < _axisMinimum) {
|
||
|
QGCMessageBox::warning(tr("Joystick"), tr("Detected %1 joystick axes. To operate PX4, you need at least %2 axes.").arg(_axisCount).arg(_axisMinimum));
|
||
|
return;
|
||
|
}
|
||
|
_startCalibration();
|
||
|
} else {
|
||
|
const stateMachineEntry* state = _getStateMachineEntry(_currentStep);
|
||
|
Q_ASSERT(state);
|
||
|
Q_ASSERT(state->nextFn);
|
||
|
(this->*state->nextFn)();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::skipButtonClicked(void)
|
||
|
{
|
||
|
Q_ASSERT(_currentStep != -1);
|
||
|
|
||
|
const stateMachineEntry* state = _getStateMachineEntry(_currentStep);
|
||
|
Q_ASSERT(state);
|
||
|
Q_ASSERT(state->skipFn);
|
||
|
(this->*state->skipFn)();
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::cancelButtonClicked(void)
|
||
|
{
|
||
|
_stopCalibration();
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_saveAllTrims(void)
|
||
|
{
|
||
|
// We save all trims as the first step. At this point no axes are mapped but it should still
|
||
|
// allow us to get good trims for the roll/pitch/yaw/throttle even though we don't know which
|
||
|
// axiss they are yet. AS we continue through the process the other axes will get their
|
||
|
// trims reset to correct values.
|
||
|
|
||
|
for (int i=0; i<_axisCount; i++) {
|
||
|
qCDebug(JoystickConfigControllerLog) << "_saveAllTrims trim" << _axisRawValue[i];
|
||
|
_rgAxisInfo[i].axisTrim = _axisRawValue[i];
|
||
|
}
|
||
|
_advanceState();
|
||
|
}
|
||
|
|
||
|
/// @brief Waits for the sticks to be centered, enabling Next when done.
|
||
|
void JoystickConfigController::_inputCenterWaitBegin(Joystick::AxisFunction_t function, int axis, int value)
|
||
|
{
|
||
|
Q_UNUSED(function);
|
||
|
Q_UNUSED(axis);
|
||
|
Q_UNUSED(value);
|
||
|
|
||
|
// FIXME: Doesn't wait for center
|
||
|
|
||
|
_nextButton->setEnabled(true);
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::_stickSettleComplete(int value)
|
||
|
{
|
||
|
// We are waiting for the stick to settle out to a max position
|
||
|
|
||
|
if (abs(_stickDetectValue - value) > _calSettleDelta) {
|
||
|
// Stick is moving too much to consider stopped
|
||
|
|
||
|
qCDebug(JoystickConfigControllerLog) << "_stickSettleComplete still moving, _stickDetectValue:value" << _stickDetectValue << value;
|
||
|
|
||
|
_stickDetectValue = value;
|
||
|
_stickDetectSettleStarted = false;
|
||
|
} else {
|
||
|
// Stick is still positioned within the specified small range
|
||
|
|
||
|
if (_stickDetectSettleStarted) {
|
||
|
// We have already started waiting
|
||
|
|
||
|
if (_stickDetectSettleElapsed.elapsed() > _stickDetectSettleMSecs) {
|
||
|
// Stick has stayed positioned in one place long enough, detection is complete.
|
||
|
return true;
|
||
|
}
|
||
|
} else {
|
||
|
// Start waiting for the stick to stay settled for _stickDetectSettleWaitMSecs msecs
|
||
|
|
||
|
qCDebug(JoystickConfigControllerLog) << "_stickSettleComplete starting settle timer, _stickDetectValue:value" << _stickDetectValue << value;
|
||
|
|
||
|
_stickDetectSettleStarted = true;
|
||
|
_stickDetectSettleElapsed.start();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_inputStickDetect(Joystick::AxisFunction_t function, int axis, int value)
|
||
|
{
|
||
|
qCDebug(JoystickConfigControllerLog) << "_inputStickDetect function:axis:value" << function << axis << value;
|
||
|
|
||
|
// If this axis is already used in a mapping we can't use it again
|
||
|
if (_rgAxisInfo[axis].function != Joystick::maxFunction) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (_stickDetectAxis == _axisMax) {
|
||
|
// We have not detected enough movement on a axis yet
|
||
|
|
||
|
if (abs(_axisValueSave[axis] - value) > _calMoveDelta) {
|
||
|
// Stick has moved far enough to consider it as being selected for the function
|
||
|
|
||
|
qCDebug(JoystickConfigControllerLog) << "_inputStickDetect starting settle wait, function:axis:value" << function << axis << value;
|
||
|
|
||
|
// Setup up to detect stick being pegged to min or max value
|
||
|
_stickDetectAxis = axis;
|
||
|
_stickDetectInitialValue = value;
|
||
|
_stickDetectValue = value;
|
||
|
}
|
||
|
} else if (axis == _stickDetectAxis) {
|
||
|
if (_stickSettleComplete(value)) {
|
||
|
AxisInfo* info = &_rgAxisInfo[axis];
|
||
|
|
||
|
qCDebug(JoystickConfigControllerLog) << "_inputStickDetect settle complete, function:axis:value" << function << axis << value;
|
||
|
|
||
|
// Stick detection is complete. Stick should be at max position.
|
||
|
// Map the axis to the function
|
||
|
_rgFunctionAxisMapping[function] = axis;
|
||
|
info->function = function;
|
||
|
|
||
|
// Axis should be at max value, if it is below initial set point the the axis is reversed.
|
||
|
info->reversed = value < _axisValueSave[axis];
|
||
|
qCDebug(JoystickConfigControllerLog) << "_inputStickDetect reversed:value:_axisValueSave" << info->reversed << value << _axisValueSave[axis];
|
||
|
|
||
|
if (info->reversed) {
|
||
|
_rgAxisInfo[axis].axisMin = value;
|
||
|
} else {
|
||
|
_rgAxisInfo[axis].axisMax = value;
|
||
|
}
|
||
|
|
||
|
_signalAllAttiudeValueChanges();
|
||
|
|
||
|
_advanceState();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_inputStickMin(Joystick::AxisFunction_t function, int axis, int value)
|
||
|
{
|
||
|
// We only care about the axis mapped to the function we are working on
|
||
|
if (_rgFunctionAxisMapping[function] != axis) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (_stickDetectAxis == _axisMax) {
|
||
|
// Setup up to detect stick being pegged to extreme position
|
||
|
if (_rgAxisInfo[axis].reversed) {
|
||
|
if (value > _calCenterPoint + _calMoveDelta) {
|
||
|
_stickDetectAxis = axis;
|
||
|
_stickDetectInitialValue = value;
|
||
|
_stickDetectValue = value;
|
||
|
}
|
||
|
} else {
|
||
|
if (value < _calCenterPoint - _calMoveDelta) {
|
||
|
_stickDetectAxis = axis;
|
||
|
_stickDetectInitialValue = value;
|
||
|
_stickDetectValue = value;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// We are waiting for the selected axis to settle out
|
||
|
|
||
|
if (_stickSettleComplete(value)) {
|
||
|
AxisInfo* info = &_rgAxisInfo[axis];
|
||
|
|
||
|
// Stick detection is complete. Stick should be at min position.
|
||
|
if (info->reversed) {
|
||
|
_rgAxisInfo[axis].axisMax = value;
|
||
|
} else {
|
||
|
_rgAxisInfo[axis].axisMin = value;
|
||
|
}
|
||
|
|
||
|
// Check if this is throttle and set trim accordingly
|
||
|
if (function == Joystick::throttleFunction) {
|
||
|
_rgAxisInfo[axis].axisTrim = value;
|
||
|
}
|
||
|
// XXX to support configs which can reverse they need to check a reverse
|
||
|
// flag here and not do this.
|
||
|
|
||
|
_advanceState();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_inputCenterWait(Joystick::AxisFunction_t function, int axis, int value)
|
||
|
{
|
||
|
// We only care about the axis mapped to the function we are working on
|
||
|
if (_rgFunctionAxisMapping[function] != axis) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (_stickDetectAxis == _axisMax) {
|
||
|
// Sticks have not yet moved close enough to center
|
||
|
|
||
|
if (abs(_calCenterPoint - value) < _calRoughCenterDelta) {
|
||
|
// Stick has moved close enough to center that we can start waiting for it to settle
|
||
|
_stickDetectAxis = axis;
|
||
|
_stickDetectInitialValue = value;
|
||
|
_stickDetectValue = value;
|
||
|
}
|
||
|
} else {
|
||
|
if (_stickSettleComplete(value)) {
|
||
|
_advanceState();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// @brief Resets internal calibration values to their initial state in preparation for a new calibration sequence.
|
||
|
void JoystickConfigController::_resetInternalCalibrationValues(void)
|
||
|
{
|
||
|
// Set all raw axiss to not reversed and center point values
|
||
|
for (size_t i=0; i<_axisMax; i++) {
|
||
|
struct AxisInfo* info = &_rgAxisInfo[i];
|
||
|
info->function = Joystick::maxFunction;
|
||
|
info->reversed = false;
|
||
|
info->axisMin = JoystickConfigController::_calCenterPoint;
|
||
|
info->axisMax = JoystickConfigController::_calCenterPoint;
|
||
|
info->axisTrim = JoystickConfigController::_calCenterPoint;
|
||
|
}
|
||
|
|
||
|
// Initialize attitude function mapping to function axis not set
|
||
|
for (size_t i=0; i<Joystick::maxFunction; i++) {
|
||
|
_rgFunctionAxisMapping[i] = _axisMax;
|
||
|
}
|
||
|
|
||
|
_signalAllAttiudeValueChanges();
|
||
|
}
|
||
|
|
||
|
/// @brief Sets internal calibration values from the stored settings
|
||
|
void JoystickConfigController::_setInternalCalibrationValuesFromSettings(void)
|
||
|
{
|
||
|
Joystick* joystick = JoystickManager::instance()->activeJoystick();
|
||
|
|
||
|
// Initialize all function mappings to not set
|
||
|
|
||
|
for (size_t i=0; i<_axisMax; i++) {
|
||
|
struct AxisInfo* info = &_rgAxisInfo[i];
|
||
|
info->function = Joystick::maxFunction;
|
||
|
}
|
||
|
|
||
|
for (size_t i=0; i<Joystick::maxFunction; i++) {
|
||
|
_rgFunctionAxisMapping[i] = _axisMax;
|
||
|
}
|
||
|
|
||
|
for (int axis=0; axis<_axisMax; axis++) {
|
||
|
struct AxisInfo* info = &_rgAxisInfo[axis];
|
||
|
|
||
|
Joystick::Calibration_t calibration = joystick->getCalibration(axis);
|
||
|
info->axisTrim = calibration.center;
|
||
|
info->axisMin = calibration.min;
|
||
|
info->axisMax = calibration.max;
|
||
|
info->reversed = calibration.reversed;
|
||
|
|
||
|
qCDebug(JoystickConfigControllerLog) << "Read settings axis:min:max:trim:reversed" << axis << info->axisMin << info->axisMax << info->axisTrim << info->reversed;
|
||
|
}
|
||
|
|
||
|
for (int function=0; function<Joystick::maxFunction; function++) {
|
||
|
int paramAxis;
|
||
|
|
||
|
paramAxis = joystick->getFunctionAxis((Joystick::AxisFunction_t)function);
|
||
|
|
||
|
_rgFunctionAxisMapping[function] = paramAxis;
|
||
|
_rgAxisInfo[paramAxis].function = (Joystick::AxisFunction_t)function;
|
||
|
}
|
||
|
|
||
|
_signalAllAttiudeValueChanges();
|
||
|
}
|
||
|
|
||
|
/// @brief Validates the current settings against the calibration rules resetting values as necessary.
|
||
|
void JoystickConfigController::_validateCalibration(void)
|
||
|
{
|
||
|
for (int chan = 0; chan<_axisMax; chan++) {
|
||
|
struct AxisInfo* info = &_rgAxisInfo[chan];
|
||
|
|
||
|
if (chan < _axisCount) {
|
||
|
// Validate Min/Max values. Although the axis appears as available we still may
|
||
|
// not have good min/max/trim values for it. Set to defaults if needed.
|
||
|
if (info->axisMin > _calValidMinValue || info->axisMax < _calValidMaxValue) {
|
||
|
qCDebug(JoystickConfigControllerLog) << "_validateCalibration resetting axis" << chan;
|
||
|
info->axisMin = _calDefaultMinValue;
|
||
|
info->axisMax = _calDefaultMaxValue;
|
||
|
info->axisTrim = info->axisMin + ((info->axisMax - info->axisMin) / 2);
|
||
|
} else {
|
||
|
switch (_rgAxisInfo[chan].function) {
|
||
|
case Joystick::throttleFunction:
|
||
|
case Joystick::yawFunction:
|
||
|
case Joystick::rollFunction:
|
||
|
case Joystick::pitchFunction:
|
||
|
// Make sure trim is within min/max
|
||
|
if (info->axisTrim < info->axisMin) {
|
||
|
info->axisTrim = info->axisMin;
|
||
|
} else if (info->axisTrim > info->axisMax) {
|
||
|
info->axisTrim = info->axisMax;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
// Non-attitude control axiss have calculated trim
|
||
|
info->axisTrim = info->axisMin + ((info->axisMax - info->axisMin) / 2);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
} else {
|
||
|
// Unavailable axiss are set to defaults
|
||
|
qCDebug(JoystickConfigControllerLog) << "_validateCalibration resetting unavailable axis" << chan;
|
||
|
info->axisMin = _calDefaultMinValue;
|
||
|
info->axisMax = _calDefaultMaxValue;
|
||
|
info->axisTrim = info->axisMin + ((info->axisMax - info->axisMin) / 2);
|
||
|
info->reversed = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// @brief Saves the rc calibration values to the board parameters.
|
||
|
void JoystickConfigController::_writeCalibration(void)
|
||
|
{
|
||
|
Joystick* joystick = JoystickManager::instance()->activeJoystick();
|
||
|
|
||
|
_validateCalibration();
|
||
|
|
||
|
for (int axis=0; axis<_axisMax; axis++) {
|
||
|
Joystick::Calibration_t calibration;
|
||
|
|
||
|
struct AxisInfo* info = &_rgAxisInfo[axis];
|
||
|
|
||
|
calibration.center = info->axisTrim;
|
||
|
calibration.min = info->axisMin;
|
||
|
calibration.max = info->axisMax;
|
||
|
calibration.reversed = info->reversed;
|
||
|
|
||
|
joystick->setCalibration(axis, calibration);
|
||
|
}
|
||
|
|
||
|
// Write function mapping parameters
|
||
|
for (int function=0; function<Joystick::maxFunction; function++) {
|
||
|
joystick->setFunctionAxis((Joystick::AxisFunction_t)function, _rgFunctionAxisMapping[function]);
|
||
|
}
|
||
|
|
||
|
_stopCalibration();
|
||
|
_setInternalCalibrationValuesFromSettings();
|
||
|
}
|
||
|
|
||
|
/// @brief Starts the calibration process
|
||
|
void JoystickConfigController::_startCalibration(void)
|
||
|
{
|
||
|
Q_ASSERT(_axisCount >= _axisMinimum);
|
||
|
|
||
|
_resetInternalCalibrationValues();
|
||
|
|
||
|
_nextButton->setProperty("text", "Next");
|
||
|
_cancelButton->setEnabled(true);
|
||
|
|
||
|
_currentStep = 0;
|
||
|
_setupCurrentState();
|
||
|
|
||
|
JoystickManager::instance()->activeJoystick()->setCalibrating(true);
|
||
|
}
|
||
|
|
||
|
/// @brief Cancels the calibration process, setting things back to initial state.
|
||
|
void JoystickConfigController::_stopCalibration(void)
|
||
|
{
|
||
|
_currentStep = -1;
|
||
|
|
||
|
_setInternalCalibrationValuesFromSettings();
|
||
|
|
||
|
_statusText->setProperty("text", "");
|
||
|
|
||
|
_nextButton->setProperty("text", "Calibrate");
|
||
|
_nextButton->setEnabled(true);
|
||
|
_cancelButton->setEnabled(false);
|
||
|
_skipButton->setEnabled(false);
|
||
|
|
||
|
_setHelpImage(_imageCenter);
|
||
|
|
||
|
JoystickManager::instance()->activeJoystick()->setCalibrating(false);
|
||
|
}
|
||
|
|
||
|
/// @brief Saves the current axis values, so that we can detect when the use moves an input.
|
||
|
void JoystickConfigController::_calSaveCurrentValues(void)
|
||
|
{
|
||
|
qCDebug(JoystickConfigControllerLog) << "_calSaveCurrentValues";
|
||
|
for (unsigned i = 0; i < _axisMax; i++) {
|
||
|
_axisValueSave[i] = _axisRawValue[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// @brief Set up the Save state of calibration.
|
||
|
void JoystickConfigController::_calSave(void)
|
||
|
{
|
||
|
_calState = calStateSave;
|
||
|
|
||
|
_statusText->setProperty("text",
|
||
|
"The current calibration settings are now displayed for each axis on screen.\n\n"
|
||
|
"Click the Next button to upload calibration to board. Click Cancel if you don't want to save these values.");
|
||
|
|
||
|
_nextButton->setEnabled(true);
|
||
|
_skipButton->setEnabled(false);
|
||
|
_cancelButton->setEnabled(true);
|
||
|
|
||
|
// This updates the internal values according to the validation rules. Then _updateView will tick and update ui
|
||
|
// such that the settings that will be written our are displayed.
|
||
|
_validateCalibration();
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_loadSettings(void)
|
||
|
{
|
||
|
QSettings settings;
|
||
|
|
||
|
settings.beginGroup(_settingsGroup);
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_storeSettings(void)
|
||
|
{
|
||
|
QSettings settings;
|
||
|
|
||
|
settings.beginGroup(_settingsGroup);
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_setHelpImage(const char* imageFile)
|
||
|
{
|
||
|
QString file = _imageFilePrefix;
|
||
|
|
||
|
file += _imageFileMode2Dir;
|
||
|
file += imageFile;
|
||
|
|
||
|
qCDebug(JoystickConfigControllerLog) << "_setHelpImage" << file;
|
||
|
|
||
|
_imageHelp = file;
|
||
|
emit imageHelpChanged(file);
|
||
|
}
|
||
|
|
||
|
int JoystickConfigController::axisCount(void)
|
||
|
{
|
||
|
return _axisCount;
|
||
|
}
|
||
|
|
||
|
int JoystickConfigController::rollAxisValue(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::rollFunction] != _axisMax) {
|
||
|
return _axisRawValue[Joystick::rollFunction];
|
||
|
} else {
|
||
|
return 1500;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int JoystickConfigController::pitchAxisValue(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::pitchFunction] != _axisMax) {
|
||
|
return _axisRawValue[Joystick::pitchFunction];
|
||
|
} else {
|
||
|
return 1500;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int JoystickConfigController::yawAxisValue(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::yawFunction] != _axisMax) {
|
||
|
return _axisRawValue[Joystick::yawFunction];
|
||
|
} else {
|
||
|
return 1500;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int JoystickConfigController::throttleAxisValue(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::throttleFunction] != _axisMax) {
|
||
|
return _axisRawValue[Joystick::throttleFunction];
|
||
|
} else {
|
||
|
return 1500;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::rollAxisMapped(void)
|
||
|
{
|
||
|
return _rgFunctionAxisMapping[Joystick::rollFunction] != _axisMax;
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::pitchAxisMapped(void)
|
||
|
{
|
||
|
return _rgFunctionAxisMapping[Joystick::pitchFunction] != _axisMax;
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::yawAxisMapped(void)
|
||
|
{
|
||
|
return _rgFunctionAxisMapping[Joystick::yawFunction] != _axisMax;
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::throttleAxisMapped(void)
|
||
|
{
|
||
|
return _rgFunctionAxisMapping[Joystick::throttleFunction] != _axisMax;
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::rollAxisReversed(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::rollFunction] != _axisMax) {
|
||
|
return _rgAxisInfo[_rgFunctionAxisMapping[Joystick::rollFunction]].reversed;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::pitchAxisReversed(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::pitchFunction] != _axisMax) {
|
||
|
return _rgAxisInfo[_rgFunctionAxisMapping[Joystick::pitchFunction]].reversed;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::yawAxisReversed(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::yawFunction] != _axisMax) {
|
||
|
return _rgAxisInfo[_rgFunctionAxisMapping[Joystick::yawFunction]].reversed;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool JoystickConfigController::throttleAxisReversed(void)
|
||
|
{
|
||
|
if (_rgFunctionAxisMapping[Joystick::throttleFunction] != _axisMax) {
|
||
|
return _rgAxisInfo[_rgFunctionAxisMapping[Joystick::throttleFunction]].reversed;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void JoystickConfigController::_signalAllAttiudeValueChanges(void)
|
||
|
{
|
||
|
emit rollAxisMappedChanged(rollAxisMapped());
|
||
|
emit pitchAxisMappedChanged(pitchAxisMapped());
|
||
|
emit yawAxisMappedChanged(yawAxisMapped());
|
||
|
emit throttleAxisMappedChanged(throttleAxisMapped());
|
||
|
|
||
|
emit rollAxisReversedChanged(rollAxisReversed());
|
||
|
emit pitchAxisReversedChanged(pitchAxisReversed());
|
||
|
emit yawAxisReversedChanged(yawAxisReversed());
|
||
|
emit throttleAxisReversedChanged(throttleAxisReversed());
|
||
|
}
|