Use Accelerometer and Joystick to mimic a mouse. This is for a class project. It is done for educational purpose. It is not practical to real world use.
Dependencies: C12832_lcd MMA7660 USBDevice mbed
Revision 0:22bdcdc386df, committed 2014-03-15
- Comitter:
- thlu
- Date:
- Sat Mar 15 09:32:43 2014 +0000
- Child:
- 1:03d0f8a4a2d7
- Commit message:
- Got calibration working using x,y, and z-axes
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832_lcd.lib Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/dreschpe/code/C12832_lcd/#8f86576007d6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA7660.lib Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/Sissors/code/MMA7660/#a8e20db7901e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice.lib Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/USBDevice/#335f2506f422
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/accelestick.cpp Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,291 @@ +#include "accelestick.h" + +inline void reset_tm_joystick_dc() +{ + tm_joystick_running = 0; + tm_joystick_dc.stop(); + tm_joystick_dc.reset(); +} + +// This function checks for joystick button presses which emulate a mouse's +// left button, right button, middle button, double click, and scroll +// features. Double click requires a timer +void get_joystick_input() +{ + static uint8_t prev_js = 0; + static bool debug_sel_en = 0; + static int mouse_scroll = 0; + + mouse_info.button = 0; + mouse_info.scroll = 0; + mouse_info.dc = 0; + + if (debug_on && debug_sel_en && (joyb != JS_NONE)) { + debug_sel_en = 0; + debug_sel = joyb; + } + + if (debug_on && (debug_sel == JS_NONE) && (joyb == JS_NONE)) { + debug_sel_en = 1; + } + + switch(joyb) { // 1 = down, 2 = left, 4 = center, 8 = up, 16 = right + case JS_LEFT: + // 1 click = left button, 2 clicks = double click + if ((prev_js != JS_LEFT) && (tm_joystick_running == JS_LEFT)) { // double click + mouse_info.dc = 1; + reset_tm_joystick_dc(); + } else if (!tm_joystick_running) { + tm_joystick_running = JS_LEFT; + tm_joystick_dc.start(); + } + mouse_info.button = MOUSE_LEFT; + break; + case JS_CENTER: // center + if ((prev_js != JS_CENTER) && (tm_joystick_running == JS_CENTER)) { // double click + calib_on = 1; + reset_tm_joystick_dc(); + } else if (!tm_joystick_running) { + tm_joystick_running = JS_CENTER; + tm_joystick_dc.start(); + + } + mouse_info.button = MOUSE_MIDDLE; + break; + case JS_RIGHT: + if ((prev_js != JS_RIGHT) && (tm_joystick_running == JS_RIGHT)) { + debug_on = !debug_on; + reset_tm_joystick_dc(); + lcd.cls(); + lcd.locate(0,0); + if (debug_on) { + lcd.printf("Debug print is ON\n"); + debug_sel = JS_NONE; + debug_sel_en = 0; + } + } else if (!tm_joystick_running) { + tm_joystick_running = JS_RIGHT; + tm_joystick_dc.start(); + } + mouse_info.button = MOUSE_RIGHT; + break; + case JS_DOWN: // down + if (prev_js == JS_DOWN) { + mouse_scroll++; + } else { + mouse_scroll = 1; // >0 means down + } + debug.printf("down scroll = %0d\r\n", mouse_info.scroll); + reset_tm_joystick_dc(); + mouse_info.scroll = mouse_scroll; + + break; + case JS_UP: // up + if (prev_js == JS_UP) { + mouse_scroll--; + } else { + mouse_scroll = -1; + } + debug.printf("up scroll = %0d\r\n", mouse_info.scroll); + reset_tm_joystick_dc(); + mouse_info.scroll = mouse_scroll; + break; + } + + + if (tm_joystick_dc.read_ms() > 1000) { // timeout for double-click detection + reset_tm_joystick_dc(); + } + + prev_js = joyb; +} + + +void sample_mma() // Accelerometer value ranges from -1.5 to 1.5 +{ + mma_g.x = mma.x(); + mma_g.y = mma.y(); + mma_g.z = mma.z(); + G_int_t current; + + if (mma_g.x > peaks.max_x) { + peaks.max_x = mma_g.x; + } else if (mma_g.x < peaks.min_x) { + peaks.min_x = mma_g.x; + } + if (mma_g.y > peaks.max_y) { + peaks.max_y = mma_g.y; + } else if (mma_g.y < peaks.min_y) { + peaks.min_y = mma_g.y; + } + if (mma_g.z > peaks.max_z) { + peaks.max_z = mma_g.z; + } else if (mma_g.z < peaks.min_z) { + peaks.min_z = mma_g.z; + } + + current = conv_g2int(mma_g); + if (calib_on) { + calib_mma(current); + } + mouse_info.x = current.x - offset.x; + mouse_info.y = current.y - offset.y; + mouse_info.z = current.z - offset.z; + detect_mma_rest(); +} + +void drive_mouse() +{ + // x-direction is reversed on PC screen + mouse.move(-mouse_info.x, mouse_info.y); + mouse.press(mouse_info.button); + mouse.scroll(mouse_info.scroll); + if (mouse_info.dc) { + mouse.doubleClick(); + } +} + +// Used for debugging +void print_debug_msg() +{ + if (debug_on) { + switch (debug_sel) { + case JS_LEFT: + debug.printf("Mx = %1.2f, mx = %1.2f ", peaks.max_x, peaks.min_x); + debug.printf("My = %1.2f, my = %1.2f ", peaks.max_y, peaks.min_y); + debug.printf("Mz = %1.2f, mz = %1.2f\r\n", peaks.max_z, peaks.min_z); + break; + case JS_CENTER: + debug.printf("x=%1.2f y=%1.2f z=%1.2f\r\n", mma_g.x, mma_g.y, mma_g.z); + debug.printf("x=%0d, y=%0d, z=%0d, button=%0d, scroll=%0d, dc=%0d\r\n\n", + mouse_info.x, mouse_info.y, mouse_info.z, mouse_info.button, + mouse_info.scroll, mouse_info.dc); + break; + case JS_RIGHT: + debug.printf("offset.x=%0d, y=%0d, z=%0d\r\n", offset.x, offset.y, offset.z); + break; + } + } +} + +// calibrate the accelerometer for leveling +void calib_mma(const G_int_t current) +{ + static uint8_t ctr = 0; + static G_int_t prev[CALIB_SMPLS]; // average array + + int temp; + + if (ctr == 0) { + lcd.cls(); + lcd.locate(0,0); + lcd.printf("Calibrating mma"); + wait(3); + } else { + lcd.printf("."); + } + prev[ctr++] = current; + + if (ctr == CALIB_SMPLS) { + temp = 0; + for (uint8_t i=0; i<CALIB_SMPLS; i++) { + debug.printf("CALIB[%0d]: x=%0d, y=%0d, z=%0d\r\n", i, prev[i].x, prev[i].y, prev[i].z); + temp += prev[i].x; + } + offset.x = temp/CALIB_SMPLS; // average + + temp = 0; + for (uint8_t i=0; i<CALIB_SMPLS; i++) { + temp += prev[i].y; + } + offset.y = temp/CALIB_SMPLS; + + temp = 0; + for (uint8_t i=0; i<CALIB_SMPLS; i++) { + temp += prev[i].z; + } + offset.z = temp/CALIB_SMPLS; + + ctr = 0; + calib_on = 0; // calibration done + lcd.cls(); + lcd.locate(0,0); + lcd.printf("Calibration Completed!\n"); + wait(1); + } +} + +void detect_mma_rest () +{ + if ((abs(mouse_info.z) <= 0.06*SCALE_Z) && + (abs(mouse_info.x) <= 0.10*SCALE_X) && + (abs(mouse_info.y) <= 0.10*SCALE_Y)) { + mouse_info.x = 0; + mouse_info.y = 0; + } +} + +// convert mma signed g float value into signed int value +G_int_t conv_g2int (G_float_t mma_g) +{ + G_int_t temp; + + temp.x = (mma_g.x * SCALE_X); + temp.y = (mma_g.y * SCALE_Y); + temp.z = (mma_g.z * SCALE_Z); + return temp; +} + +// +void flash_led_alive() +{ + static bool led_state = 0; + led_alive = led_state; + led_state = !led_state; + +} + +int8_t init_accelestick() +{ + lcd.cls(); + reset_tm_joystick_dc(); + + offset.x = 0; + offset.y = 0; + offset.z = 1.0*SCALE_Z; + + peaks.max_x=ACCEL_MIN, peaks.max_y=ACCEL_MIN, peaks.max_z=ACCEL_MIN; + peaks.min_x=ACCEL_MAX, peaks.min_y=ACCEL_MAX, peaks.min_z=ACCEL_MAX; + + if (!mma.testConnection()) { + lcd.printf("Error in MMA init\n"); + return -1; + } + tk_led_alive.attach(&flash_led_alive, 1.0); + tk_print_debug.attach(&print_debug_msg, 1.0); + return 0; + +} + +int8_t run_accelestick() +{ + int8_t status; + + status = init_accelestick(); + + if (status != 0) { + return -1; + } + + while(1) { + get_joystick_input(); + sample_mma(); + drive_mouse(); + } + +} + +int main() +{ + run_accelestick(); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/accelestick.h Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,100 @@ +#include <stdlib.h> +#include "mbed.h" + +#ifndef ACCELESTICK_H +#define ACCELESTICK_H + +#include "MMA7660.h" // Accelerometer API +#include "C12832_lcd.h" // LCD API +#include "USBMouseKeyboard.h" + +#define SCALE_X 50 // g value has noise about 0.05 +#define SCALE_Y SCALE_X +#define SCALE_Z SCALE_X +#define ACCEL_MIN -1.5 +#define ACCEL_MAX 1.5 + +#define CALIB_SMPLS 16 // number of samples used for calibrating accelerometer + +// Joystick button values based on joyb declaration +#define JS_NONE 0 +#define JS_DOWN 1 +#define JS_LEFT 2 +#define JS_CENTER 4 +#define JS_UP 8 +#define JS_RIGHT 16 + +//--- Global Variables declaration ---// + +C12832_LCD lcd; // for debugging +MMA7660 mma(p28, p27); // I2C Accelerometer +USBMouseKeyboard mouse; +DigitalOut led_alive(LED4); +DigitalOut leds[] = {LED1, LED2, LED3}; + +DigitalIn jd = p12; +DigitalIn jl = p13; +DigitalIn jc = p14; +DigitalIn ju = p15; +DigitalIn jr = p16; +BusIn joyb(p12, p13, p14, p15, p16); + +typedef struct s_max_min { + float max_x, max_y, max_z; + float min_x, min_y, min_z; +} Max_min_t; + +typedef struct s_int_g { + int16_t x, y, z; +} G_int_t; + +typedef struct s_float_pos { + float x, y, z; +} G_float_t; + +typedef struct +{ + int16_t x, y, z; // x, y, z position + uint8_t button; // left button, 1 = left, 2 = center, 4 = middle + bool dc; // double click + int8_t scroll; // <0 to go up, >0 to go down +} Mouse_state_t; + +Max_min_t peaks; +Mouse_state_t mouse_info; +G_int_t offset; // calibration offset value + +bool calib_on = 0; +bool debug_on = 0; +uint8_t tm_joystick_running = 0, debug_sel; + +G_float_t mma_g; // g values from accelerometer + +Ticker tk_led_alive; // Ticker for flashing LED as program alive beacon +Ticker tk_print_debug;// Ticker for printing debug information +Timer tm_joystick_dc; // Timer for joystick double-click detection +RawSerial debug(USBTX, USBRX); + +// End of Global Variable Declaration + + +//--- Functions Declaration ---// + + // calibrate accelerometer + void calib_mma(G_int_t current); + + // convert floating MMA g value into integer + int16_t scale_g(int8_t g); + G_int_t conv_g2int(G_float_t mma_g); + + // detect MMA at rest + void detect_mma_rest(); + + // Sample joystick for button press + void get_joystick_input(); + + inline void reset_tm_joystick_dc(); + int8_t init_accelestick(); + int8_t run_accelestick(); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,9 @@ +/* +#include "accelestick.h" + +int main() +{ + run_accelestick(); + +} +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sat Mar 15 09:32:43 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/8e73be2a2ac1 \ No newline at end of file