Joystick.cc 18.3 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 15 16 17 18

#include "Joystick.h"
#include "QGC.h"
#include "AutoPilotPlugin.h"
#include "UAS.h"

#include <QSettings>

QGC_LOGGING_CATEGORY(JoystickLog, "JoystickLog")
19
QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog")
20 21 22

const char* Joystick::_settingsGroup =              "Joysticks";
const char* Joystick::_calibratedSettingsKey =      "Calibrated";
Don Gagne's avatar
Don Gagne committed
23
const char* Joystick::_buttonActionSettingsKey =    "ButtonActionName%1";
24 25 26 27 28 29 30 31 32
const char* Joystick::_throttleModeSettingsKey =    "ThrottleMode";

const char* Joystick::_rgFunctionSettingsKey[Joystick::maxFunction] = {
    "RollAxis",
    "PitchAxis",
    "YawAxis",
    "ThrottleAxis"
};

33
Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager)
Gregory Dymarek's avatar
Gregory Dymarek committed
34
    : _exitThread(false)
35 36 37
    , _name(name)
    , _axisCount(axisCount)
    , _buttonCount(buttonCount)
38 39 40
    , _hatCount(hatCount)
    , _hatButtonCount(4*hatCount)
    , _totalButtonCount(_buttonCount+_hatButtonCount)
Don Gagne's avatar
Don Gagne committed
41
    , _calibrationMode(CalibrationModeOff)
42 43 44 45
    , _rgAxisValues(NULL)
    , _rgCalibration(NULL)
    , _rgButtonValues(NULL)
    , _rgButtonActions(NULL)
46 47
    , _lastButtonBits(0)
    , _throttleMode(ThrottleModeCenterZero)
48 49
    , _activeVehicle(NULL)
    , _pollingStartedForCalibration(false)
50
    , _multiVehicleManager(multiVehicleManager)
51
{
52

53 54
    _rgAxisValues = new int[_axisCount];
    _rgCalibration = new Calibration_t[_axisCount];
55 56
    _rgButtonValues = new bool[_totalButtonCount];
    _rgButtonActions = new QString[_totalButtonCount];
57 58

    for (int i=0; i<_axisCount; i++) {
59 60
        _rgAxisValues[i] = 0;
    }
61
    for (int i=0; i<_totalButtonCount; i++) {
62 63 64 65 66 67 68 69
        _rgButtonValues[i] = false;
    }
    
    _loadSettings();
}

Joystick::~Joystick()
{
70 71 72 73
    delete _rgAxisValues;
    delete _rgCalibration;
    delete _rgButtonValues;
    delete _rgButtonActions;
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
}

