You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
8.2 KiB
286 lines
8.2 KiB
/*===================================================================== |
|
======================================================================*/ |
|
|
|
/** |
|
* @file |
|
* @brief Joystick interface |
|
* |
|
* @author Lorenz Meier <mavteam@student.ethz.ch> |
|
* @author Andreas Romer <mavteam@student.ethz.ch> |
|
* |
|
*/ |
|
|
|
#include "JoystickInput.h" |
|
|
|
#include <QDebug> |
|
#include <limits.h> |
|
#include "UAS.h" |
|
#include "UASManager.h" |
|
#include "QGC.h" |
|
#include <QMutexLocker> |
|
|
|
/** |
|
* The coordinate frame of the joystick axis is the aeronautical frame like shown on this image: |
|
* @image html http://pixhawk.ethz.ch/wiki/_media/standards/body-frame.png Aeronautical frame |
|
*/ |
|
JoystickInput::JoystickInput() : |
|
sdlJoystickMin(-32768.0f), |
|
sdlJoystickMax(32767.0f), |
|
defaultIndex(0), |
|
uas(NULL), |
|
uasButtonList(QList<int>()), |
|
done(false), |
|
thrustAxis(2), |
|
xAxis(0), |
|
yAxis(1), |
|
yawAxis(3), |
|
joystickName(tr("Unitinialized")) |
|
{ |
|
for (int i = 0; i < 10; i++) { |
|
calibrationPositive[i] = sdlJoystickMax; |
|
calibrationNegative[i] = sdlJoystickMin; |
|
} |
|
|
|
connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); |
|
|
|
// Enter main loop |
|
//start(); |
|
} |
|
|
|
JoystickInput::~JoystickInput() |
|
{ |
|
done = true; |
|
while (done) |
|
{ |
|
QGC::SLEEP::usleep(5000); |
|
} |
|
this->deleteLater(); |
|
} |
|
|
|
|
|
void JoystickInput::setActiveUAS(UASInterface* uas) |
|
{ |
|
// Only connect / disconnect is the UAS is of a controllable UAS class |
|
UAS* tmp = 0; |
|
if (this->uas) |
|
{ |
|
tmp = dynamic_cast<UAS*>(this->uas); |
|
if(tmp) |
|
{ |
|
disconnect(this, SIGNAL(joystickChanged(double,double,double,double,int,int)), tmp, SLOT(setManualControlCommands(double,double,double,double))); |
|
disconnect(this, SIGNAL(buttonPressed(int)), tmp, SLOT(receiveButton(int))); |
|
} |
|
} |
|
|
|
this->uas = uas; |
|
|
|
tmp = dynamic_cast<UAS*>(this->uas); |
|
if(tmp) { |
|
connect(this, SIGNAL(joystickChanged(double,double,double,double,int,int)), tmp, SLOT(setManualControlCommands(double,double,double,double))); |
|
connect(this, SIGNAL(buttonPressed(int)), tmp, SLOT(receiveButton(int))); |
|
} |
|
if (!isRunning()) |
|
{ |
|
start(); |
|
} |
|
} |
|
|
|
void JoystickInput::init() |
|
{ |
|
// INITIALIZE SDL Joystick support |
|
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) { |
|
printf("Couldn't initialize SimpleDirectMediaLayer: %s\n", SDL_GetError()); |
|
} |
|
|
|
// Enumerate joysticks and select one |
|
int numJoysticks = SDL_NumJoysticks(); |
|
|
|
// Wait for joysticks if none is connected |
|
while (numJoysticks == 0) |
|
{ |
|
MG::SLEEP::msleep(800); |
|
// INITIALIZE SDL Joystick support |
|
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) |
|
{ |
|
printf("Couldn't initialize SimpleDirectMediaLayer: %s\n", SDL_GetError()); |
|
} |
|
numJoysticks = SDL_NumJoysticks(); |
|
} |
|
|
|
printf("%d Input devices found:\n", numJoysticks); |
|
for(int i=0; i < SDL_NumJoysticks(); i++ ) |
|
{ |
|
printf("\t- %s\n", SDL_JoystickName(i)); |
|
joystickName = QString(SDL_JoystickName(i)); |
|
} |
|
|
|
printf("\nOpened %s\n", SDL_JoystickName(defaultIndex)); |
|
|
|
SDL_JoystickEventState(SDL_ENABLE); |
|
|
|
joystick = SDL_JoystickOpen(defaultIndex); |
|
|
|
// Make sure active UAS is set |
|
setActiveUAS(UASManager::instance()->getActiveUAS()); |
|
} |
|
|
|
/** |
|
* @brief Execute the Joystick process |
|
*/ |
|
void JoystickInput::run() |
|
{ |
|
|
|
init(); |
|
|
|
forever |
|
{ |
|
if (done) |
|
{ |
|
done = false; |
|
exit(); |
|
} |
|
while(SDL_PollEvent(&event)) |
|
{ |
|
|
|
SDL_JoystickUpdate(); |
|
|
|
// Todo check if it would be more beneficial to use the event structure |
|
switch(event.type) { |
|
case SDL_KEYDOWN: |
|
/* handle keyboard stuff here */ |
|
//qDebug() << "KEY PRESSED!"; |
|
break; |
|
|
|
case SDL_QUIT: |
|
/* Set whatever flags are necessary to */ |
|
/* end the main loop here */ |
|
break; |
|
|
|
case SDL_JOYBUTTONDOWN: /* Handle Joystick Button Presses */ |
|
if ( event.jbutton.button == 0 ) { |
|
//qDebug() << "BUTTON PRESSED!"; |
|
} |
|
break; |
|
|
|
case SDL_JOYAXISMOTION: /* Handle Joystick Motion */ |
|
if ( ( event.jaxis.value < -3200 ) || (event.jaxis.value > 3200 ) ) { |
|
if( event.jaxis.axis == 0) { |
|
/* Left-right movement code goes here */ |
|
} |
|
|
|
if( event.jaxis.axis == 1) { |
|
/* Up-Down movement code goes here */ |
|
} |
|
} |
|
break; |
|
|
|
default: |
|
//qDebug() << "SDL event occured"; |
|
break; |
|
} |
|
} |
|
|
|
// Display all axes |
|
for(int i = 0; i < SDL_JoystickNumAxes(joystick); i++) |
|
{ |
|
//qDebug() << "\rAXIS" << i << "is: " << SDL_JoystickGetAxis(joystick, i); |
|
} |
|
|
|
// THRUST |
|
double thrust = ((double)SDL_JoystickGetAxis(joystick, thrustAxis) - calibrationNegative[thrustAxis]) / (calibrationPositive[thrustAxis] - calibrationNegative[thrustAxis]); |
|
// Has to be inverted for Logitech Wingman |
|
thrust = 1.0f - thrust; |
|
// Bound rounding errors |
|
if (thrust > 1) thrust = 1; |
|
if (thrust < 0) thrust = 0; |
|
emit thrustChanged((float)thrust); |
|
|
|
// X Axis |
|
double x = ((double)SDL_JoystickGetAxis(joystick, xAxis) - calibrationNegative[xAxis]) / (calibrationPositive[xAxis] - calibrationNegative[xAxis]); |
|
x = 1.0f - x; |
|
x = x * 2.0f - 1.0f; |
|
// Bound rounding errors |
|
if (x > 1.0f) x = 1.0f; |
|
if (x < -1.0f) x = -1.0f; |
|
emit xChanged((float)x); |
|
|
|
// Y Axis |
|
double y = ((double)SDL_JoystickGetAxis(joystick, yAxis) - calibrationNegative[yAxis]) / (calibrationPositive[yAxis] - calibrationNegative[yAxis]); |
|
y = 1.0f - y; |
|
y = y * 2.0f - 1.0f; |
|
// Bound rounding errors |
|
if (y > 1.0f) y = 1.0f; |
|
if (y < -1.0f) y = -1.0f; |
|
emit yChanged((float)y); |
|
|
|
// Yaw Axis |
|
|
|
double yaw = ((double)SDL_JoystickGetAxis(joystick, yawAxis) - calibrationNegative[yawAxis]) / (calibrationPositive[yawAxis] - calibrationNegative[yawAxis]); |
|
yaw = 1.0f - yaw; |
|
yaw = yaw * 2.0f - 1.0f; |
|
// Bound rounding errors |
|
if (yaw > 1.0f) yaw = 1.0f; |
|
if (yaw < -1.0f) yaw = -1.0f; |
|
emit yawChanged((float)yaw); |
|
|
|
// Get joystick hat position, convert it to vector |
|
int hatPosition = SDL_JoystickGetHat(joystick, 0); |
|
|
|
int xHat,yHat; |
|
xHat = 0; |
|
yHat = 0; |
|
|
|
// Build up vectors describing the hat position |
|
// |
|
// Coordinate frame for joystick hat: |
|
// |
|
// y |
|
// ^ |
|
// | |
|
// | |
|
// 0 ----> x |
|
// |
|
|
|
if ((SDL_HAT_UP & hatPosition) > 0) yHat = 1; |
|
if ((SDL_HAT_DOWN & hatPosition) > 0) yHat = -1; |
|
|
|
if ((SDL_HAT_LEFT & hatPosition) > 0) xHat = -1; |
|
if ((SDL_HAT_RIGHT & hatPosition) > 0) xHat = 1; |
|
|
|
// Send new values to rest of groundstation |
|
emit hatDirectionChanged(xHat, yHat); |
|
emit joystickChanged(y, x, yaw, thrust, xHat, yHat); |
|
|
|
|
|
// Display all buttons |
|
for(int i = 0; i < SDL_JoystickNumButtons(joystick); i++) |
|
{ |
|
//qDebug() << "BUTTON" << i << "is: " << SDL_JoystickGetAxis(joystick, i); |
|
if(SDL_JoystickGetButton(joystick, i)) |
|
{ |
|
emit buttonPressed(i); |
|
// Check if button is a UAS select button |
|
|
|
if (uasButtonList.contains(i)) |
|
{ |
|
UASInterface* uas = UASManager::instance()->getUASForId(i); |
|
if (uas) |
|
{ |
|
UASManager::instance()->setActiveUAS(uas); |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
// Sleep, update rate of joystick is approx. 50 Hz (1000 ms / 50 = 20 ms) |
|
QGC::SLEEP::msleep(20); |
|
|
|
} |
|
|
|
} |
|
|
|
const QString& JoystickInput::getName() |
|
{ |
|
return joystickName; |
|
}
|
|
|