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

10 11
/// @file
/// @brief  Joystick Controller
12

13
#pragma once
14 15 16 17 18 19

#include <QObject>
#include <QThread>

#include "QGCLoggingCategory.h"
#include "Vehicle.h"
20
#include "MultiVehicleManager.h"
21 22

Q_DECLARE_LOGGING_CATEGORY(JoystickLog)
23
Q_DECLARE_LOGGING_CATEGORY(JoystickValuesLog)
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/// Action assigned to button
class AssignedButtonAction : public QObject {
    Q_OBJECT
public:
    AssignedButtonAction(QObject* parent, const QString name);
    QString action;
    QElapsedTimer buttonTime;
    bool    repeat = false;
};

/// Assignable Button Action
class AssignableButtonAction : public QObject {
    Q_OBJECT
public:
    AssignableButtonAction(QObject* parent, QString action_, bool canRepeat_ = false);
    Q_PROPERTY(QString  action      READ action     CONSTANT)
    Q_PROPERTY(bool     canRepeat   READ canRepeat  CONSTANT)
    QString action      () { return _action; }
    bool    canRepeat   () { return _repeat; }
private:
    QString _action;
    bool    _repeat = false;
};

/// Joystick Controller
50 51 52 53
class Joystick : public QThread
{
    Q_OBJECT
public:
54 55
    Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager);

56
    ~Joystick();
57

58
    typedef struct Calibration_t {
59 60 61
        int     min;
        int     max;
        int     center;
62
        int     deadband;
63
        bool    reversed;
64 65 66 67 68 69
        Calibration_t()
            : min(-32767)
            , max(32767)
            , center(0)
            , deadband(0)
            , reversed(false) {}
70
    } Calibration_t;
71

72 73 74 75 76
    typedef enum {
        rollFunction,
        pitchFunction,
        yawFunction,
        throttleFunction,
77 78
        gimbalPitchFunction,
        gimbalYawFunction,
79 80
        maxFunction
    } AxisFunction_t;
81

82 83 84 85 86
    typedef enum {
        ThrottleModeCenterZero,
        ThrottleModeDownZero,
        ThrottleModeMax
    } ThrottleMode_t;
87

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    Q_PROPERTY(QString  name                    READ name                   CONSTANT)
    Q_PROPERTY(bool     calibrated              MEMBER _calibrated          NOTIFY calibratedChanged)
    Q_PROPERTY(int      totalButtonCount        READ totalButtonCount       CONSTANT)
    Q_PROPERTY(int      axisCount               READ axisCount              CONSTANT)
    Q_PROPERTY(bool     requiresCalibration     READ requiresCalibration    CONSTANT)

    //-- Actions assigned to buttons
    Q_PROPERTY(QStringList buttonActions        READ buttonActions          NOTIFY buttonActionsChanged)

    //-- Actions that can be assigned to buttons
    Q_PROPERTY(QmlObjectListModel* assignableActions    READ assignableActions          NOTIFY      assignableActionsChanged)
    Q_PROPERTY(QStringList assignableActionTitles       READ assignableActionTitles     NOTIFY      assignableActionsChanged)
    Q_PROPERTY(QString  disabledActionName              READ disabledActionName         CONSTANT)

    Q_PROPERTY(bool     gimbalEnabled           READ gimbalEnabled          WRITE setGimbalEnabled      NOTIFY gimbalEnabledChanged)
    Q_PROPERTY(int      throttleMode            READ throttleMode           WRITE setThrottleMode       NOTIFY throttleModeChanged)
    Q_PROPERTY(float    axisFrequencyHz         READ axisFrequencyHz        WRITE setAxisFrequency      NOTIFY axisFrequencyHzChanged)
    Q_PROPERTY(float    minAxisFrequencyHz      MEMBER _minAxisFrequencyHz                              CONSTANT)
    Q_PROPERTY(float    maxAxisFrequencyHz      MEMBER _minAxisFrequencyHz                              CONSTANT)
    Q_PROPERTY(float    buttonFrequencyHz       READ buttonFrequencyHz      WRITE setButtonFrequency    NOTIFY buttonFrequencyHzChanged)
    Q_PROPERTY(float    minButtonFrequencyHz    MEMBER _minButtonFrequencyHz                            CONSTANT)
    Q_PROPERTY(float    maxButtonFrequencyHz    MEMBER _maxButtonFrequencyHz                            CONSTANT)
    Q_PROPERTY(bool     negativeThrust          READ negativeThrust         WRITE setNegativeThrust     NOTIFY negativeThrustChanged)
    Q_PROPERTY(float    exponential             READ exponential            WRITE setExponential        NOTIFY exponentialChanged)
    Q_PROPERTY(bool     accumulator             READ accumulator            WRITE setAccumulator        NOTIFY accumulatorChanged)
    Q_PROPERTY(bool     circleCorrection        READ circleCorrection       WRITE setCircleCorrection   NOTIFY circleCorrectionChanged)

    Q_INVOKABLE void    setButtonRepeat     (int button, bool repeat);
    Q_INVOKABLE bool    getButtonRepeat     (int button);
    Q_INVOKABLE void    setButtonAction     (int button, const QString& action);
    Q_INVOKABLE QString getButtonAction     (int button);
