JoystickInput.h 11 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>
pixhawk's avatar
pixhawk committed
40 41 42 43 44 45 46
 */

#ifndef _JOYSTICKINPUT_H_
#define _JOYSTICKINPUT_H_

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

#include "UASInterface.h"

56 57 58 59 60
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.
    QMap<int, int> buttonActions; ///< The index of the action associated with every button.
};
61
Q_DECLARE_METATYPE(JoystickSettings)
62

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

public:
    JoystickInput();
72
    ~JoystickInput();
pixhawk's avatar
pixhawk committed
73
    void run();
74
    void shutdown();
pixhawk's avatar
pixhawk committed
75

76 77 78 79 80 81 82 83 84 85 86 87 88
    /**
     * @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
89
    /**
90
     * @brief Load joystick-specific settings.
Lorenz Meier's avatar
Lorenz Meier committed
91
     */
92 93 94 95 96
    void loadJoystickSettings();
    /**
     * @brief Load joystick-independent settings.
     */
    void loadGeneralSettings();
Lorenz Meier's avatar
Lorenz Meier committed
97 98

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

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

112
    int getMappingThrottleAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
113
    {
114
        return throttleAxis;
Lorenz Meier's avatar
Lorenz Meier committed
115 116
    }

117
    int getMappingRollAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
118
    {
119
        return rollAxis;
Lorenz Meier's avatar
Lorenz Meier committed
120 121
    }

122
    int getMappingPitchAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
123
    {
124
        return pitchAxis;
Lorenz Meier's avatar
Lorenz Meier committed
125 126
    }

127
    int getMappingYawAxis() const
Lorenz Meier's avatar
Lorenz Meier committed
128 129 130 131
    {
        return yawAxis;
    }

132 133
    int getJoystickNumButtons() const
    {
134
        return joystickNumButtons;
135 136
    }

137 138
    int getJoystickNumAxes() const
    {
139
        return joystickNumAxes;
140 141
    }

142 143 144 145 146
    int getJoystickID() const
    {
        return joystickID;
    }

147 148 149 150 151
    const QString& getName() const
    {
        return joystickName;
    }

152 153
    int getNumJoysticks() const
    {
154
        return numJoysticks;
155 156 157 158 159 160 161
    }

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

162 163 164 165
    float getCurrentValueForAxis(int axis) const;
    bool getInvertedForAxis(int axis) const;
    bool getRangeLimitForAxis(int axis) const;
    int getActionForButton(int button) const;
166

pixhawk's avatar
pixhawk committed
167 168 169 170
    const double sdlJoystickMin;
    const double sdlJoystickMax;

protected:
171 172
    double calibrationPositive[10];
    double calibrationNegative[10];
173 174 175 176

    bool isEnabled; ///< Track whether the system should emit the higher-level signals: joystickChanged & actionTriggered.
    bool done;

pixhawk's avatar
pixhawk committed
177
    SDL_Joystick* joystick;
178
    UASInterface* uas; ///< Track the current UAS.
179 180
    int autopilotType; ///< Cache the autopilotType
    int systemType; ///< Cache the systemType
181
    bool uasCanReverse; ///< Track whether the connect UAS can drive a reverse speed.
pixhawk's avatar
pixhawk committed
182

183
    // Store the mapping between axis numbers and the roll/pitch/yaw/throttle configuration.
184
    // Value is one of JoystickAxis::JOYSTICK_INPUT_MAPPING.
185 186
    int rollAxis;
    int pitchAxis;
pixhawk's avatar
pixhawk committed
187
    int yawAxis;
188 189 190
    int throttleAxis;

    // Cache information on the joystick instead of polling the SDL everytime.
191
    int numJoysticks; ///< Total number of joysticks detected by the SDL.
192
    QString joystickName;
193
    int joystickID;
194 195
    int joystickNumAxes;
    int joystickNumButtons;
196

197 198 199 200 201 202 203 204 205
    // 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.
206
    QList<float> joystickAxes; ///< The values of every axes during the last sample.
207
    quint16 joystickButtons;   ///< The state of every button. Bitfield supporting 16 buttons with 1s indicating that the button is down.
208
    qint8 xHat, yHat;            ///< The horizontal/vertical hat directions. Values are -1, 0, 1, with (-1,-1) indicating bottom-left.
pixhawk's avatar
pixhawk committed
209

210 211 212
    /**
     * @brief Called before main run() event loop starts. Waits for joysticks to be connected.
     */
pixhawk's avatar
pixhawk committed
213 214
    void init();

215
signals:
pixhawk's avatar
pixhawk committed
216 217 218 219

    /**
     * @brief Signal containing all joystick raw positions
     *
220 221 222 223
     * @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
224 225 226
     * @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
     */
227
    void joystickChanged(float roll, float pitch, float yaw, float throttle, qint8 xHat, qint8 yHat, quint16 buttons);
pixhawk's avatar
pixhawk committed
228 229

    /**
230
      * @brief Emit a new value for an axis
231
      *
232
      * @param value Value of the axis, between -1.0 and 1.0.
233
      */
234
    void axisValueChanged(int axis, float value);
pixhawk's avatar
pixhawk committed
235

236
    /**
237
      * @brief Joystick button has changed state from unpressed to pressed.
238 239
      * @param key index of the pressed key
      */
pixhawk's avatar
pixhawk committed
240 241
    void buttonPressed(int key);

242 243 244 245 246 247 248
    /**
      * @brief Joystick button has changed state from pressed to unpressed.
      *
      * @param key index of the released key
      */
    void buttonReleased(int key);

249 250 251 252 253 254
    /**
      * @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);

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
    /**
      * @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
      */
270
    void hatDirectionChanged(qint8 x, qint8 y);
pixhawk's avatar
pixhawk committed
271

272 273 274 275 276
    /** @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*);

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

280 281 282
    /** @brief The JoystickInput has switched to a different joystick. UI should be adjusted accordingly. */
    void newJoystickSelected();

283
public slots:
284 285
    /** @brief Enable or disable emitting the high-level control signals from the joystick. */
    void setEnabled(bool enable);
286
    /** @brief Specify the UAS that this input should forward joystickChanged signals and buttonPresses to. */
pixhawk's avatar
pixhawk committed
287
    void setActiveUAS(UASInterface* uas);
288
    /** @brief Switch to a new joystick by ID number. Both buttons and axes are updated with the proper signals emitted. */
289
    void setActiveJoystick(int id);
290 291 292 293 294 295
    /**
     * @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
     */
296
    void setAxisMapping(int axis, JoystickInput::JOYSTICK_INPUT_MAPPING newMapping);
297 298 299 300 301 302
    /**
     * @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);
303 304 305 306 307 308
    /**
     * @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);
309 310 311 312 313 314 315 316
    /**
     * @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
317 318 319
};

#endif // _JOYSTICKINPUT_H_