void Joystick::_loadSettings(void)
{
    QSettings   settings;
    
    settings.beginGroup(_settingsGroup);
    settings.beginGroup(_name);
    
    bool badSettings = false;
    bool convertOk;
    
    qCDebug(JoystickLog) << "_loadSettings " << _name;
    
    _calibrated = settings.value(_calibratedSettingsKey, false).toBool();
    
    _throttleMode = (ThrottleMode_t)settings.value(_throttleModeSettingsKey, ThrottleModeCenterZero).toInt(&convertOk);
    badSettings |= !convertOk;
    
93
    qCDebug(JoystickLog) << "_loadSettings calibrated:throttlemode:badsettings" << _calibrated << _throttleMode << badSettings;
94 95 96 97 98 99
    
    QString minTpl  ("Axis%1Min");
    QString maxTpl  ("Axis%1Max");
    QString trimTpl ("Axis%1Trim");
    QString revTpl  ("Axis%1Rev");
    
100
    for (int axis=0; axis<_axisCount; axis++) {
101 102 103 104 105 106 107 108
        Calibration_t* calibration = &_rgCalibration[axis];
        
        calibration->center = settings.value(trimTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;
        
        calibration->min = settings.value(minTpl.arg(axis), -32768).toInt(&convertOk);
        badSettings |= !convertOk;
        
109
        calibration->max = settings.value(maxTpl.arg(axis), 32767).toInt(&convertOk);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        badSettings |= !convertOk;
        
        calibration->reversed = settings.value(revTpl.arg(axis), false).toBool();
        
        qCDebug(JoystickLog) << "_loadSettings axis:min:max:trim:reversed:badsettings" << axis << calibration->min << calibration->max << calibration->center << calibration->reversed << badSettings;
    }
    
    for (int function=0; function<maxFunction; function++) {
        int functionAxis;
        
        functionAxis = settings.value(_rgFunctionSettingsKey[function], -1).toInt(&convertOk);
        badSettings |= !convertOk || (functionAxis == -1);
        
        _rgFunctionAxis[function] = functionAxis;
        
        qCDebug(JoystickLog) << "_loadSettings function:axis:badsettings" << function << functionAxis << badSettings;
    }
    
128
    for (int button=0; button<_buttonCount; button++) {
Don Gagne's avatar
Don Gagne committed
129 130
        _rgButtonActions[button] = settings.value(QString(_buttonActionSettingsKey).arg(button), QString()).toString();        
        qCDebug(JoystickLog) << "_loadSettings button:action" << button << _rgButtonActions[button];
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    }
    
    if (badSettings) {
        _calibrated = false;
        settings.setValue(_calibratedSettingsKey, false);
    }
}

void Joystick::_saveSettings(void)
{
    QSettings settings;
    
    settings.beginGroup(_settingsGroup);
    settings.beginGroup(_name);
    
    settings.setValue(_calibratedSettingsKey, _calibrated);
    settings.setValue(_throttleModeSettingsKey, _throttleMode);
    
149
    qCDebug(JoystickLog) << "_saveSettings calibrated:throttlemode" << _calibrated << _throttleMode;
150 151 152 153 154 155

    QString minTpl  ("Axis%1Min");
    QString maxTpl  ("Axis%1Max");
    QString trimTpl ("Axis%1Trim");
    QString revTpl  ("Axis%1Rev");
    
156
    for (int axis=0; axis<_axisCount; axis++) {
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
        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);
        
        qCDebug(JoystickLog) << "_saveSettings name:axis:min:max:trim:reversed"
                                << _name
                                << axis
                                << calibration->min
                                << calibration->max
                                << calibration->center
                                << calibration->reversed;
    }
    
    for (int function=0; function<maxFunction; function++) {
        settings.setValue(_rgFunctionSettingsKey[function], _rgFunctionAxis[function]);
        qCDebug(JoystickLog) << "_saveSettings name:function:axis" << _name << function << _rgFunctionSettingsKey[function];
    }
    
178
    for (int button=0; button<_buttonCount; button++) {
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
        settings.setValue(QString(_buttonActionSettingsKey).arg(button), _rgButtonActions[button]);
        qCDebug(JoystickLog) << "_saveSettings button:action" << button << _rgButtonActions[button];
    }
}

/// Adjust the raw axis value to the -1:1 range given calibration information
float Joystick::_adjustRange(int value, Calibration_t calibration)
{
    float valueNormalized;
    float axisLength;
    float axisBasis;
    
    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;
    }
    
    float axisPercent = valueNormalized / axisLength;
    
    float correctedValue = axisBasis * axisPercent;
    
    if (calibration.reversed) {
        correctedValue *= -1.0f;
    }
    
#if 0
    qCDebug(JoystickLog) << "_adjustRange corrected:value:min:max:center:reversed:basis:normalized:length"
                            << correctedValue
                            << value
                            << calibration.min
                            << calibration.max
                            << calibration.center
                            << calibration.center
                            << axisBasis
                            << valueNormalized
                            << axisLength;
#endif

222
    return std::max(-1.0f, std::min(correctedValue, 1.0f));
223 224 225 226 227
}


void Joystick::run(void)
{
Gregory Dymarek's avatar
Gregory Dymarek committed
228
    _open();
229 230
    
    while (!_exitThread) {
Gregory Dymarek's avatar
Gregory Dymarek committed
231
    _update();
232 233 234

        // Update axes
        for (int axisIndex=0; axisIndex<_axisCount; axisIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
235
            int newAxisValue = _getAxis(axisIndex);
236 237 238 239 240 241 242
            // Calibration code requires signal to be emitted even if value hasn't changed
            _rgAxisValues[axisIndex] = newAxisValue;
            emit rawAxisValueChanged(axisIndex, newAxisValue);
        }
        
        // Update buttons
        for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
243
            bool newButtonValue = _getButton(buttonIndex);
244 245 246 247 248
            if (newButtonValue != _rgButtonValues[buttonIndex]) {
                _rgButtonValues[buttonIndex] = newButtonValue;
                emit rawButtonPressedChanged(buttonIndex, newButtonValue);
            }
        }
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263

        // Update hat - append hat buttons to the end of the normal button list
        int numHatButtons = 4;
        for (int hatIndex=0; hatIndex<_hatCount; hatIndex++) {
            for (int hatButtonIndex=0; hatButtonIndex<numHatButtons; hatButtonIndex++) {
                // Create new index value that includes the normal button list
                int rgButtonValueIndex = hatIndex*numHatButtons + hatButtonIndex + _buttonCount;
                // Get hat value from joystick
                bool newButtonValue = _getHat(hatIndex,hatButtonIndex);
                if (newButtonValue != _rgButtonValues[rgButtonValueIndex]) {
                    _rgButtonValues[rgButtonValueIndex] = newButtonValue;
                    emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue);
                }
            }
        }
