Joystick.cc 34.9 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10 11 12 13 14

#include "Joystick.h"
#include "QGC.h"
#include "AutoPilotPlugin.h"
#include "UAS.h"
15 16 17 18
#include "QGCApplication.h"
#include "VideoManager.h"
#include "QGCCameraManager.h"
#include "QGCCameraControl.h"
19 20 21

#include <QSettings>

Gus Grubba's avatar
Gus Grubba committed
22
QGC_LOGGING_CATEGORY(JoystickLog,       "JoystickLog")
23
QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog")
24

25
const char* Joystick::_settingsGroup =                  "Joysticks";
Gus Grubba's avatar
Gus Grubba committed
26
const char* Joystick::_calibratedSettingsKey =          "Calibrated3"; // Increment number to force recalibration
27 28 29 30 31
const char* Joystick::_buttonActionSettingsKey =        "ButtonActionName%1";
const char* Joystick::_throttleModeSettingsKey =        "ThrottleMode";
const char* Joystick::_exponentialSettingsKey =         "Exponential";
const char* Joystick::_accumulatorSettingsKey =         "Accumulator";
const char* Joystick::_deadbandSettingsKey =            "Deadband";
32
const char* Joystick::_circleCorrectionSettingsKey =    "Circle_Correction";
33
const char* Joystick::_frequencySettingsKey =           "Frequency";
34
const char* Joystick::_txModeSettingsKey =              nullptr;
35 36 37 38 39
const char* Joystick::_fixedWingTXModeSettingsKey =     "TXMode_FixedWing";
const char* Joystick::_multiRotorTXModeSettingsKey =    "TXMode_MultiRotor";
const char* Joystick::_roverTXModeSettingsKey =         "TXMode_Rover";
const char* Joystick::_vtolTXModeSettingsKey =          "TXMode_VTOL";
const char* Joystick::_submarineTXModeSettingsKey =     "TXMode_Submarine";
Gus Grubba's avatar
Gus Grubba committed
40
const char* Joystick::_gimbalSettingsKey =              "GimbalEnabled";
41

42 43
const char* Joystick::_buttonActionArm =                QT_TR_NOOP("Arm");
const char* Joystick::_buttonActionDisarm =             QT_TR_NOOP("Disarm");
Gus Grubba's avatar
Gus Grubba committed
44
const char* Joystick::_buttonActionToggleArm =          QT_TR_NOOP("Toggle Arm");
45 46
const char* Joystick::_buttonActionVTOLFixedWing =      QT_TR_NOOP("VTOL: Fixed Wing");
const char* Joystick::_buttonActionVTOLMultiRotor =     QT_TR_NOOP("VTOL: Multi-Rotor");
47 48 49 50 51 52
const char* Joystick::_buttonActionZoomIn =             QT_TR_NOOP("Zoom In");
const char* Joystick::_buttonActionZoomOut =            QT_TR_NOOP("Zoom Out");
const char* Joystick::_buttonActionNextStream =         QT_TR_NOOP("Next Video Stream");
const char* Joystick::_buttonActionPreviousStream =     QT_TR_NOOP("Previous Video Stream");
const char* Joystick::_buttonActionNextCamera =         QT_TR_NOOP("Next Camera");
const char* Joystick::_buttonActionPreviousCamera =     QT_TR_NOOP("Previous Camera");
Gus Grubba's avatar
Gus Grubba committed
53 54 55 56
const char* Joystick::_buttonActionTriggerCamera =      QT_TR_NOOP("Trigger Camera");
const char* Joystick::_buttonActionStartVideoRecord =   QT_TR_NOOP("Start Recording Video");
const char* Joystick::_buttonActionStopVideoRecord =    QT_TR_NOOP("Stop Recording Video");
const char* Joystick::_buttonActionToggleVideoRecord =  QT_TR_NOOP("Toggle Recording Video");
Gus Grubba's avatar
Gus Grubba committed
57 58 59 60 61
const char* Joystick::_buttonActionGimbalDown =         QT_TR_NOOP("Gimbal Down");
const char* Joystick::_buttonActionGimbalUp =           QT_TR_NOOP("Gimbal Up");
const char* Joystick::_buttonActionGimbalLeft =         QT_TR_NOOP("Gimbal Left");
const char* Joystick::_buttonActionGimbalRight =        QT_TR_NOOP("Gimbal Right");
const char* Joystick::_buttonActionGimbalCenter =       QT_TR_NOOP("Gimbal Center");
62

63 64 65 66
const char* Joystick::_rgFunctionSettingsKey[Joystick::maxFunction] = {
    "RollAxis",
    "PitchAxis",
    "YawAxis",
Gus Grubba's avatar
Gus Grubba committed
67 68 69
    "ThrottleAxis",
    "GimbalPitchAxis",
    "GimbalYawAxis"
70 71
};

72 73
int Joystick::_transmitterMode = 2;

74
Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager)
Gus Grubba's avatar
Gus Grubba committed
75
    : _name(name)
76 77
    , _axisCount(axisCount)
    , _buttonCount(buttonCount)
78
    , _hatCount(hatCount)
Gus Grubba's avatar
Gus Grubba committed
79
    , _hatButtonCount(4 * hatCount)
80
    , _totalButtonCount(_buttonCount+_hatButtonCount)
81
    , _multiVehicleManager(multiVehicleManager)