119

120
    // Property accessors
121

122 123 124 125 126
    QString     name                () { return _name; }
    int         totalButtonCount    () { return _totalButtonCount; }
    int         axisCount           () { return _axisCount; }
    bool        gimbalEnabled       () { return _gimbalEnabled; }
    QStringList buttonActions       ();
127

128 129 130
    QmlObjectListModel* assignableActions   () { return &_assignableButtonActions; }
    QStringList assignableActionTitles      () { return _availableActionTitles; }
    QString     disabledActionName          () { return _buttonActionNone; }
131

132
    void setGimbalEnabled           (bool set);
133

134
    /// Start the polling thread which will in turn emit joystick signals
135
    void startPolling(Vehicle* vehicle);
136
    void stopPolling(void);
137

138 139
    void setCalibration(int axis, Calibration_t& calibration);
    Calibration_t getCalibration(int axis);
140

141 142
    void setFunctionAxis(AxisFunction_t function, int axis);
    int getFunctionAxis(AxisFunction_t function);
143 144


145
/*
Jacob Walser's avatar
Jacob Walser committed
146
    // Joystick index used by sdl library
Patrick José Pereira's avatar
Patrick José Pereira committed
147
    // Settable because sdl library remaps indices after certain events
Jacob Walser's avatar
Jacob Walser committed
148 149
    virtual int index(void) = 0;
    virtual void setIndex(int index) = 0;
150
*/
151 152
	virtual bool requiresCalibration(void) { return true; }

153 154
    int   throttleMode      ();
    void  setThrottleMode   (int mode);
155

156 157
    bool  negativeThrust    ();
    void  setNegativeThrust (bool allowNegative);
158

159 160
    float exponential       ();
    void  setExponential    (float expo);
161

162 163
    bool  accumulator       ();
    void  setAccumulator    (bool accu);
164

165 166
    bool  deadband          ();
    void  setDeadband       (bool accu);
Gregory Dymarek's avatar
Gregory Dymarek committed
167

168 169
    bool  circleCorrection  ();
    void  setCircleCorrection(bool circleCorrection);
170

171 172
    void  setTXMode         (int mode);
    int   getTXMode         () { return _transmitterMode; }
173

Don Gagne's avatar
Don Gagne committed
174
    /// Set the current calibration mode
175
    void  setCalibrationMode (bool calibrating);
176

177 178 179 180
    /// Get joystick message rate (in Hz)
    float axisFrequencyHz     () { return _axisFrequencyHz; }
    /// Set joystick message rate (in Hz)
    void  setAxisFrequency  (float val);
