JoystickInput.h 11.8 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*=====================================================================

PIXHAWK Micro Air Vehicle Flying Robotics Toolkit

(c) 2009, 2010 PIXHAWK PROJECT  <http://pixhawk.ethz.ch>

This file is part of the PIXHAWK project

    PIXHAWK 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.

    PIXHAWK 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 PIXHAWK. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
26
 * @brief Definition of joystick interface
pixhawk's avatar
pixhawk committed
27
 *
28 29 30 31 32
 * This class defines a new thread to operate the reading of any joystick/controllers
 * via the Simple Directmedia Library (libsdl.org). This relies on polling of the SDL,
 * which is not their recommended method, instead they suggest use event checking. That
 * does not seem to support switching joysticks after their internal event loop has started,
 * so it was abandoned.
pixhawk's avatar
pixhawk committed
33
 *
34 35 36 37 38 39
 * All joystick-related functionality is done in this class, though the JoystickWidget provides
 * a UI around modifying its settings. Additionally controller buttons can be mapped to
 * actions defined by any UASInterface object through the `UASInterface::getActions()` function.
 *
 * @author Lorenz Meier <mavteam@student.ethz.ch>
 * @author Andreas Romer <mavteam@student.ethz.ch>
40
 * @author Julian Oes <julian@oes.ch>
pixhawk's avatar
pixhawk committed
41 42 43 44 45 46 47
 */

#ifndef _JOYSTICKINPUT_H_
#define _JOYSTICKINPUT_H_

#include <QThread>
#include <QList>
48
#include <qmutex.h>
Lorenz Meier's avatar
Lorenz Meier committed
49 50 51
#ifdef Q_OS_MAC
#include <SDL.h>
#else
52
#include <SDL/SDL.h>
Lorenz Meier's avatar
Lorenz Meier committed
53
#endif
pixhawk's avatar
pixhawk committed
54 55 56

#include "UASInterface.h"

57 58 59
struct JoystickSettings {
    QMap<int, bool> axesInverted; ///< Whether each axis should be used inverted from what was reported.
    QMap<int, bool> axesLimited; ///< Whether each axis should be limited to only the positive range. Currently this only applies to the throttle axis, but is kept generic here to possibly support other axes.
60 61
    QMap<int, float> axesMaxRange; ///< The maximum values per axis
    QMap<int, float> axesMinRange; ///< The minimum values per axis
62 63
    QMap<int, int> buttonActions; ///< The index of the action associated with every button.
};
64
Q_DECLARE_METATYPE(JoystickSettings)
65

pixhawk's avatar
pixhawk committed
66 67 68 69 70 71 72 73 74
/**
 * @brief Joystick input
 */
class JoystickInput : public QThread
{
    Q_OBJECT

public:
    JoystickInput();
75
    ~JoystickInput();
pixhawk's avatar
pixhawk committed
76
    void run();
77
    void shutdown();
pixhawk's avatar
pixhawk committed
78

79 80 81 82 83 84 85 86 87 88 89 90 91
    /**
     * @brief The JOYSTICK_INPUT_MAPPING enum storing the values for each item in the mapping combobox.
     * This should match the order of items in the mapping combobox in JoystickAxis.ui.
     */
    enum JOYSTICK_INPUT_MAPPING
    {
        JOYSTICK_INPUT_MAPPING_NONE     = 0,
        JOYSTICK_INPUT_MAPPING_YAW      = 1,
        JOYSTICK_INPUT_MAPPING_PITCH    = 2,
        JOYSTICK_INPUT_MAPPING_ROLL     = 3,
        JOYSTICK_INPUT_MAPPING_THROTTLE = 4
    };

Lorenz Meier's avatar
Lorenz Meier committed
92
    /**
93
     * @brief Load joystick-specific settings.
Lorenz Meier's avatar
Lorenz Meier committed
94
     */
95 96 97 98 99
    void loadJoystickSettings();
    /**
     * @brief Load joystick-independent settings.
     */
    void loadGeneralSettings();
Lorenz Meier's avatar
Lorenz Meier committed
100 101

    /**
102 103 104 105 106
     * @brief Store joystick-specific settings.
     */
    void storeJoystickSettings() const;
    /**
     * @brief Store joystick-independent settings.
Lorenz Meier's avatar
Lorenz Meier committed
107
     */
108 109 110 111 112 113
    void storeGeneralSettings() const;