82
{
Gus Grubba's avatar
Gus Grubba committed
83 84 85
    _rgAxisValues   = new int[static_cast<size_t>(_axisCount)];
    _rgCalibration  = new Calibration_t[static_cast<size_t>(_axisCount)];
    _rgButtonValues = new uint8_t[static_cast<size_t>(_totalButtonCount)];
86

Gus Grubba's avatar
Gus Grubba committed
87
    for (int i = 0; i < _axisCount; i++) {
88 89
        _rgAxisValues[i] = 0;
    }
Gus Grubba's avatar
Gus Grubba committed
90
    for (int i = 0; i < _totalButtonCount; i++) {
Gus Grubba's avatar
Gus Grubba committed
91
        _rgButtonValues[i] = BUTTON_UP;
92
    }
93

94
    _updateTXModeSettingsKey(_multiVehicleManager->activeVehicle());
95
    _loadSettings();
96
    connect(_multiVehicleManager, &MultiVehicleManager::activeVehicleChanged, this, &Joystick::_activeVehicleChanged);
97 98 99 100
}

Joystick::~Joystick()
{
101 102 103 104
    // Crash out of the thread if it is still running
    terminate();
    wait();

Jacob Walser's avatar
Jacob Walser committed
105 106 107
    delete[] _rgAxisValues;
    delete[] _rgCalibration;
    delete[] _rgButtonValues;
108 109
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
void Joystick::_setDefaultCalibration(void) {
    QSettings   settings;
    settings.beginGroup(_settingsGroup);
    settings.beginGroup(_name);
    _calibrated = settings.value(_calibratedSettingsKey, false).toBool();

    // Only set default calibrations if we do not have a calibration for this gamecontroller
    if(_calibrated) return;

    for(int axis = 0; axis < _axisCount; axis++) {
        Joystick::Calibration_t calibration;
        _rgCalibration[axis] = calibration;
    }

    _rgCalibration[1].reversed = true;
    _rgCalibration[3].reversed = true;

127 128 129 130 131
    // Default TX Mode 2 axis assignments for gamecontrollers
    _rgFunctionAxis[rollFunction]       = 2;
    _rgFunctionAxis[pitchFunction]      = 3;
    _rgFunctionAxis[yawFunction]        = 0;
    _rgFunctionAxis[throttleFunction]   = 1;
132

Gus Grubba's avatar
Gus Grubba committed
133 134 135 136 137 138 139 140 141
    _rgFunctionAxis[gimbalPitchFunction]= 4;
    _rgFunctionAxis[gimbalYawFunction]  = 5;

    _exponential    = 0;
    _accumulator    = false;
    _deadband       = false;
    _frequency      = 25.0f;
    _throttleMode   = ThrottleModeDownZero;
    _calibrated     = true;
142
    _circleCorrection = false;
143 144 145 146

    _saveSettings();
}

147
void Joystick::_updateTXModeSettingsKey(Vehicle* activeVehicle)
148 149 150 151 152 153 154 155 156 157 158 159 160
{
    if(activeVehicle) {
        if(activeVehicle->fixedWing()) {
            _txModeSettingsKey = _fixedWingTXModeSettingsKey;
        } else if(activeVehicle->multiRotor()) {
            _txModeSettingsKey = _multiRotorTXModeSettingsKey;
        } else if(activeVehicle->rover()) {
            _txModeSettingsKey = _roverTXModeSettingsKey;
        } else if(activeVehicle->vtol()) {
            _txModeSettingsKey = _vtolTXModeSettingsKey;
        } else if(activeVehicle->sub()) {
            _txModeSettingsKey = _submarineTXModeSettingsKey;
        } else {
161
            _txModeSettingsKey = nullptr;
162 163 164
            qWarning() << "No valid joystick TXmode settings key for selected vehicle";
            return;
        }
165
    } else {
166
        _txModeSettingsKey = nullptr;
167 168
    }
}
169

170 171 172 173
void Joystick::_activeVehicleChanged(Vehicle* activeVehicle)
{
    _updateTXModeSettingsKey(activeVehicle);
    if(activeVehicle) {
174 175 176 177 178 179 180
        QSettings settings;
        settings.beginGroup(_settingsGroup);
        int mode = settings.value(_txModeSettingsKey, activeVehicle->firmwarePlugin()->defaultJoystickTXMode()).toInt();
        setTXMode(mode);
    }
}

Gus Grubba's avatar
Gus Grubba committed
181
void Joystick::_loadSettings()
182
{
183
    QSettings settings;
184
    settings.beginGroup(_settingsGroup);
185 186 187 188
    Vehicle* activeVehicle = _multiVehicleManager->activeVehicle();

    if(_txModeSettingsKey && activeVehicle)
        _transmitterMode = settings.value(_txModeSettingsKey, activeVehicle->firmwarePlugin()->defaultJoystickTXMode()).toInt();
189

190
    settings.beginGroup(_name);
191

192 193
    bool badSettings = false;
    bool convertOk;
194

195
    qCDebug(JoystickLog) << "_loadSettings " << _name;
196

197 198 199 200 201
    _calibrated     = settings.value(_calibratedSettingsKey, false).toBool();
    _exponential    = settings.value(_exponentialSettingsKey, 0).toFloat();
    _accumulator    = settings.value(_accumulatorSettingsKey, false).toBool();
    _deadband       = settings.value(_deadbandSettingsKey, false).toBool();
    _frequency      = settings.value(_frequencySettingsKey, 25.0f).toFloat();
202
    _circleCorrection = settings.value(_circleCorrectionSettingsKey, false).toBool();
Gus Grubba's avatar
Gus Grubba committed
203
    _gimbalEnabled  = settings.value(_gimbalSettingsKey, false).toBool();
204

205
    _throttleMode   = static_cast<ThrottleMode_t>(settings.value(_throttleModeSettingsKey, ThrottleModeDownZero).toInt(&convertOk));
206
    badSettings |= !convertOk;
207

208
    qCDebug(JoystickLog) << "_loadSettings calibrated:txmode:throttlemode:exponential:deadband:badsettings" << _calibrated << _transmitterMode << _throttleMode << _exponential << _deadband << badSettings;
209

210 211 212 213
    QString minTpl      ("Axis%1Min");
    QString maxTpl      ("Axis%1Max");
    QString trimTpl     ("Axis%1Trim");
    QString revTpl      ("Axis%1Rev");
214
    QString deadbndTpl  ("Axis%1Deadbnd");
215

216
    for (int axis = 0; axis < _axisCount; axis++) {
217
        Calibration_t* calibration = &_rgCalibration[axis];
218

219 220
        calibration->center = settings.value(trimTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;
221

222 223
        calibration->min = settings.value(minTpl.arg(axis), -32768).toInt(&convertOk);
        badSettings |= !convertOk;
224

225
        calibration->max = settings.value(maxTpl.arg(axis), 32767).toInt(&convertOk);
226
        badSettings |= !convertOk;
227

228 229 230
        calibration->deadband = settings.value(deadbndTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;

231
        calibration->reversed = settings.value(revTpl.arg(axis), false).toBool();
232

233
        qCDebug(JoystickLog) << "_loadSettings axis:min:max:trim:reversed:deadband:badsettings" << axis << calibration->min << calibration->max << calibration->center << calibration->reversed << calibration->deadband << badSettings;
234
    }
235

Gus Grubba's avatar
Gus Grubba committed
236
    for (int function = 0; function < maxFunction; function++) {
237 238
        int functionAxis;
        functionAxis = settings.value(_rgFunctionSettingsKey[function], -1).toInt(&convertOk);
Gus Grubba's avatar
Gus Grubba committed
239 240 241 242
        badSettings |= !convertOk || (functionAxis == -1) || (functionAxis >= _axisCount);
        if(functionAxis < _axisCount) {
            _rgFunctionAxis[function] = functionAxis;
        }
243 244
        qCDebug(JoystickLog) << "_loadSettings function:axis:badsettings" << function << functionAxis << badSettings;
    }
245

246 247 248 249
    // FunctionAxis mappings are always stored in TX mode 2
    // Remap to stored TX mode in settings
    _remapAxes(2, _transmitterMode, _rgFunctionAxis);

Don Gagne's avatar
Don Gagne committed
250
    for (int button=0; button<_totalButtonCount; button++) {
251
        _rgButtonActions << settings.value(QString(_buttonActionSettingsKey).arg(button), QString()).toString();
Don Gagne's avatar
Don Gagne committed
252
        qCDebug(JoystickLog) << "_loadSettings button:action" << button << _rgButtonActions[button];
253
    }
254

255 256 257 258 259 260
    if (badSettings) {
        _calibrated = false;
        settings.setValue(_calibratedSettingsKey, false);
    }
}

Gus Grubba's avatar
Gus Grubba committed
261
void Joystick::_saveSettings()
262 263
{
    QSettings settings;
264

265
    settings.beginGroup(_settingsGroup);
266 267 268

    // Transmitter mode is static
    // Save the mode we are using
269 270
    if(_txModeSettingsKey)
        settings.setValue(_txModeSettingsKey, _transmitterMode);
271

272
    settings.beginGroup(_name);
273

274 275 276 277 278
    settings.setValue(_calibratedSettingsKey,   _calibrated);
    settings.setValue(_exponentialSettingsKey,  _exponential);
    settings.setValue(_accumulatorSettingsKey,  _accumulator);
    settings.setValue(_deadbandSettingsKey,     _deadband);
    settings.setValue(_frequencySettingsKey,    _frequency);
279
    settings.setValue(_throttleModeSettingsKey, _throttleMode);
Gus Grubba's avatar
Gus Grubba committed
280
    settings.setValue(_gimbalSettingsKey,       _gimbalEnabled);
281
    settings.setValue(_circleCorrectionSettingsKey, _circleCorrection);
282

283
    qCDebug(JoystickLog) << "_saveSettings calibrated:throttlemode:deadband:txmode" << _calibrated << _throttleMode << _deadband << _circleCorrection << _transmitterMode;
284

285 286 287 288
    QString minTpl      ("Axis%1Min");
    QString maxTpl      ("Axis%1Max");
    QString trimTpl     ("Axis%1Trim");
    QString revTpl      ("Axis%1Rev");
289
    QString deadbndTpl  ("Axis%1Deadbnd");
290

291
    for (int axis = 0; axis < _axisCount; axis++) {
292 293 294 295 296
        Calibration_t* calibration = &_rgCalibration[axis];
        settings.setValue(trimTpl.arg(axis), calibration->center);
        settings.setValue(minTpl.arg(axis), calibration->min);
        settings.setValue(maxTpl.arg(axis), calibration->max);
        settings.setValue(revTpl.arg(axis), calibration->reversed);
297
        settings.setValue(deadbndTpl.arg(axis), calibration->deadband);
298
        qCDebug(JoystickLog) << "_saveSettings name:axis:min:max:trim:reversed:deadband"
299 300 301 302 303
                                << _name
                                << axis
                                << calibration->min
                                << calibration->max
                                << calibration->center
304 305
                                << calibration->reversed
                                << calibration->deadband;
306
    }
307

308 309 310 311 312
    // Always save function Axis mappings in TX Mode 2
    // Write mode 2 mappings without changing mapping currently in use
    int temp[maxFunction];
    _remapAxes(_transmitterMode, 2, temp);

313
    for (int function = 0; function < maxFunction; function++) {
314
        settings.setValue(_rgFunctionSettingsKey[function], temp[function]);
315 316
        qCDebug(JoystickLog) << "_saveSettings name:function:axis" << _name << function << _rgFunctionSettingsKey[function];
    }
317

318
    for (int button = 0; button < _totalButtonCount; button++) {
319 320 321 322 323
        settings.setValue(QString(_buttonActionSettingsKey).arg(button), _rgButtonActions[button]);
        qCDebug(JoystickLog) << "_saveSettings button:action" << button << _rgButtonActions[button];
    }
}

324 325
// Relative mappings of axis functions between different TX modes
int Joystick::_mapFunctionMode(int mode, int function) {
326 327 328 329 330
    static const int mapping[][6] = {
        { yawFunction, pitchFunction, rollFunction, throttleFunction, gimbalPitchFunction, gimbalYawFunction },
        { yawFunction, throttleFunction, rollFunction, pitchFunction, gimbalPitchFunction, gimbalYawFunction },
        { rollFunction, pitchFunction, yawFunction, throttleFunction, gimbalPitchFunction, gimbalYawFunction },
        { rollFunction, throttleFunction, yawFunction, pitchFunction, gimbalPitchFunction, gimbalYawFunction }};
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    return mapping[mode-1][function];
}

// Remap current axis functions from current TX mode to new TX mode
void Joystick::_remapAxes(int currentMode, int newMode, int (&newMapping)[maxFunction]) {
    int temp[maxFunction];

    for(int function = 0; function < maxFunction; function++) {
        temp[_mapFunctionMode(newMode, function)] = _rgFunctionAxis[_mapFunctionMode(currentMode, function)];
    }

    for(int function = 0; function < maxFunction; function++) {
        newMapping[function] = temp[function];
    }

}

void Joystick::setTXMode(int mode) {
    if(mode > 0 && mode <= 4) {
        _remapAxes(_transmitterMode, mode, _rgFunctionAxis);
        _transmitterMode = mode;
        _saveSettings();
    } else {
        qCWarning(JoystickLog) << "Invalid mode:" << mode;
    }
}

358
/// Adjust the raw axis value to the -1:1 range given calibration information
359
float Joystick::_adjustRange(int value, Calibration_t calibration, bool withDeadbands)
360 361 362 363
{
    float valueNormalized;
    float axisLength;
    float axisBasis;
364

365 366 367 368 369 370 371 372 373
    if (value > calibration.center) {
        axisBasis = 1.0f;
        valueNormalized = value - calibration.center;
        axisLength =  calibration.max - calibration.center;
    } else {
        axisBasis = -1.0f;
        valueNormalized = calibration.center - value;
        axisLength =  calibration.center - calibration.min;
    }
374

375 376
    float axisPercent;

377
    if (withDeadbands) {
378 379 380 381 382 383 384
        if (valueNormalized>calibration.deadband) {
            axisPercent = (valueNormalized - calibration.deadband) / (axisLength - calibration.deadband);
        } else if (valueNormalized<-calibration.deadband) {
            axisPercent = (valueNormalized + calibration.deadband) / (axisLength - calibration.deadband);
        } else {
            axisPercent = 0.f;
        }
385 386 387
    }
    else {
        axisPercent = valueNormalized / axisLength;
388
    }
389

390
    float correctedValue = axisBasis * axisPercent;
391

392 393 394
    if (calibration.reversed) {
        correctedValue *= -1.0f;
    }
395

396
#if 0
397
    qCDebug(JoystickLog) << "_adjustRange corrected:value:min:max:center:reversed:deadband:basis:normalized:length"
398 399 400 401 402
                            << correctedValue
                            << value
                            << calibration.min
                            << calibration.max
                            << calibration.center
403
                            << calibration.reversed
404
                            << calibration.deadband
405 406 407 408 409
                            << axisBasis
                            << valueNormalized
                            << axisLength;
#endif

410
    return std::max(-1.0f, std::min(correctedValue, 1.0f));
411 412 413
}


Gus Grubba's avatar
Gus Grubba committed
414
void Joystick::run()
415
{
Gregory Dymarek's avatar
Gregory Dymarek committed
416
    _open();
417

418
    while (!_exitThread) {
Gregory Dymarek's avatar
Gregory Dymarek committed
419
    _update();
420 421

        // Update axes
Gus Grubba's avatar
Gus Grubba committed
422
        for (int axisIndex = 0; axisIndex < _axisCount; axisIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
423
            int newAxisValue = _getAxis(axisIndex);
424 425 426 427
            // Calibration code requires signal to be emitted even if value hasn't changed
            _rgAxisValues[axisIndex] = newAxisValue;
            emit rawAxisValueChanged(axisIndex, newAxisValue);
        }
428

429
        // Update buttons
Gus Grubba's avatar
Gus Grubba committed
430
        for (int buttonIndex = 0; buttonIndex < _buttonCount; buttonIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
431
            bool newButtonValue = _getButton(buttonIndex);
Gus Grubba's avatar
Gus Grubba committed
432 433 434 435 436
            if (newButtonValue && _rgButtonValues[buttonIndex] == BUTTON_UP) {
                _rgButtonValues[buttonIndex] = BUTTON_DOWN;
                emit rawButtonPressedChanged(buttonIndex, newButtonValue);
            } else if (!newButtonValue && _rgButtonValues[buttonIndex] != BUTTON_UP) {
                _rgButtonValues[buttonIndex] = BUTTON_UP;
437 438 439
                emit rawButtonPressedChanged(buttonIndex, newButtonValue);
            }
        }
440 441 442

        // Update hat - append hat buttons to the end of the normal button list
        int numHatButtons = 4;
Gus Grubba's avatar
Gus Grubba committed
443 444
        for (int hatIndex = 0; hatIndex < _hatCount; hatIndex++) {
            for (int hatButtonIndex = 0; hatButtonIndex<numHatButtons; hatButtonIndex++) {
445 446 447
                // Create new index value that includes the normal button list
                int rgButtonValueIndex = hatIndex*numHatButtons + hatButtonIndex + _buttonCount;
                // Get hat value from joystick
Gus Grubba's avatar
Gus Grubba committed
448 449 450 451 452 453
                bool newButtonValue = _getHat(hatIndex, hatButtonIndex);
                if (newButtonValue && _rgButtonValues[rgButtonValueIndex] == BUTTON_UP) {
                    _rgButtonValues[rgButtonValueIndex] = BUTTON_DOWN;
                    emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue);
                } else if (!newButtonValue && _rgButtonValues[rgButtonValueIndex] != BUTTON_UP) {
                    _rgButtonValues[rgButtonValueIndex] = BUTTON_UP;
454 455 456 457
                    emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue);
                }
            }
        }
458

459
        if (_activeVehicle->joystickEnabled() && !_calibrationMode && _calibrated) {
460
            int     axis = _rgFunctionAxis[rollFunction];
Gus Grubba's avatar
Gus Grubba committed
461
            float   roll = _adjustRange(_rgAxisValues[axis],    _rgCalibration[axis], _deadband);
462

463
                    axis = _rgFunctionAxis[pitchFunction];
Gus Grubba's avatar
Gus Grubba committed
464
            float   pitch = _adjustRange(_rgAxisValues[axis],   _rgCalibration[axis], _deadband);
465

466
                    axis = _rgFunctionAxis[yawFunction];
Gus Grubba's avatar
Gus Grubba committed
467
            float   yaw = _adjustRange(_rgAxisValues[axis],     _rgCalibration[axis],_deadband);
468

469
                    axis = _rgFunctionAxis[throttleFunction];
Gus Grubba's avatar
Gus Grubba committed
470
            float   throttle = _adjustRange(_rgAxisValues[axis],_rgCalibration[axis], _throttleMode==ThrottleModeDownZero?false:_deadband);
471

Gus Grubba's avatar
Gus Grubba committed
472 473
            float   gimbalPitch = 0.0f;
            float   gimbalYaw   = 0.0f;
Gus Grubba's avatar
Gus Grubba committed
474

Gus Grubba's avatar
Gus Grubba committed
475 476 477 478 479 480 481 482 483
            if(_axisCount > 4) {
                axis = _rgFunctionAxis[gimbalPitchFunction];
                gimbalPitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis],_deadband);
            }

            if(_axisCount > 5) {
                axis = _rgFunctionAxis[gimbalYawFunction];
                gimbalYaw = _adjustRange(_rgAxisValues[axis],   _rgCalibration[axis],_deadband);
            }
Gus Grubba's avatar
Gus Grubba committed
484

Gus Grubba's avatar
Gus Grubba committed
485
            if (_accumulator) {
486
                static float throttle_accu = 0.f;
Gus Grubba's avatar
Gus Grubba committed
487
                throttle_accu += throttle * (40 / 1000.f); //for throttle to change from min to max it will take 1000ms (40ms is a loop time)
488 489 490 491
                throttle_accu = std::max(static_cast<float>(-1.f), std::min(throttle_accu, static_cast<float>(1.f)));
                throttle = throttle_accu;
            }

Gus Grubba's avatar
Gus Grubba committed
492
            if (_circleCorrection) {
Gus Grubba's avatar
Gus Grubba committed
493 494 495 496
                float roll_limited      = std::max(static_cast<float>(-M_PI_4), std::min(roll,      static_cast<float>(M_PI_4)));
                float pitch_limited     = std::max(static_cast<float>(-M_PI_4), std::min(pitch,     static_cast<float>(M_PI_4)));
                float yaw_limited       = std::max(static_cast<float>(-M_PI_4), std::min(yaw,       static_cast<float>(M_PI_4)));
                float throttle_limited  = std::max(static_cast<float>(-M_PI_4), std::min(throttle,  static_cast<float>(M_PI_4)));
497 498

                // Map from unit circle to linear range and limit
Gus Grubba's avatar
Gus Grubba committed
499 500 501
                roll =      std::max(-1.0f, std::min(tanf(asinf(roll_limited)),     1.0f));
                pitch =     std::max(-1.0f, std::min(tanf(asinf(pitch_limited)),    1.0f));
                yaw =       std::max(-1.0f, std::min(tanf(asinf(yaw_limited)),      1.0f));
502 503 504
                throttle =  std::max(-1.0f, std::min(tanf(asinf(throttle_limited)), 1.0f));
            }

Gus Grubba's avatar
Gus Grubba committed
505
            if ( _exponential < -0.01f) {
506
                // Exponential (0% to -50% range like most RC radios)
Gus Grubba's avatar
Gus Grubba committed
507
                // _exponential is set by a slider in joystickConfigAdvanced.qml
508
                // Calculate new RPY with exponential applied
Gus Grubba's avatar
Gus Grubba committed
509
                roll =      -_exponential*powf(roll, 3) + (1+_exponential)*roll;
510
                pitch =     -_exponential*powf(pitch,3) + (1+_exponential)*pitch;
Gus Grubba's avatar
Gus Grubba committed
511
                yaw =       -_exponential*powf(yaw,  3) + (1+_exponential)*yaw;
512
            }
513

514
            // Adjust throttle to 0:1 range
515
            if (_throttleMode == ThrottleModeCenterZero && _activeVehicle->supportsThrottleModeCenterZero()) {
516
                if (!_activeVehicle->supportsNegativeThrust() || !_negativeThrust) {
517 518
                    throttle = std::max(0.0f, throttle);
                }
519
            } else {
520 521
                throttle = (throttle + 1.0f) / 2.0f;
            }
522

Gus Grubba's avatar
Gus Grubba committed
523
            //-- Process button press
Gus Grubba's avatar
Gus Grubba committed
524
            for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) {
Gus Grubba's avatar
Gus Grubba committed
525 526 527 528 529 530 531 532 533
                //-- This button just went down
                if(_rgButtonValues[buttonIndex] == BUTTON_DOWN) {
                    //-- Flag it as processed
                    _rgButtonValues[buttonIndex] = BUTTON_REPEAT;
                    //-- Process button
                    QString buttonAction =_rgButtonActions[buttonIndex];
                    qCDebug(JoystickLog) << "button triggered" << buttonIndex << buttonAction;
                    if (!buttonAction.isEmpty()) {
                        _buttonAction(buttonAction);
534
                    }
Gus Grubba's avatar
Gus Grubba committed
535 536
                }
            }
537

Gus Grubba's avatar
Gus Grubba committed
538 539 540
            // Set up button bitmap
            quint64 buttonPressedBits = 0;  // Buttons pressed for manualControl signal
            for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) {
Gus Grubba's avatar
Gus Grubba committed
541
                quint64 buttonBit = static_cast<quint64>(1LL << buttonIndex);
Gus Grubba's avatar
Gus Grubba committed
542
                if (_rgButtonValues[buttonIndex] != BUTTON_UP) {
543
                    // Mark the button as pressed as long as its pressed
544
                    buttonPressedBits |= buttonBit;
545 546
                }
            }