181

182 183 184 185
    /// Get joystick button repeat rate (in Hz)
    float buttonFrequencyHz   () { return _buttonFrequencyHz; }
    /// Set joystick button repeat rate (in Hz)
    void  setButtonFrequency(float val);
186

187
signals:
188
    // The raw signals are only meant for use by calibration
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 222
    void rawAxisValueChanged        (int index, int value);
    void rawButtonPressedChanged    (int index, int pressed);
    void calibratedChanged          (bool calibrated);
    void buttonActionsChanged       ();
    void assignableActionsChanged   ();
    void throttleModeChanged        (int mode);
    void negativeThrustChanged      (bool allowNegative);
    void exponentialChanged         (float exponential);
    void accumulatorChanged         (bool accumulator);
    void enabledChanged             (bool enabled);
    void circleCorrectionChanged    (bool circleCorrection);
    void axisValues                 (float roll, float pitch, float yaw, float throttle);
    void manualControlGimbal        (float gimbalPitch, float gimbalYaw);

    void gimbalEnabledChanged       ();
    void axisFrequencyHzChanged       ();
    void buttonFrequencyHzChanged     ();
    void startContinuousZoom        (int direction);
    void stopContinuousZoom         ();
    void stepZoom                   (int direction);
    void stepCamera                 (int direction);
    void stepStream                 (int direction);
    void triggerCamera              ();
    void startVideoRecord           ();
    void stopVideoRecord            ();
    void toggleVideoRecord          ();
    void gimbalPitchStep            (int direction);
    void gimbalYawStep              (int direction);
    void centerGimbal               ();
    void gimbalControlValue         (double pitch, double yaw);
    void setArmed                   (bool arm);
    void setVtolInFwdFlight         (bool set);
    void setFlightMode              (const QString& flightMode);
    void emergencyStop              ();
223

224
protected:
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    void    _setDefaultCalibration  ();
    void    _saveSettings           ();
    void    _saveButtonSettings     ();
    void    _loadSettings           ();
    float   _adjustRange            (int value, Calibration_t calibration, bool withDeadbands);
    void    _executeButtonAction    (const QString& action, bool buttonDown);
    int     _findAssignableButtonAction(const QString& action);
    bool    _validAxis              (int axis);
    bool    _validButton            (int button);
    void    _handleAxis             ();
    void    _handleButtons          ();
    void    _buildActionList        (Vehicle* activeVehicle);

    void    _pitchStep              (int direction);
    void    _yawStep                (int direction);
    double  _localYaw       = 0.0;
    double  _localPitch     = 0.0;
242

243
private:
244 245 246
    virtual bool _open      ()          = 0;
    virtual void _close     ()          = 0;
    virtual bool _update    ()          = 0;
247

248 249 250
    virtual bool _getButton (int i)      = 0;
    virtual int  _getAxis   (int i)      = 0;
    virtual bool _getHat    (int hat,int i) = 0;
251

252
    void _updateTXModeSettingsKey(Vehicle* activeVehicle);
253 254 255
    int _mapFunctionMode(int mode, int function);
    void _remapAxes(int currentMode, int newMode, int (&newMapping)[maxFunction]);

256
    // Override from QThread
257
    virtual void run();
258

259
protected:
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
    enum {
        BUTTON_UP,
        BUTTON_DOWN,
        BUTTON_REPEAT
    };

    static const float  _defaultAxisFrequencyHz;
    static const float  _defaultButtonFrequencyHz;

    uint8_t*_rgButtonValues         = nullptr;

    bool    _exitThread             = false;    ///< true: signal thread to exit
    bool    _calibrationMode        = false;
    int*    _rgAxisValues           = nullptr;
    Calibration_t* _rgCalibration   = nullptr;
    ThrottleMode_t _throttleMode    = ThrottleModeDownZero;
    bool    _negativeThrust         = false;
    float   _exponential            = 0;
    bool    _accumulator            = false;
    bool    _deadband               = false;
    bool    _circleCorrection       = true;
    float   _axisFrequencyHz        = _defaultAxisFrequencyHz;
    float   _buttonFrequencyHz      = _defaultButtonFrequencyHz;
    Vehicle* _activeVehicle         = nullptr;
    bool    _gimbalEnabled          = false;

    bool    _pollingStartedForCalibration = false;
