This is the first rev of HW3 for IDD
Dependencies: MMA8451Q USBDevice mbed nRF24L01P
Revision 3:99ed0483f868, committed 2014-09-29
- Comitter:
- shunshou
- Date:
- Mon Sep 29 17:14:42 2014 +0000
- Parent:
- 2:c3b748d86642
- Child:
- 4:7012a2af25f6
- Commit message:
- Better mouse/keyboard interface; motor
Changed in this revision
| main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/main.cpp Mon Sep 29 10:38:39 2014 +0000
+++ b/main.cpp Mon Sep 29 17:14:42 2014 +0000
@@ -4,13 +4,13 @@
#include "mbed.h"
#include "nRF24L01P.h" // nordic library
-#define DEBUG 0
-#define BASE 1
+#define DEBUG 0 // code debug mode
+#define BASE 0 // is base station
#include "USBMouseKeyboard.h" // for the sword - mouse/keyboard combo
#if(BASE == 1)
- USBMouseKeyboard MK; //Default is REL_MOUSE, bout could use ABS_MOUSE too
+ USBMouseKeyboard MK; //Default is REL_MOUSE, bout could use ABS_MOUSE too
#endif
#define SCALING 50 // factor to multiply the accelerometer reading by (usually it is in the scale of g's. Decides sensitivity of mouse. Keep it less 100 (mouse is assigned an int8)
@@ -27,17 +27,11 @@
#define RX_NRF24L01P_ADDRESS ((unsigned long long) 0xABABABABAB )
#define TX_NRF24L01P_ADDRESS ((unsigned long long) 0xCDCDCDCDCD )
-// Masks
-#define LOW8 0x00FF
-#define HIGH3 0x0007
-#define LOW5 0x001F
-#define HIGH6 0x003F
-
// The nRF24L01+ supports transfers from 1 to 32 bytes
-// Assume 1680x1050 max screen resolution -- MSB to LSB 0 padded, 1 bit pressed, 11 bits x, 11 bits y for Fruit Ninja
-// For Blade Symphony, way fewer than 24 control bits for keyboard/house
-// From PC, only need (zero padded) 1 bit flag indicating if hit + 1 bit indicating Fruit Ninja (0) or Blade Symphony (1)
-#define TRANSFER_SIZE 3
+// To base station: roll | cycle 1 2 3 | space = jump | left click = attack | right click = defend | w | s | d | a | 8-bit Y mouse movement | 8-bit X mouse movement
+// WASD = forward, left, back, right
+// From PC, only need (zero padded) 1 bit flag indicating if hit
+#define TRANSFER_SIZE 4
Serial pc(USBTX, USBRX); // PC communication
@@ -45,7 +39,9 @@
nRF24L01P nordic(PTD2, PTD3, PTC5, PTD0, PTD5, PTA13); // mosi, miso, sck, csn, ce, irq
-DigitalIn modeSW(D15); // base station or sword mode
+DigitalIn modeSW(D15); // base station or sword mode can be selected w/ jumper
+
+DigitalOut greenLED(LED_GREEN);
// Accelerometer
MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
@@ -53,31 +49,32 @@
void Calibrate(void);
void Acc_GetXY(void);
-int16_t x,y; // variables to hold acceleration data after call to Acc_Get_All
-float x_b, y_b; // acc bias
+ int16_t x,y; // variables to hold acceleration data after call to Acc_Get_All
+float x_b, y_b; // acc bias
// Debug
//DigitalOut greenLED(LED_GREEN);
//DigitalOut redLED(LED_RED);
-
-AnalogIn ATTACK(A0);
-AnalogIn SELECT(A1);
-AnalogIn XJOY(A2);
-AnalogIn YJOY(A3);
+AnalogIn ATTACK(A0); // attack FSR
+AnalogIn SELECT(A1); // defense/mode FSR
+AnalogIn XJOY(A2); // joystick x axis
+AnalogIn YJOY(A3); // joystick y axis
DigitalIn JOYSEL(D3);
-
bool isBaseStation;
+bool motorOnFlag;
+int motorCycle = 0;
int main() {
int8_t mouse_x, mouse_y;
- Calibrate();
+ Calibrate(); // Calibrate accelerometer
- modeSW.mode(PullUp); // Configure pull down to minimize wire
+ modeSW.mode(PullUp); // Configure pull up to minimize wire on sword
- isBaseStation = (bool) !modeSW; // Detect device via jumper connection
+ isBaseStation = (bool) !modeSW; // Detect device via jumper connection
+
wait(5);
// Power up wireless
@@ -112,24 +109,22 @@
motor.period(0.001f); // 1ms period
motor.write(0.0f); // initially not on
- // motor.write(0.40f); // 95% duty cycle, relative to period
-
// Status flags
- bool isBladeSymphony = false;
- bool sensor1ON = false;
-
bool motorON = false;
+ bool mouse1 = false;
+ bool mouse2 = false;
+ bool mouse3 = false;
+ bool mouse4 = false;
+ bool mouse5 = false;
+ bool attackflag = false;
int rxDataCnt = 0;
- // Debug
- int testcount = 0;
-
// counting the mode
uint8_t mode_count = 0;
while (1) {
- // Only reads 1 byte from PC + sends to other mcu (pads w/ 0 bytes) if base station
+ // Only reads 1 byte from PC + sends to other mcu (pads w/ bytes) if base station
if (isBaseStation){
// If we've received anything over the host serial link...
@@ -138,7 +133,8 @@
// ...add it to the transmit buffer -- only care about first byte
txData[0] = pc.getc();
txData[1] = 100;
- txData[2] = '\n';
+ txData[2] = 100;
+ txData[3] = '\n';
// Send the transmitbuffer via the nRF24L01+
nordic.write( NRF24L01P_PIPE_P0, txData, TRANSFER_SIZE );
@@ -154,15 +150,15 @@
// ...read the data into the receive buffer
rxDataCnt = nordic.read( NRF24L01P_PIPE_P0, rxData, TRANSFER_SIZE );
- //NOTE: NEED TO INTERPRET AS KEYS/MOUSE HERE
-
- int8_t dx = rxData[0];
- int8_t dy = rxData[1];
+ //Get data and convert to mouse x,y and key entry
+ // To base station: roll | cycle 1 2 3 | space = jump | left click = attack | right click = defend | w | s | d | a | 8-bit Y mouse movement | 8-bit X mouse movement
+ int8_t dx = rxData[0]; // change in x
+ int8_t dy = rxData[1]; // change in y
- bool mode_stat = (rxData[2] >> 7) & 1;
+ bool mode_stat = (rxData[2] >> 7) & 1; // checking flag bits
bool joy_but = (rxData[2] >> 6) & 1;
- bool sel_stat = (rxData[2] >> 5) & 1;
+ bool def_stat = (rxData[2] >> 5) & 1;
bool attack_stat = (rxData[2] >> 4) & 1;
bool key_w = (rxData[2] >> 3) & 1;
bool key_s = (rxData[2] >> 2) & 1;
@@ -171,167 +167,194 @@
bool roll = (rxData[3] >> 0) & 1;
- #if(BASE == 1)
- MK.move(dy, dx);
-
- if(joy_but)
+ #if(BASE == 1) // Only if base station
+ MK.move(dy, dx); // move mouse relative
+
+ if(joy_but) // do keyboard events
+ MK.putc(' ');
+
+ if(attack_stat)
+ {
+ MK.press(MOUSE_LEFT);
+ mouse1 = true;
+ }
+ if(!attack_stat && mouse1)
+ {
+ MK.release(MOUSE_LEFT);
+ mouse1 = false;
+ }
+ if(key_a) // move left
{
- MK.putc(' ');
- }
- if(key_w)
+ MK.press(MOUSE_RIGHT);
+ mouse2 = true;
+ }
+ if(!key_a && mouse2)
+ {
+ MK.release(MOUSE_RIGHT);
+ mouse2 = false;
+ }
+ if(key_d) // move right
{
+ MK.press(MOUSE_MIDDLE);
+ mouse3 = true;
+ }
+ if(!key_d && mouse3)
+ {
+ MK.release(MOUSE_MIDDLE);
+ mouse3 = false;
+ }
+ // mouse 4, 5 have issues on windows
+ if(key_w) // move forward
+ {
+ //MK.press(16); // mouse5
+ //mouse5 = true;
MK.putc('w');
}
- if(key_a)
+ /*if(!key_w && mouse5)
{
- MK.putc('a');
- }
- if(key_s)
+ MK.release(16);
+ mouse5 = false;
+ }*/
+ if(key_s) // move backward
{
+ //MK.press(8); // mouse4
+ //mouse4 = true;
MK.putc('s');
}
- if(key_d)
- {
- MK.putc('d');
- }
- if(sel_stat)
+ /*if(!key_s && mouse4)
{
- MK.click(MOUSE_RIGHT);
- }
- if(attack_stat)
- {
- MK.click(MOUSE_LEFT);
- }
+ MK.release(8);
+ mouse4 = false;
+ }*/
+
+ // Single push commands
+ if(def_stat)
+ MK.putc('d');
+
if(mode_stat)
{
MK.putc('1'+mode_count);
mode_count = (mode_count+1)%3;
}
if(roll)
- {
- //MK.putc('r');
- }
+ MK.putc('r');
+
#endif
-
- pc.printf("x: %d y: %d \r\n",dx,dy);
+ //pc.printf("x: %d y: %d \r\n",dx,dy);
// Display the receive buffer contents via the host serial link
/*for ( int i = 0; i < TRANSFER_SIZE; i++ ) {
pc.putc( rxData[i] );
}*/
-
- // Toggle LED2 (to help debug nRF24L01+ -> Host communication)
- if (rxData[0] == 65 && rxData[1] == 66 && rxData[2] == 67){
-// redLED = !redLED;
- }
}
}
-
// sword
else{
- int ATTACKVAL = ATTACK.read_u16();
- int SELECTVAL = SELECT.read_u16();
- int XJOYVAL = XJOY.read_u16();
- int YJOYVAL = YJOY.read_u16();
- int JOYSELVAL = (int) JOYSEL;
+ int ATTACKVAL = ATTACK.read_u16(); // attack FSR
+ int SELECTVAL = SELECT.read_u16(); // mode/defense FSR
+ int XJOYVAL = XJOY.read_u16(); // joystick x
+ int YJOYVAL = YJOY.read_u16(); // joystick y
+ int JOYSELVAL = (int) JOYSEL; // joystick select value
+ // if joystick push/pulled all the way on axis, do roll/move faster in direction
+ //bool roll = ((XJOYVAL > 64000) || (XJOYVAL < 1000) || (YJOYVAL > 64000) || (YJOYVAL < 1000)) ? true: 0;
+ // Disable backward roll due to lack of continuous MOUSE buttons
+ bool roll = ((XJOYVAL > 64000) || (XJOYVAL < 1000) || (YJOYVAL > 64000)) ? true: 0;
- bool roll = ((XJOYVAL > 65000) || (XJOYVAL < 500) || (YJOYVAL > 65000) || (YJOYVAL < 500)) ? true: 0;
-
- bool mode_stat = (SELECTVAL > 45000) ? true: 0;
+ // thresholding
+ bool mode_stat = (SELECTVAL > 45000) ? true: 0; // 1, 2, 3 rotated (defense/mode FSR pressed all the way)
bool joy_but = JOYSEL == 0? true: 0;
- bool sel_stat = (SELECTVAL > 10000 && SELECTVAL < 45000) ? true: 0;
- bool attack_stat = ATTACKVAL > 10000? true: 0;
- bool key_d = XJOYVAL > 35000 ? true: 0;
+ bool def_stat = (SELECTVAL > 10000 && SELECTVAL < 45000) ? true: 0; // defend if defense/mode FSR slightly pressed
+ bool attack_stat = ATTACKVAL > 10000? true: 0; // attack if attack FSR pressed
+ bool key_d = XJOYVAL > 35000 ? true: 0; // if joystick moves in direction, direction key should be pressed
bool key_a = XJOYVAL < 30000 ? true : 0;
bool key_w = YJOYVAL > 35000 ? true: 0;
bool key_s = YJOYVAL < 30000 ? true: 0;
- uint8_t key_stat = mode_stat<<7|joy_but<<6|sel_stat<<5|attack_stat<<4|key_w<<3|key_s<<2|key_d<<1|key_a<<0;
+ // turn on motor at start of attack
+
+ if (attack_stat == true)
+ attackflag = true;
+ if (attackflag == true){
+ if (motorCycle < 250){
+ motorCycle++;
+ motor.write(0.80f); // 40% duty cycle, relative to period
+
+ }
+ else {
+ motorCycle = 0;
+ attackflag = false;
+ motor.write(0.00f);
+ }
+ }
- pc.printf("F1: %d \t F2: %d \t X: %d \t Y: %d \t SEL: %d \r\n", ATTACKVAL, SELECTVAL, XJOYVAL, YJOYVAL, JOYSELVAL);
-
-// greenLED = JOYSEL;
+
+ // make byte 2 of packet
+ uint8_t key_stat = mode_stat<<7|joy_but<<6|def_stat<<5|attack_stat<<4|key_w<<3|key_s<<2|key_d<<1|key_a<<0;
+
+ //pc.printf("F1: %d \t F2: %d \t X: %d \t Y: %d \t SEL: %d \r\n", ATTACKVAL, SELECTVAL, XJOYVAL, YJOYVAL, JOYSELVAL);
// Let serial read catch up on base station/PC side
wait_us(150);
char swordData[TRANSFER_SIZE];
- int16_t deltax = 768;
- int16_t deltay = 345;
-
- if (testcount <= 2000){
- deltax = testcount;
- deltay = 2000-testcount;
- testcount++;
- }
- else
- testcount = 0;
-
- Acc_GetXY();
+ Acc_GetXY(); // Get X, Y acceleration
- mouse_x = x;
+ mouse_x = x; // x, y assigned in prev function
mouse_y = y;
- char lowX = char(mouse_x & LOW8);
- char lowY = char(mouse_y & LOW8);
+ char lowX = char(mouse_x & 0x00FF); // only use lowest 8 bits of data
+ char lowY = char(mouse_y & 0x00FF);
+
+ //pc.printf("x: %f \t y: %f \r\n", mouse_x,mouse_y);
// left A, right D, back S, up W
- // MSB -- LSB,
+ // MSB -- LSB send packet
swordData[0] = lowX;
swordData[1] = lowY;
swordData[2] = char(key_stat);
- swordData[3] = char(roll);
+ swordData[3] = char(roll); // cast bool into char
// Send the transmitbuffer via the nRF24L01+
nordic.write( NRF24L01P_PIPE_P0, swordData, TRANSFER_SIZE );
- // NOTE: Action settings depending on type of game. Accelerometer data. Force sensitive resistor thresholding, etc.
-
// If we've received anything from base station
+ if ( nordic.readable() ) {
- if ( nordic.readable() ) {
+ greenLED = !greenLED;
+
char rxData[TRANSFER_SIZE];
// ...read the data into the receive buffer
rxDataCnt = nordic.read( NRF24L01P_PIPE_P0, rxData, TRANSFER_SIZE );
#if DEBUG == 1
- // Toggle LED1 (to help debug Host -> nRF24L01+ communication)
- pc.printf("x: %f \t y: %f \r\n", mouse_x,mouse_y);
-// greenLED = !greenLED;
-
// Display the receive buffer contents via the host serial link
for ( int i = 0; i < TRANSFER_SIZE; i++ ) {
-
pc.putc( rxData[i] );
}
-
- // Toggle LED2 (to help debug nRF24L01+ -> Host communication)
- if (rxData[0] == 65 && rxData[1] == 100 && rxData[2] == 100){
-// redLED = !redLED;
- }
#endif
-
- // From PC, only need (zero padded) 1 bit flag indicating if hit + 1 bit indicating Fruit Ninja (0) or Blade Symphony (1)
+ // From PC, only need (zero padded) 1 bit flag indicating if hit
// In first byte
- isBladeSymphony = (rxData[0] >> 0) & 1;
- motorON = (rxData[0] >> 1) & 1; // Motor ON when sword contact made
-
-// greenLED = !isBladeSymphony; // LEDs active low
-// redLED = !motorON;
-
+ motorON = (rxData[0] >> 0) & 1; // Motor ON when sword contact made
+ if (motorON)
+ motorOnFlag = true;
}
+
+ // if flag to turn motor on sent, run motor for a little while and then stop
+ // period not extended if another motor on command sent in the middle of the count
+
}
}
}
+// perform initial accelerometer calibration to zero stuff
void Calibrate(void)
{
unsigned int count1;
@@ -340,19 +363,82 @@
float sstatey = 0;
do{
- sstatex += acc.getAccX(); // Accumulate Samples
+ sstatex += acc.getAccX(); // Accumulate Samples
sstatey += acc.getAccY();
count1++;
- }while(count1!=0x0400); // 1024 times
- x_b = sstatex/1024.0; // division between 1024
+ }while(count1!=0x0400); // 1024 times
+ x_b = sstatex/1024.0; // division between 1024
y_b = sstatey/1024.0;
}
+// remove offset from calibration + scale for sensitivity when getting accelerometer data
void Acc_GetXY(void)
{
x = (int16_t)((acc.getAccX()- x_b)*SCALING);
y = (int16_t)((acc.getAccY()- y_b)*SCALING);
}
+/* Processing code
+
+//sikuli-java.jar needed to keep track of HP/score for rumble + serial RX/TX
+
+import org.sikuli.script.*;
+import processing.serial.*;
+
+Serial myPort; // Serial port
+int lastTime = 0; // Time counter
+
+Region myHPReg = new Region(1,1,500,500); // HP watch regions x, y, w, h
+Region otherHPReg = new Region(500,500,500,500);
+
+// Specify event handler for detecting changes
+class hpChangeClass implements SikuliEventObserver {
+ @Override
+ void targetChanged(SikuliEventChange evnt1) {
+ println( "changed!" );
+ for (int i = 0; i <100; i++){
+ myPort.write(3); // Rumble motor (LSB high)
+ }
+ //lastTime++;
+ }
+
+ void targetAppeared(SikuliEventAppear evnt2) {
+ println("test");
+ }
+
+ void targetVanished(SikuliEventVanish evnt3) {
+ println("test");
+ }
+
+}
+
+hpChangeClass regionChange = new hpChangeClass();
+
+void setup(){
+ size(1,1); // Don't care (out of focus)
+ myPort = new Serial(this, "/dev/tty.usbmodem1422", 9600); // Serial setup
+ myPort.clear();
+ //lastTime = millis();
+ myHPReg.highlight(5); // Show regions watched for 5 seconds
+ otherHPReg.highlight(5);
+
+ myHPReg.onChange(10, regionChange); // num of pixels for change detection, event handler
+ myHPReg.observeInBackground((int)Float.POSITIVE_INFINITY); // watch forever
+
+ otherHPReg.onChange(10, regionChange); // num of pixels for change detection, event handler
+ otherHPReg.observeInBackground((int)Float.POSITIVE_INFINITY); // watch forever
+}
+
+void draw() {
+
+ Wait
+ if ( millis() - lastTime > 5000 ) {
+ myPort.write(68);
+ lastTime = millis();
+ }
+
+}
+
+*/