547

Gus Grubba's avatar
Gus Grubba committed
548
            qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle:gimbalPitch:gimbalYaw" << name() << roll << -pitch << yaw << throttle << gimbalPitch << gimbalYaw;
Gus Grubba's avatar
Gus Grubba committed
549 550 551 552 553 554 555 556
            // NOTE: The buttonPressedBits going to MANUAL_CONTROL are currently used by ArduSub (and it only handles 16 bits)
            uint16_t shortButtons = static_cast<uint16_t>(buttonPressedBits & 0xFFFF);
            emit manualControl(roll, -pitch, yaw, throttle, shortButtons, _activeVehicle->joystickMode());
            if(_activeVehicle && _axisCount > 4 && _gimbalEnabled) {
                //-- TODO: There is nothing consuming this as there are no messages to handle gimbal
                //   the way MANUAL_CONTROL handles the other channels.
                emit manualControlGimbal((gimbalPitch + 1.0f) / 2.0f * 90.0f, gimbalYaw * 180.0f);
            }
557
        }
558

559
        // Sleep. Update rate of joystick is by default 25 Hz
Gus Grubba's avatar
Gus Grubba committed
560
        unsigned long mswait = static_cast<unsigned long>(1000.0f / _frequency);
561
        QGC::SLEEP::msleep(mswait);