264
        
Don Gagne's avatar
Don Gagne committed
265
        if (_calibrationMode != CalibrationModeCalibrating) {
266 267 268 269 270 271 272 273
            int     axis = _rgFunctionAxis[rollFunction];
            float   roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]);
            
                    axis = _rgFunctionAxis[pitchFunction];
            float   pitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]);
            
                    axis = _rgFunctionAxis[yawFunction];
            float   yaw = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]);
274

275 276 277
                    axis = _rgFunctionAxis[throttleFunction];
            float   throttle = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis]);

278 279 280 281 282
            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)));

283
            // Map from unit circle to linear range and limit
284 285 286 287
            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));
            throttle =  std::max(-1.0f, std::min(tanf(asinf(throttle_limited)), 1.0f));
288 289 290
            
            // Adjust throttle to 0:1 range
            if (_throttleMode == ThrottleModeCenterZero) {
291
                throttle = std::max(0.0f, throttle);
292 293 294 295 296 297 298
            } else {                
                throttle = (throttle + 1.0f) / 2.0f;
            }
            
            // Set up button pressed information
            
            // We only send the buttons the firmwware has reserved
299
            int reservedButtonCount = _activeVehicle->manualControlReservedButtonCount();
300
            if (reservedButtonCount == -1) {
301
                reservedButtonCount = _totalButtonCount;
302 303 304 305 306
            }
            
            quint16 newButtonBits = 0;      // New set of button which are down
            quint16 buttonPressedBits = 0;  // Buttons pressed for manualControl signal
            
307
            for (int buttonIndex=0; buttonIndex<_totalButtonCount; buttonIndex++) {
308 309
                quint16 buttonBit = 1 << buttonIndex;
                
310 311
                if (!_rgButtonValues[buttonIndex]) {
                    // Button up, just record it
312 313 314
                    newButtonBits |= buttonBit;
                } else {
                    if (_lastButtonBits & buttonBit) {
315
                        // Button was up last time through, but is now down which indicates a button press
316 317 318 319
                        qCDebug(JoystickLog) << "button triggered" << buttonIndex;
                        
                        if (buttonIndex >= reservedButtonCount) {
                            // Button is above firmware reserved set
Don Gagne's avatar
Don Gagne committed
320 321 322
                            QString buttonAction =_rgButtonActions[buttonIndex];
                            if (!buttonAction.isEmpty()) {
                                _buttonAction(buttonAction);
323 324 325
                            }
                        }
                    }
326 327

                    // Mark the button as pressed as long as its pressed
328
                    buttonPressedBits |= buttonBit;
329 330 331 332 333
                }
            }
            
            _lastButtonBits = newButtonBits;
            
334
            qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle" << name() << roll << -pitch << yaw << throttle;
335

336
            emit manualControl(roll, -pitch, yaw, throttle, buttonPressedBits, _activeVehicle->joystickMode());
337 338 339 340 341 342
        }
        
        // Sleep, update rate of joystick is approx. 25 Hz (1000 ms / 25 = 40 ms)
        QGC::SLEEP::msleep(40);
    }
    
Gregory Dymarek's avatar
Gregory Dymarek committed
343
    _close();
344 345
}

346
void Joystick::startPolling(Vehicle* vehicle)
347
{
348 349 350 351 352 353
    if (vehicle) {

        // If a vehicle is connected, disconnect it
        if (_activeVehicle) {
            UAS* uas = _activeVehicle->uas();
            disconnect(this, &Joystick::manualControl, uas, &UAS::setExternalControlSetpoint);
354
        }
355 356

        // Always set up the new vehicle
357
        _activeVehicle = vehicle;
358 359 360 361 362 363 364 365 366 367 368 369 370 371

        // 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);
            // FIXME: ****
            //connect(this, &Joystick::buttonActionTriggered, uas, &UAS::triggerAction);
        }
    }


    if (!isRunning()) {
372 373
        _exitThread = false;
        start();
374 375 376 377 378
    }
}

void Joystick::stopPolling(void)
{
379
    if (isRunning()) {
380 381 382 383 384 385

        if (_activeVehicle && _activeVehicle->joystickEnabled()) {
            UAS* uas = _activeVehicle->uas();

            disconnect(this, &Joystick::manualControl,          uas, &UAS::setExternalControlSetpoint);
        }
Don Gagne's avatar
Don Gagne committed
386 387
        // FIXME: ****
        //disconnect(this, &Joystick::buttonActionTriggered,  uas, &UAS::triggerAction);
388 389 390
        
        _exitThread = true;
        }
391 392 393 394
}