    bool enabled() const
    {
        return isEnabled;
    }
Lorenz Meier's avatar
Lorenz Meier committed
114

115 116 117 118 119
    bool calibrating() const
    {
        return isCalibrating;
    }

120
    int getMappingThrottleAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
121
    {
122
        return throttleAxis;
Lorenz Meier's avatar
Lorenz Meier committed
123 124
    }

125
    int getMappingRollAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
126
    {
127
        return rollAxis;
Lorenz Meier's avatar
Lorenz Meier committed
128 129
    }

130
    int getMappingPitchAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
131
    {
132
        return pitchAxis;
Lorenz Meier's avatar
Lorenz Meier committed
133 134
    }

135
    int getMappingYawAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
136 137 138 139
    {
        return yawAxis;
    }

140 141
    int getJoystickNumButtons() const
    {
142
        return joystickNumButtons;
143 144
    }

145 146
    int getJoystickNumAxes() const
    {
147
        return joystickNumAxes;
148 149
    }

150 151 152 153 154
    int getJoystickID() const
    {
        return joystickID;
    }

155 156 157 158 159
    const QString& getName() const
    {
        return joystickName;
    }

160 161
    int getNumJoysticks() const
    {
162
        return numJoysticks;
163 164 165 166 167 168 169
    }

    QString getJoystickNameById(int id) const
    {
        return QString(SDL_JoystickName(id));
    }

170 171 172
    float getCurrentValueForAxis(int axis) const;
    bool getInvertedForAxis(int axis) const;
    bool getRangeLimitForAxis(int axis) const;
173 174
    float getAxisRangeLimitMinForAxis(int axis) const;
    float getAxisRangeLimitMaxForAxis(int axis) const;
175
    int getActionForButton(int button) const;
176

pixhawk's avatar
pixhawk committed
177 178 179 180
    const double sdlJoystickMin;
    const double sdlJoystickMax;

protected:
181 182

    bool isEnabled; ///< Track whether the system should emit the higher-level signals: joystickChanged & actionTriggered.
183
    bool isCalibrating; ///< Track if calibration in progress
184 185
    bool done;

pixhawk's avatar
pixhawk committed
186
    SDL_Joystick* joystick;
187
    UASInterface* uas; ///< Track the current UAS.
188 189
    int autopilotType; ///< Cache the autopilotType
    int systemType; ///< Cache the systemType
190
    bool uasCanReverse; ///< Track whether the connect UAS can drive a reverse speed.
pixhawk's avatar
pixhawk committed
191

192
    // Store the mapping between axis numbers and the roll/pitch/yaw/throttle configuration.
193
    // Value is one of JoystickAxis::JOYSTICK_INPUT_MAPPING.
194 195
    int rollAxis;
    int pitchAxis;
pixhawk's avatar
pixhawk committed
196
    int yawAxis;
197 198 199
    int throttleAxis;

    // Cache information on the joystick instead of polling the SDL everytime.
200
    int numJoysticks; ///< Total number of joysticks detected by the SDL.
201
    QString joystickName;
202
    int joystickID;
203 204
    int joystickNumAxes;
    int joystickNumButtons;
205

206 207 208 209 210 211 212 213 214
    // Track axis/button settings based on a Joystick/AutopilotType/SystemType triplet.
    // This is only a double-map, because settings are stored/loaded based on joystick
    // name first, so only the settings for the current joystick need to be stored at any given time.
    // Pointers are kept to the various settings field to reduce lookup times.
    // Note that the mapping (0,0) corresponds to when no UAS is connected. Since this corresponds
    // to a generic vehicle type and a generic autopilot, this is a pretty safe default.
    QMap<int, QMap<int, JoystickSettings> > joystickSettings;

    // Track the last state of the axes, buttons, and hats for only emitting change signals.
215
    QList<float> joystickAxes; ///< The values of every axes during the last sample.
216
    quint16 joystickButtons;   ///< The state of every button. Bitfield supporting 16 buttons with 1s indicating that the button is down.
217
    qint8 xHat, yHat;            ///< The horizontal/vertical hat directions. Values are -1, 0, 1, with (-1,-1) indicating bottom-left.
pixhawk's avatar
pixhawk committed
218

219 220 221
    /**
     * @brief Called before main run() event loop starts. Waits for joysticks to be connected.
     */
pixhawk's avatar
pixhawk committed
222 223
    void init();

224
signals:
pixhawk's avatar
pixhawk committed
225 226 227 228

    /**
     * @brief Signal containing all joystick raw positions
     *
229 230 231 232
     * @param roll forward / pitch / x axis, front: 1, center: 0, back: -1. If the roll axis isn't defined, NaN is transmit instead.
     * @param pitch left / roll / y axis, left: -1, middle: 0, right: 1. If the roll axis isn't defined, NaN is transmit instead.
     * @param yaw turn axis, left-turn: -1, centered: 0, right-turn: 1. If the roll axis isn't defined, NaN is transmit instead.
     * @param throttle Throttle, -100%:-1.0, 0%: 0.0, 100%: 1.0. If the roll axis isn't defined, NaN is transmit instead.
pixhawk's avatar
pixhawk committed
233 234 235
     * @param xHat hat vector in forward-backward direction, +1 forward, 0 center, -1 backward
     * @param yHat hat vector in left-right direction, -1 left, 0 center, +1 right
     */
236
    void joystickChanged(float roll, float pitch, float yaw, float throttle, qint8 xHat, qint8 yHat, quint16 buttons);
pixhawk's avatar
pixhawk committed
237 238