562
    }
563

Gregory Dymarek's avatar
Gregory Dymarek committed
564
    _close();
565 566
}

567
void Joystick::startPolling(Vehicle* vehicle)
568
{
569 570 571 572 573
    if (vehicle) {
        // If a vehicle is connected, disconnect it
        if (_activeVehicle) {
            UAS* uas = _activeVehicle->uas();
            disconnect(this, &Joystick::manualControl, uas, &UAS::setExternalControlSetpoint);
Gus Grubba's avatar
Gus Grubba committed
574 575 576 577 578 579
            disconnect(this, &Joystick::setArmed,           _activeVehicle, &Vehicle::setArmed);
            disconnect(this, &Joystick::setVtolInFwdFlight, _activeVehicle, &Vehicle::setVtolInFwdFlight);
            disconnect(this, &Joystick::setFlightMode,      _activeVehicle, &Vehicle::setFlightMode);
            disconnect(this, &Joystick::gimbalPitchStep,    _activeVehicle, &Vehicle::gimbalPitchStep);
            disconnect(this, &Joystick::gimbalYawStep,      _activeVehicle, &Vehicle::gimbalYawStep);
            disconnect(this, &Joystick::centerGimbal,       _activeVehicle, &Vehicle::centerGimbal);
580
        }
581
        // Always set up the new vehicle
582
        _activeVehicle = vehicle;
583 584 585 586
        // If joystick is not calibrated, disable it
        if ( !_calibrated ) {
            vehicle->setJoystickEnabled(false);
        }
Jacob Walser's avatar
Jacob Walser committed
587 588
        // Update qml in case of joystick transition
        emit calibratedChanged(_calibrated);
589 590 591 592 593
        // Only connect the new vehicle if it wants joystick data
        if (vehicle->joystickEnabled()) {
            _pollingStartedForCalibration = false;
            UAS* uas = _activeVehicle->uas();
            connect(this, &Joystick::manualControl, uas, &UAS::setExternalControlSetpoint);
Gus Grubba's avatar
Gus Grubba committed
594 595 596 597 598 599
            connect(this, &Joystick::setArmed,           _activeVehicle, &Vehicle::setArmed);
            connect(this, &Joystick::setVtolInFwdFlight, _activeVehicle, &Vehicle::setVtolInFwdFlight);
            connect(this, &Joystick::setFlightMode,      _activeVehicle, &Vehicle::setFlightMode);
            connect(this, &Joystick::gimbalPitchStep,    _activeVehicle, &Vehicle::gimbalPitchStep);
            connect(this, &Joystick::gimbalYawStep,      _activeVehicle, &Vehicle::gimbalYawStep);
            connect(this, &Joystick::centerGimbal,       _activeVehicle, &Vehicle::centerGimbal);
600 601 602 603 604
            // FIXME: ****
            //connect(this, &Joystick::buttonActionTriggered, uas, &UAS::triggerAction);
        }
    }
    if (!isRunning()) {
605 606
        _exitThread = false;
        start();
607 608 609 610 611
    }
}