void Joystick::setCalibration(int axis, Calibration_t& calibration)
{
395
    if (!_validAxis(axis)) {
396 397 398 399 400 401 402 403 404 405 406 407
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
    
    _calibrated = true;
    _rgCalibration[axis] = calibration;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

Joystick::Calibration_t Joystick::getCalibration(int axis)
{
408
    if (!_validAxis(axis)) {
409 410 411 412 413 414 415 416
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
    }
    
    return _rgCalibration[axis];
}

void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{
417
    if (!_validAxis(axis)) {
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }

    _calibrated = true;
    _rgFunctionAxis[function] = axis;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

int Joystick::getFunctionAxis(AxisFunction_t function)
{
    if (function < 0 || function >= maxFunction) {
        qCWarning(JoystickLog) << "Invalid function" << function;
    }

    return _rgFunctionAxis[function];
}

QStringList Joystick::actions(void)
{
    QStringList list;
Don Gagne's avatar
Don Gagne committed
440 441

    list << "Arm" << "Disarm";
442 443 444 445

    if (_activeVehicle) {
        list << _activeVehicle->flightModes();
    }
446 447 448 449
    
    return list;
}

Don Gagne's avatar
Don Gagne committed
450
void Joystick::setButtonAction(int button, const QString& action)
451
{
452
    if (!_validButton(button)) {
453 454 455 456
        qCWarning(JoystickLog) << "Invalid button index" << button;
        return;
    }
    
Don Gagne's avatar
Don Gagne committed
457 458
    qDebug() << "setButtonAction" << action;
    
459 460 461 462 463
    _rgButtonActions[button] = action;
    _saveSettings();
    emit buttonActionsChanged(buttonActions());
}

Don Gagne's avatar
Don Gagne committed
464
QString Joystick::getButtonAction(int button)
465
{
466
    if (!_validButton(button)) {
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
        qCWarning(JoystickLog) << "Invalid button index" << button;
    }
    
    return _rgButtonActions[button];
}

QVariantList Joystick::buttonActions(void)
{
    QVariantList list;
    
    for (int button=0; button<_buttonCount; button++) {
        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;
    }
    
    _throttleMode = (ThrottleMode_t)mode;
    _saveSettings();
    emit throttleModeChanged(_throttleMode);
}

Don Gagne's avatar
Don Gagne committed
501
void Joystick::startCalibrationMode(CalibrationMode_t mode)
502
{
Don Gagne's avatar
Don Gagne committed
503 504 505 506 507 508
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode CalibrationModeOff";
        return;
    }
    
    _calibrationMode = mode;
509
    
510 511
    if (!isRunning()) {
        _pollingStartedForCalibration = true;
512
        startPolling(_multiVehicleManager->activeVehicle());
513
    }
514 515
}

Don Gagne's avatar
Don Gagne committed
516
void Joystick::stopCalibrationMode(CalibrationMode_t mode)
517
{
Don Gagne's avatar
Don Gagne committed
518 519 520 521 522 523 524 525 526
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode: CalibrationModeOff";
        return;
    }
    
    if (mode == CalibrationModeCalibrating) {
        _calibrationMode = CalibrationModeMonitor;
    } else {
        _calibrationMode = CalibrationModeOff;
527 528 529
        if (_pollingStartedForCalibration) {
            stopPolling();
        }
530 531
    }
}
532

Don Gagne's avatar
Don Gagne committed
533 534
void Joystick::_buttonAction(const QString& action)
{
535 536 537 538
    if (!_activeVehicle || !_activeVehicle->joystickEnabled()) {
        return;
    }

Don Gagne's avatar
Don Gagne committed
539 540 541 542
    if (action == "Arm") {
        _activeVehicle->setArmed(true);
    } else if (action == "Disarm") {
        _activeVehicle->setArmed(false);
543 544
    } else if (_activeVehicle->flightModes().contains(action)) {
        _activeVehicle->setFlightMode(action);
Don Gagne's avatar
Don Gagne committed
545 546 547 548 549
    } else {
        qCDebug(JoystickLog) << "_buttonAction unknown action:" << action;
    }
}

550 551 552 553 554 555 556
bool Joystick::_validAxis(int axis)
{
    return axis >= 0 && axis < _axisCount;
}

bool Joystick::_validButton(int button)
{
557
    return button >= 0 && button < _totalButtonCount;
558 559
}