RUOFAN LI / Mbed 2 deprecated el17rl

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Joystick.cpp Source File

Joystick.cpp

00001 #include "Joystick.h"
00002 
00003 Joystick::Joystick(PinName vertPin,PinName horizPin,PinName clickPin)
00004 {
00005     vert = new AnalogIn(vertPin);
00006     horiz = new AnalogIn(horizPin);
00007     click = new InterruptIn(clickPin);
00008 }
00009 
00010 void Joystick::init()
00011 {
00012     // read centred values of joystick
00013     _x0 = horiz->read();
00014     _y0 = vert->read();
00015 
00016     // this assumes that the joystick is centred when the init function is called
00017     // if perfectly centred, the pots should read 0.5, but this may
00018     // not be the case and x0 and y0 will be used to calibrate readings
00019 
00020     // turn on pull-down for button -> this assumes the other side of the button
00021     // is connected to +3V3 so we read 1 when pressed and 0 when not pressed
00022     click->mode(PullDown);
00023     // we therefore need to fire the interrupt on a rising edge
00024     click->rise(callback(this,&Joystick::click_isr));
00025     // need to use a callback since mbed-os5 - basically tells it to look in this class for the ISR
00026     _click_flag = 0;
00027 
00028 }
00029 
00030 Direction Joystick::get_direction()
00031 {
00032     float angle = get_angle();  // 0 to 360, -1 for centred
00033 
00034     Direction d;
00035     // partition 360 into segments and check which segment the angle is in
00036     if (angle < 0.0f) {
00037         d = CENTRE;   // check for -1.0 angle
00038     } else if (angle < 22.5f) {  // then keep going in 45 degree increments
00039         d = N;
00040     } else if (angle < 67.5f) {
00041         d = NE;
00042     } else if (angle < 112.5f) {
00043         d = E;
00044     } else if (angle < 157.5f) {
00045         d = SE;
00046     } else if (angle < 202.5f) {
00047         d = S;
00048     } else if (angle < 247.5f) {
00049         d = SW;
00050     } else if (angle < 292.5f) {
00051         d = W;
00052     } else if (angle < 337.5f) {
00053         d = NW;
00054     } else {
00055         d = N;
00056     }
00057 
00058     return d;
00059 }
00060 
00061 // this method gets the magnitude of the joystick movement
00062 float Joystick::get_mag()
00063 {
00064     Polar p = get_polar();
00065     return p.mag;
00066 }
00067 
00068 // this method gets the angle of joystick movement (0 to 360, 0 North)
00069 float Joystick::get_angle()
00070 {
00071     Polar p = get_polar();
00072     return p.angle;
00073 }
00074 
00075 // get raw joystick coordinate in range -1 to 1
00076 // Direction (x,y)
00077 // North     (0,1)
00078 // East      (1,0)
00079 // South     (0,-1)
00080 // West      (-1,0)
00081 Vector2D Joystick::get_coord()
00082 {
00083     // read() returns value in range 0.0 to 1.0 so is scaled and centre value
00084     // substracted to get values in the range -1.0 to 1.0
00085     float x = 2.0f*( horiz->read() - _x0 );
00086     float y = 2.0f*( vert->read() - _y0 );
00087 
00088     // Note: the x value here is inverted to ensure the positive x is to the
00089     // right. This is simply due to how the potentiometer on the joystick
00090     // I was using was connected up. It could have been corrected in hardware
00091     // by swapping the power supply pins. Instead it is done in software so may
00092     // need to be changed depending on your wiring setup
00093 
00094     Vector2D coord = {-x,y};
00095     return coord;
00096 }
00097 
00098 // This maps the raw x,y coord onto a circular grid.
00099 // See:  http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
00100 Vector2D Joystick::get_mapped_coord()
00101 {
00102     Vector2D coord = get_coord();
00103 
00104     // do the transformation
00105     float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
00106     float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
00107 
00108     Vector2D mapped_coord = {x,y};
00109     return mapped_coord;
00110 }
00111 
00112 // this function converts the mapped coordinates into polar form
00113 Polar Joystick::get_polar()
00114 {
00115     // get the mapped coordinate
00116     Vector2D coord = get_mapped_coord();
00117 
00118     // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
00119     // We want 0 degrees to correspond to North and increase clockwise to 359
00120     // like a compass heading, so we need to swap the axis and invert y
00121     float x = coord.y;
00122     float y = coord.x;
00123 
00124     float mag = sqrt(x*x+y*y);  // pythagoras
00125     float angle = RAD2DEG*atan2(y,x);
00126     // angle will be in range -180 to 180, so add 360 to negative angles to
00127     // move to 0 to 360 range
00128     if (angle < 0.0f) {
00129         angle+=360.0f;
00130     }
00131 
00132     // the noise on the ADC causes the values of x and y to fluctuate slightly
00133     // around the centred values. This causes the random angle values to get
00134     // calculated when the joystick is centred and untouched. This is also when
00135     // the magnitude is very small, so we can check for a small magnitude and then
00136     // set the angle to -1. This will inform us when the angle is invalid and the
00137     // joystick is centred
00138 
00139     if (mag < TOL) {
00140         mag = 0.0f;
00141         angle = -1.0f;
00142     }
00143 
00144     Polar p = {mag,angle};
00145     return p;
00146 }
00147 
00148 bool Joystick::button_pressed()
00149 {
00150     // ISR must have been triggered
00151     if (_click_flag) {
00152         _click_flag = 0;  // clear flag
00153         return true;
00154     } else {
00155         return false;
00156     }
00157 }
00158 
00159 void Joystick::click_isr()
00160 {
00161     _click_flag = 1;
00162 }#include "Gamepad.h"
00163 
00164 #include "mbed.h"
00165 
00166 //////////// constructor/destructor ////////////
00167 Gamepad::Gamepad()
00168     :
00169     _led1(new PwmOut(PTA1)),
00170     _led2(new PwmOut(PTA2)),
00171     _led3(new PwmOut(PTC2)),
00172     _led4(new PwmOut(PTC3)),
00173     _led5(new PwmOut(PTC4)),
00174     _led6(new PwmOut(PTD3)),
00175 
00176     _button_A(new InterruptIn(PTB9)),
00177     _button_B(new InterruptIn(PTD0)),
00178     _button_X(new InterruptIn(PTC17)),
00179     _button_Y(new InterruptIn(PTC12)),
00180     _button_L(new InterruptIn(PTB18)),
00181     _button_R(new InterruptIn(PTB3)),
00182     _button_back(new InterruptIn(PTB19)),
00183     _button_start(new InterruptIn(PTC5)),
00184     _button_joystick(new InterruptIn(PTC16)),
00185 
00186     _vert(new AnalogIn(PTB10)),
00187     _horiz(new AnalogIn(PTB11)),
00188 
00189     _buzzer(new PwmOut(PTC10)),
00190     _pot(new AnalogIn(PTB2)),
00191 
00192     _timeout(new Timeout()),
00193 
00194     _event_state(0),
00195 
00196     _x0(0),
00197     _y0(0)
00198 {}
00199 
00200 Gamepad::~Gamepad()
00201 {
00202     delete _led1,_led2,_led3,_led4,_led5,_led6;
00203     delete _button_A,_button_B,_button_joystick,_vert,_horiz;
00204     delete _button_X,_button_Y,_button_back,_button_start;
00205     delete _button_L,_button_R, _buzzer, _pot, _timeout;
00206 }
00207 
00208 ///////////////// public methods /////////////////
00209 
00210 void Gamepad::init()
00211 {
00212     leds_off();
00213     init_buttons();
00214 
00215     // read centred values of joystick
00216     _x0 = _horiz->read();
00217     _y0 = _vert->read();
00218 
00219     // clear all flags
00220     _event_state = 0;
00221 }
00222 
00223 void Gamepad::leds_off()
00224 {
00225     leds(0.0);
00226 }
00227 
00228 void Gamepad::leds_on()
00229 {
00230     leds(1.0);
00231 }
00232 
00233 void Gamepad::leds(float val) const
00234 {
00235     if (val < 0.0f) {
00236         val = 0.0f;
00237     }
00238     if (val > 1.0f) {
00239         val = 1.0f;
00240     }
00241 
00242     // leds are active-low, so subtract from 1.0
00243     // 0.0 corresponds to fully-off, 1.0 to fully-on
00244     val = 1.0f - val;
00245 
00246     _led1->write(val);
00247     _led2->write(val);
00248     _led3->write(val);
00249     _led4->write(val);
00250     _led5->write(val);
00251     _led6->write(val);
00252 }
00253 
00254 void Gamepad::led(int n,float val) const
00255 {
00256     // ensure they are within vlaid range
00257     if (val < 0.0f) {
00258         val = 0.0f;
00259     }
00260     if (val > 1.0f) {
00261         val = 1.0f;
00262     }
00263     
00264     switch (n) {
00265         
00266         // check for valid LED number and set value
00267 
00268         case 1:
00269             _led1->write(1.0f-val);   // active-low so subtract from 1
00270             break;
00271         case 2:
00272             _led2->write(1.0f-val);   // active-low so subtract from 1
00273             break;
00274         case 3:
00275             _led3->write(1.0f-val);   // active-low so subtract from 1
00276             break;
00277         case 4:
00278             _led4->write(1.0f-val);   // active-low so subtract from 1
00279             break;
00280         case 5:
00281             _led5->write(1.0f-val);   // active-low so subtract from 1
00282             break;
00283         case 6:
00284             _led6->write(1.0f-val);   // active-low so subtract from 1
00285             break;
00286 
00287     }
00288 }
00289 
00290 float Gamepad::read_pot() const
00291 {
00292     return _pot->read();
00293 }
00294 
00295 void Gamepad::tone(float frequency, float duration)
00296 {
00297     _buzzer->period(1.0f/frequency);
00298     _buzzer->write(0.5);  // 50% duty cycle - square wave
00299     _timeout->attach(callback(this, &Gamepad::tone_off), duration );
00300 }
00301 
00302 bool Gamepad::check_event(GamepadEvent const id)
00303 {
00304     // Check whether event flag is set
00305     if (_event_state[id]) {
00306         _event_state.reset(id);  // clear flag
00307         return true;
00308     } else {
00309         return false;
00310     }
00311 }
00312 
00313 // this method gets the magnitude of the joystick movement
00314 float Gamepad::get_mag()
00315 {
00316     Polar p = get_polar();
00317     return p.mag;
00318 }
00319 
00320 // this method gets the angle of joystick movement (0 to 360, 0 North)
00321 float Gamepad::get_angle()
00322 {
00323     Polar p = get_polar();
00324     return p.angle;
00325 }
00326 
00327 Direction Gamepad::get_direction()
00328 {
00329     float angle = get_angle();  // 0 to 360, -1 for centred
00330 
00331     Direction d;
00332     // partition 360 into segments and check which segment the angle is in
00333     if (angle < 0.0f) {
00334         d = CENTRE;   // check for -1.0 angle
00335     } else if (angle < 22.5f) {  // then keep going in 45 degree increments
00336         d = N;
00337     } else if (angle < 67.5f) {
00338         d = NE;
00339     } else if (angle < 112.5f) {
00340         d = E;
00341     } else if (angle < 157.5f) {
00342         d = SE;
00343     } else if (angle < 202.5f) {
00344         d = S;
00345     } else if (angle < 247.5f) {
00346         d = SW;
00347     } else if (angle < 292.5f) {
00348         d = W;
00349     } else if (angle < 337.5f) {
00350         d = NW;
00351     } else {
00352         d = N;
00353     }
00354 
00355     return d;
00356 }
00357 
00358 ///////////////////// private methods ////////////////////////
00359 
00360 void Gamepad::tone_off()
00361 {
00362     // called after timeout
00363     _buzzer->write(0.0);
00364 }
00365 
00366 void Gamepad::init_buttons()
00367 {
00368     // turn on pull-downs as other side of button is connected to 3V3
00369     // button is 0 when not pressed and 1 when pressed
00370     _button_A->mode(PullDown);
00371     _button_B->mode(PullDown);
00372     _button_X->mode(PullDown);
00373     _button_Y->mode(PullDown);
00374     _button_back->mode(PullDown);
00375     _button_start->mode(PullDown);
00376     _button_L->mode(PullDown);
00377     _button_R->mode(PullDown);
00378     _button_joystick->mode(PullDown);
00379     // therefore setup rising edge interrupts
00380     _button_A->rise(callback(this,&Gamepad::a_isr));
00381     _button_B->rise(callback(this,&Gamepad::b_isr));
00382     _button_X->rise(callback(this,&Gamepad::x_isr));
00383     _button_Y->rise(callback(this,&Gamepad::y_isr));
00384     _button_L->rise(callback(this,&Gamepad::l_isr));
00385     _button_R->rise(callback(this,&Gamepad::r_isr));
00386     _button_start->rise(callback(this,&Gamepad::start_isr));
00387     _button_back->rise(callback(this,&Gamepad::back_isr));
00388     _button_joystick->rise(callback(this,&Gamepad::joy_isr));
00389 }
00390 
00391 // button interrupts ISRs
00392 // Each of these simply sets the appropriate event bit in the _event_state
00393 // variable
00394 void Gamepad::a_isr()
00395 {
00396     _event_state.set(A_PRESSED);
00397 }
00398 void Gamepad::b_isr()
00399 {
00400     _event_state.set(B_PRESSED);
00401 }
00402 void Gamepad::x_isr()
00403 {
00404     _event_state.set(X_PRESSED);
00405 }
00406 void Gamepad::y_isr()
00407 {
00408     _event_state.set(Y_PRESSED);
00409 }
00410 void Gamepad::l_isr()
00411 {
00412     _event_state.set(L_PRESSED);
00413 }
00414 void Gamepad::r_isr()
00415 {
00416     _event_state.set(R_PRESSED);
00417 }
00418 void Gamepad::back_isr()
00419 {
00420     _event_state.set(BACK_PRESSED);
00421 }
00422 void Gamepad::start_isr()
00423 {
00424     _event_state.set(START_PRESSED);
00425 }
00426 void Gamepad::joy_isr()
00427 {
00428     _event_state.set(JOY_PRESSED);
00429 }
00430 
00431 // get raw joystick coordinate in range -1 to 1
00432 // Direction (x,y)
00433 // North     (0,1)
00434 // East      (1,0)
00435 // South     (0,-1)
00436 // West      (-1,0)
00437 Vector2D Gamepad::get_coord()
00438 {
00439     // read() returns value in range 0.0 to 1.0 so is scaled and centre value
00440     // substracted to get values in the range -1.0 to 1.0
00441     float x = 2.0f*( _horiz->read() - _x0 );
00442     float y = 2.0f*( _vert->read()  - _y0 );
00443 
00444     // Note: the x value here is inverted to ensure the positive x is to the
00445     // right. This is simply due to how the potentiometer on the joystick
00446     // I was using was connected up. It could have been corrected in hardware
00447     // by swapping the power supply pins. Instead it is done in software so may
00448     // need to be changed depending on your wiring setup
00449 
00450     Vector2D coord = {-x,y};
00451     return coord;
00452 }
00453 
00454 // This maps the raw x,y coord onto a circular grid.
00455 // See:  http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
00456 Vector2D Gamepad::get_mapped_coord()
00457 {
00458     Vector2D coord = get_coord();
00459 
00460     // do the transformation
00461     float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
00462     float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
00463 
00464     Vector2D mapped_coord = {x,y};
00465     return mapped_coord;
00466 }
00467 
00468 // this function converts the mapped coordinates into polar form
00469 Polar Gamepad::get_polar()
00470 {
00471     // get the mapped coordinate
00472     Vector2D coord = get_mapped_coord();
00473 
00474     // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
00475     // We want 0 degrees to correspond to North and increase clockwise to 359
00476     // like a compass heading, so we need to swap the axis and invert y
00477     float x = coord.y;
00478     float y = coord.x;
00479 
00480     float mag = sqrt(x*x+y*y);  // pythagoras
00481     float angle = RAD2DEG*atan2(y,x);
00482     // angle will be in range -180 to 180, so add 360 to negative angles to
00483     // move to 0 to 360 range
00484     if (angle < 0.0f) {
00485         angle+=360.0f;
00486     }
00487 
00488     // the noise on the ADC causes the values of x and y to fluctuate slightly
00489     // around the centred values. This causes the random angle values to get
00490     // calculated when the joystick is centred and untouched. This is also when
00491     // the magnitude is very small, so we can check for a small magnitude and then
00492     // set the angle to -1. This will inform us when the angle is invalid and the
00493     // joystick is centred
00494 
00495     if (mag < TOL) {
00496         mag = 0.0f;
00497         angle = -1.0f;
00498     }
00499 
00500     Polar p = {mag,angle};
00501     return p;
00502 }