void Joystick::stopPolling(void)
{
612
    if (isRunning()) {
613 614
        if (_activeVehicle && _activeVehicle->joystickEnabled()) {
            UAS* uas = _activeVehicle->uas();
Jacob Walser's avatar
Jacob Walser committed
615 616
            // Neutral attitude controls
            // emit manualControl(0, 0, 0, 0.5, 0, _activeVehicle->joystickMode());
Gus Grubba's avatar
Gus Grubba committed
617 618 619 620 621 622 623
            disconnect(this, &Joystick::manualControl, uas, &UAS::setExternalControlSetpoint);
            disconnect(this, &Joystick::setArmed,           _activeVehicle, &Vehicle::setArmed);
            disconnect(this, &Joystick::setVtolInFwdFlight, _activeVehicle, &Vehicle::setVtolInFwdFlight);
            disconnect(this, &Joystick::setFlightMode,      _activeVehicle, &Vehicle::setFlightMode);
            disconnect(this, &Joystick::gimbalPitchStep,    _activeVehicle, &Vehicle::gimbalPitchStep);
            disconnect(this, &Joystick::gimbalYawStep,      _activeVehicle, &Vehicle::gimbalYawStep);
            disconnect(this, &Joystick::centerGimbal,       _activeVehicle, &Vehicle::centerGimbal);
624
        }
Don Gagne's avatar
Don Gagne committed
625 626
        // FIXME: ****
        //disconnect(this, &Joystick::buttonActionTriggered,  uas, &UAS::triggerAction);
627
        _exitThread = true;
Jacob Walser's avatar
Jacob Walser committed
628
    }
629 630 631 632
}