288

289 290 291 292
    QString _name;
    bool    _calibrated;
    int     _axisCount;
    int     _buttonCount;
293 294 295
    int     _hatCount;
    int     _hatButtonCount;
    int     _totalButtonCount;
296

297
    static int          _transmitterMode;
298 299
    int                 _rgFunctionAxis[maxFunction] = {};
    QElapsedTimer       _axisTime;
300

301 302 303 304
    QmlObjectListModel              _assignableButtonActions;
    QList<AssignedButtonAction*>    _buttonActionArray;
    QStringList                     _availableActionTitles;
    MultiVehicleManager*            _multiVehicleManager = nullptr;
305

306 307 308 309
    static const float  _minAxisFrequencyHz;
    static const float  _maxAxisFrequencyHz;
    static const float  _minButtonFrequencyHz;
    static const float  _maxButtonFrequencyHz;
310

311 312 313
private:
    static const char*  _rgFunctionSettingsKey[maxFunction];

314 315
    static const char* _settingsGroup;
    static const char* _calibratedSettingsKey;
316 317
    static const char* _buttonActionNameKey;
    static const char* _buttonActionRepeatKey;
318
    static const char* _throttleModeSettingsKey;
319
    static const char* _exponentialSettingsKey;
320
    static const char* _accumulatorSettingsKey;
Gregory Dymarek's avatar
Gregory Dymarek committed
321
    static const char* _deadbandSettingsKey;
322
    static const char* _circleCorrectionSettingsKey;
323 324
    static const char* _axisFrequencySettingsKey;
    static const char* _buttonFrequencySettingsKey;
325
    static const char* _txModeSettingsKey;
326 327 328 329 330
    static const char* _fixedWingTXModeSettingsKey;
    static const char* _multiRotorTXModeSettingsKey;
    static const char* _roverTXModeSettingsKey;
    static const char* _vtolTXModeSettingsKey;
    static const char* _submarineTXModeSettingsKey;
331
    static const char* _gimbalSettingsKey;
332

333
    static const char* _buttonActionNone;
334 335
    static const char* _buttonActionArm;
    static const char* _buttonActionDisarm;
336
    static const char* _buttonActionToggleArm;
337 338
    static const char* _buttonActionVTOLFixedWing;
    static const char* _buttonActionVTOLMultiRotor;
339 340 341 342
    static const char* _buttonActionStepZoomIn;
    static const char* _buttonActionStepZoomOut;
    static const char* _buttonActionContinuousZoomIn;
    static const char* _buttonActionContinuousZoomOut;
343 344 345 346
    static const char* _buttonActionNextStream;
    static const char* _buttonActionPreviousStream;
    static const char* _buttonActionNextCamera;
    static const char* _buttonActionPreviousCamera;
347 348 349 350 351 352 353 354 355 356
    static const char* _buttonActionTriggerCamera;
    static const char* _buttonActionStartVideoRecord;
    static const char* _buttonActionStopVideoRecord;
    static const char* _buttonActionToggleVideoRecord;
    static const char* _buttonActionGimbalDown;
    static const char* _buttonActionGimbalUp;
    static const char* _buttonActionGimbalLeft;
    static const char* _buttonActionGimbalRight;
    static const char* _buttonActionGimbalCenter;
    static const char* _buttonActionEmergencyStop;
357

358 359
private slots:
    void _activeVehicleChanged(Vehicle* activeVehicle);
360
};