    /**
239
      * @brief Emit a new value for an axis
240
      *
241
      * @param value Value of the axis, between -1.0 and 1.0.
242
      */
243
    void axisValueChanged(int axis, float value);
pixhawk's avatar
pixhawk committed
244

245
    /**
246
      * @brief Joystick button has changed state from unpressed to pressed.
247 248
      * @param key index of the pressed key
      */
pixhawk's avatar
pixhawk committed
249 250
    void buttonPressed(int key);

251 252 253 254 255 256 257
    /**
      * @brief Joystick button has changed state from pressed to unpressed.
      *
      * @param key index of the released key
      */
    void buttonReleased(int key);

258 259 260 261 262 263
    /**
      * @brief A joystick button was pressed that had a corresponding action.
      * @param action The index of the action to trigger. Dependent on UAS.
      */
    void actionTriggered(int action);

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    /**
      * @brief Hat (8-way switch on the top) has changed position
      *
      * Coordinate frame for joystick hat:
      *
      *    y
      *    ^
      *    |
      *    |
      *    0 ----> x
      *
      *
      * @param x vector in left-right direction
      * @param y vector in forward-backward direction
      */
279
    void hatDirectionChanged(qint8 x, qint8 y);
pixhawk's avatar
pixhawk committed
280

281 282 283 284 285
    /** @brief Signal that the UAS has been updated for this JoystickInput
     * Note that any UI updates should NOT query this object for joystick details. That should be done in response to the joystickSettingsChanged signal.
     */
    void activeUASSet(UASInterface*);

286 287 288
    /** @brief Signals that new joystick-specific settings were changed. Useful for triggering updates that at dependent on the current joystick. */
    void joystickSettingsChanged();

289 290 291
    /** @brief The JoystickInput has switched to a different joystick. UI should be adjusted accordingly. */
    void newJoystickSelected();

292
public slots:
293 294
    /** @brief Enable or disable emitting the high-level control signals from the joystick. */
    void setEnabled(bool enable);
295
    /** @brief Specify the UAS that this input should forward joystickChanged signals and buttonPresses to. */
pixhawk's avatar
pixhawk committed
296
    void setActiveUAS(UASInterface* uas);
297
    /** @brief Switch to a new joystick by ID number. Both buttons and axes are updated with the proper signals emitted. */
298
    void setActiveJoystick(int id);
299 300
    /** @brief Switch calibration mode active */
    void setCalibrating(bool active);
301 302 303 304 305 306
    /**
     * @brief Change the control mapping for a given joystick axis.
     * @param axisID The axis to modify (0-indexed)
     * @param newMapping The mapping to use.
     * @see JOYSTICK_INPUT_MAPPING
     */
307
    void setAxisMapping(int axis, JoystickInput::JOYSTICK_INPUT_MAPPING newMapping);
308 309 310 311 312 313
    /**
     * @brief Specify if an axis should be inverted.
     * @param axis The ID of the axis.
     * @param inverted True indicates inverted from normal. Varies by controller.
     */
    void setAxisInversion(int axis, bool inverted);
314

315 316 317 318 319 320
    /**
     * @brief Specify that an axis should only transmit the positive values. Useful for controlling throttle from auto-centering axes.
     * @param axis Which axis has its range limited.
     * @param limitRange If true only the positive half of this axis will be read.
     */
    void setAxisRangeLimit(int axis, bool limitRange);
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

    /**
     * @brief Specify minimum value for axis.
     * @param axis Which axis should be set.
     * @param min Value to be set.
     */
    void setAxisRangeLimitMin(int axis, float min);

    /**
     * @brief Specify maximum value for axis.
     * @param axis Which axis should be set.
     * @param max Value to be set.
     */
    void setAxisRangeLimitMax(int axis, float max);

336 337 338 339 340 341 342 343
    /**
     * @brief Specify a button->action mapping for the given uas.
     * This mapping is applied based on UAS autopilot type and UAS system type.
     * Connects the buttonEmitted signal for the corresponding button to the corresponding action for the current UAS.
     * @param button The numeric ID for the button
     * @param action The numeric ID of the action for this UAS to map to.
     */
    void setButtonAction(int button, int action);
pixhawk's avatar
pixhawk committed
344 345 346
};

#endif // _JOYSTICKINPUT_H_