void Joystick::setCalibration(int axis, Calibration_t& calibration)
{
633
    if (!_validAxis(axis)) {
634 635 636 637 638 639 640 641 642 643 644
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
    _calibrated = true;
    _rgCalibration[axis] = calibration;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

Joystick::Calibration_t Joystick::getCalibration(int axis)
{
645
    if (!_validAxis(axis)) {
646 647
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
    }
648

649 650 651 652 653
    return _rgCalibration[axis];
}

void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{
654
    if (!_validAxis(axis)) {
655 656 657 658 659 660 661 662 663 664 665
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
    _calibrated = true;
    _rgFunctionAxis[function] = axis;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

int Joystick::getFunctionAxis(AxisFunction_t function)
{
Gus Grubba's avatar
Gus Grubba committed
666
    if (static_cast<int>(function) < 0 || function >= maxFunction) {
667 668 669 670 671
        qCWarning(JoystickLog) << "Invalid function" << function;
    }
    return _rgFunctionAxis[function];
}

Gus Grubba's avatar
Gus Grubba committed
672
QStringList Joystick::actions()
673 674
{
    QStringList list;
Gus Grubba's avatar
Gus Grubba committed
675
    list << _buttonActionArm << _buttonActionDisarm << _buttonActionToggleArm;
676 677 678
    if (_activeVehicle) {
        list << _activeVehicle->flightModes();
    }
679
    list << _buttonActionVTOLFixedWing << _buttonActionVTOLMultiRotor;
680 681 682
    list << _buttonActionZoomIn << _buttonActionZoomOut;
    list << _buttonActionNextStream << _buttonActionPreviousStream;
    list << _buttonActionNextCamera << _buttonActionPreviousCamera;
Gus Grubba's avatar
Gus Grubba committed
683 684 685 686
    list << _buttonActionTriggerCamera;
    list << _buttonActionStartVideoRecord;
    list << _buttonActionStopVideoRecord;
    list << _buttonActionToggleVideoRecord;
Gus Grubba's avatar
Gus Grubba committed
687 688 689 690 691
    list << _buttonActionGimbalDown;
    list << _buttonActionGimbalUp;
    list << _buttonActionGimbalLeft;
    list << _buttonActionGimbalRight;
    list << _buttonActionGimbalCenter;
692 693 694
    return list;
}

Don Gagne's avatar
Don Gagne committed
695
void Joystick::setButtonAction(int button, const QString& action)
696
{
697
    if (!_validButton(button)) {
698 699 700
        qCWarning(JoystickLog) << "Invalid button index" << button;
        return;
    }
701

Don Gagne's avatar
Don Gagne committed
702
    qDebug() << "setButtonAction" << action;
703

704 705 706 707 708
    _rgButtonActions[button] = action;
    _saveSettings();
    emit buttonActionsChanged(buttonActions());
}

Don Gagne's avatar
Don Gagne committed
709
QString Joystick::getButtonAction(int button)
710
{
711
    if (!_validButton(button)) {
712 713
        qCWarning(JoystickLog) << "Invalid button index" << button;
    }
714

715 716 717
    return _rgButtonActions[button];
}

Gus Grubba's avatar
Gus Grubba committed
718
QVariantList Joystick::buttonActions()
719 720
{
    QVariantList list;
Don Gagne's avatar
Don Gagne committed
721
    for (int button=0; button<_totalButtonCount; button++) {
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
        list += QVariant::fromValue(_rgButtonActions[button]);
    }
    return list;
}

int Joystick::throttleMode(void)
{
    return _throttleMode;
}

void Joystick::setThrottleMode(int mode)
{
    if (mode < 0 || mode >= ThrottleModeMax) {
        qCWarning(JoystickLog) << "Invalid throttle mode" << mode;
        return;
    }
Gus Grubba's avatar
Gus Grubba committed
738
    _throttleMode = static_cast<ThrottleMode_t>(mode);
739 740 741
    if (_throttleMode == ThrottleModeDownZero) {
        setAccumulator(false);
    }
742 743 744 745
    _saveSettings();
    emit throttleModeChanged(_throttleMode);
}

746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
bool Joystick::negativeThrust(void)
{
    return _negativeThrust;
}

void Joystick::setNegativeThrust(bool allowNegative)
{
    if (_negativeThrust == allowNegative) {
        return;
    }
    _negativeThrust = allowNegative;
    _saveSettings();
    emit negativeThrustChanged(_negativeThrust);
}

761
float Joystick::exponential(void)
762 763 764 765
{
    return _exponential;
}

766
void Joystick::setExponential(float expo)
767 768 769 770 771 772
{
    _exponential = expo;
    _saveSettings();
    emit exponentialChanged(_exponential);
}

773 774 775 776 777 778 779 780 781 782 783 784
bool Joystick::accumulator(void)
{
    return _accumulator;
}

void Joystick::setAccumulator(bool accu)
{
    _accumulator = accu;
    _saveSettings();
    emit accumulatorChanged(_accumulator);
}

Gregory Dymarek's avatar
Gregory Dymarek committed
785 786 787 788 789 790 791 792 793 794 795
bool Joystick::deadband(void)
{
    return _deadband;
}

void Joystick::setDeadband(bool deadband)
{
    _deadband = deadband;
    _saveSettings();
}

796 797 798 799 800 801 802 803 804 805 806 807
bool Joystick::circleCorrection(void)
{
    return _circleCorrection;
}

void Joystick::setCircleCorrection(bool circleCorrection)
{
    _circleCorrection = circleCorrection;
    _saveSettings();
    emit circleCorrectionChanged(_circleCorrection);
}

808 809 810 811 812
float Joystick::frequency()
{
    return _frequency;
}

Gus Grubba's avatar
Gus Grubba committed
813 814 815 816 817 818 819
void Joystick::setGimbalEnabled(bool set)
{
    _gimbalEnabled = set;
    _saveSettings();
    emit gimbalEnabledChanged();
}

820 821 822 823 824 825 826 827 828 829
void Joystick::setFrequency(float val)
{
    //-- Arbitrary limits
    if(val < 0.25f)  val = 0.25f;
    if(val > 100.0f) val = 100.0f;
    _frequency = val;
    _saveSettings();
    emit frequencyChanged();
}

830
void Joystick::setCalibrationMode(bool calibrating)
831
{
832 833
    _calibrationMode = calibrating;
    if (calibrating && !isRunning()) {
834
        _pollingStartedForCalibration = true;
835
        startPolling(_multiVehicleManager->activeVehicle());
836
    }
837 838
    else if (_pollingStartedForCalibration) {
        stopPolling();
Don Gagne's avatar
Don Gagne committed
839
    }
840 841
}

842

Don Gagne's avatar
Don Gagne committed
843 844
void Joystick::_buttonAction(const QString& action)
{
845 846 847
    if (!_activeVehicle || !_activeVehicle->joystickEnabled()) {
        return;
    }
848
    if (action == _buttonActionArm) {
Gus Grubba's avatar
Gus Grubba committed
849
        emit setArmed(true);
850
    } else if (action == _buttonActionDisarm) {
Gus Grubba's avatar
Gus Grubba committed
851
        emit setArmed(false);
Gus Grubba's avatar
Gus Grubba committed
852
    } else if (action == _buttonActionToggleArm) {
Gus Grubba's avatar
Gus Grubba committed
853
        emit setArmed(!_activeVehicle->armed());
854
    } else if (action == _buttonActionVTOLFixedWing) {
Gus Grubba's avatar
Gus Grubba committed
855
        emit setVtolInFwdFlight(true);
856
    } else if (action == _buttonActionVTOLMultiRotor) {
Gus Grubba's avatar
Gus Grubba committed
857
        emit setVtolInFwdFlight(false);
858
    } else if (_activeVehicle->flightModes().contains(action)) {
Gus Grubba's avatar
Gus Grubba committed
859
        emit setFlightMode(action);
860 861 862 863 864 865
    } else if(action == _buttonActionZoomIn || action == _buttonActionZoomOut) {
        emit stepZoom(action == _buttonActionZoomIn ? 1 : -1);
    } else if(action == _buttonActionNextStream || action == _buttonActionPreviousStream) {
        emit stepStream(action == _buttonActionNextStream ? 1 : -1);
    } else if(action == _buttonActionNextCamera || action == _buttonActionPreviousCamera) {
        emit stepCamera(action == _buttonActionNextCamera ? 1 : -1);
Gus Grubba's avatar
Gus Grubba committed
866 867 868 869 870 871 872 873
    } else if(action == _buttonActionTriggerCamera) {
        emit triggerCamera();
    } else if(action == _buttonActionStartVideoRecord) {
        emit startVideoRecord();
    } else if(action == _buttonActionStopVideoRecord) {
        emit stopVideoRecord();
    } else if(action == _buttonActionToggleVideoRecord) {
        emit toggleVideoRecord();
Gus Grubba's avatar
Gus Grubba committed
874
    } else if(action == _buttonActionGimbalUp) {
Gus Grubba's avatar
Gus Grubba committed
875
        emit gimbalPitchStep(1);
Gus Grubba's avatar
Gus Grubba committed
876
    } else if(action == _buttonActionGimbalDown) {
Gus Grubba's avatar
Gus Grubba committed
877
        emit gimbalPitchStep(-1);
Gus Grubba's avatar
Gus Grubba committed
878
    } else if(action == _buttonActionGimbalLeft) {
Gus Grubba's avatar
Gus Grubba committed
879
        emit gimbalYawStep(-1);
Gus Grubba's avatar
Gus Grubba committed
880
    } else if(action == _buttonActionGimbalRight) {
Gus Grubba's avatar
Gus Grubba committed
881
        emit gimbalYawStep(1);
Gus Grubba's avatar
Gus Grubba committed
882
    } else if(action == _buttonActionGimbalCenter) {
Gus Grubba's avatar
Gus Grubba committed
883
        emit centerGimbal();
Don Gagne's avatar
Don Gagne committed
884 885 886 887 888
    } else {
        qCDebug(JoystickLog) << "_buttonAction unknown action:" << action;
    }
}

889 890 891 892 893 894 895
bool Joystick::_validAxis(int axis)
{
    return axis >= 0 && axis < _axisCount;
}

bool Joystick::_validButton(int button)
{
896
    return button >= 0 && button < _totalButtonCount;
897 898
}