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
accelestick.cpp@0:22bdcdc386df, 2014-03-15 (annotated)
- Committer:
- thlu
- Date:
- Sat Mar 15 09:32:43 2014 +0000
- Revision:
- 0:22bdcdc386df
- Child:
- 1:03d0f8a4a2d7
Got calibration working using x,y, and z-axes
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
thlu | 0:22bdcdc386df | 1 | #include "accelestick.h" |
thlu | 0:22bdcdc386df | 2 | |
thlu | 0:22bdcdc386df | 3 | inline void reset_tm_joystick_dc() |
thlu | 0:22bdcdc386df | 4 | { |
thlu | 0:22bdcdc386df | 5 | tm_joystick_running = 0; |
thlu | 0:22bdcdc386df | 6 | tm_joystick_dc.stop(); |
thlu | 0:22bdcdc386df | 7 | tm_joystick_dc.reset(); |
thlu | 0:22bdcdc386df | 8 | } |
thlu | 0:22bdcdc386df | 9 | |
thlu | 0:22bdcdc386df | 10 | // This function checks for joystick button presses which emulate a mouse's |
thlu | 0:22bdcdc386df | 11 | // left button, right button, middle button, double click, and scroll |
thlu | 0:22bdcdc386df | 12 | // features. Double click requires a timer |
thlu | 0:22bdcdc386df | 13 | void get_joystick_input() |
thlu | 0:22bdcdc386df | 14 | { |
thlu | 0:22bdcdc386df | 15 | static uint8_t prev_js = 0; |
thlu | 0:22bdcdc386df | 16 | static bool debug_sel_en = 0; |
thlu | 0:22bdcdc386df | 17 | static int mouse_scroll = 0; |
thlu | 0:22bdcdc386df | 18 | |
thlu | 0:22bdcdc386df | 19 | mouse_info.button = 0; |
thlu | 0:22bdcdc386df | 20 | mouse_info.scroll = 0; |
thlu | 0:22bdcdc386df | 21 | mouse_info.dc = 0; |
thlu | 0:22bdcdc386df | 22 | |
thlu | 0:22bdcdc386df | 23 | if (debug_on && debug_sel_en && (joyb != JS_NONE)) { |
thlu | 0:22bdcdc386df | 24 | debug_sel_en = 0; |
thlu | 0:22bdcdc386df | 25 | debug_sel = joyb; |
thlu | 0:22bdcdc386df | 26 | } |
thlu | 0:22bdcdc386df | 27 | |
thlu | 0:22bdcdc386df | 28 | if (debug_on && (debug_sel == JS_NONE) && (joyb == JS_NONE)) { |
thlu | 0:22bdcdc386df | 29 | debug_sel_en = 1; |
thlu | 0:22bdcdc386df | 30 | } |
thlu | 0:22bdcdc386df | 31 | |
thlu | 0:22bdcdc386df | 32 | switch(joyb) { // 1 = down, 2 = left, 4 = center, 8 = up, 16 = right |
thlu | 0:22bdcdc386df | 33 | case JS_LEFT: |
thlu | 0:22bdcdc386df | 34 | // 1 click = left button, 2 clicks = double click |
thlu | 0:22bdcdc386df | 35 | if ((prev_js != JS_LEFT) && (tm_joystick_running == JS_LEFT)) { // double click |
thlu | 0:22bdcdc386df | 36 | mouse_info.dc = 1; |
thlu | 0:22bdcdc386df | 37 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 38 | } else if (!tm_joystick_running) { |
thlu | 0:22bdcdc386df | 39 | tm_joystick_running = JS_LEFT; |
thlu | 0:22bdcdc386df | 40 | tm_joystick_dc.start(); |
thlu | 0:22bdcdc386df | 41 | } |
thlu | 0:22bdcdc386df | 42 | mouse_info.button = MOUSE_LEFT; |
thlu | 0:22bdcdc386df | 43 | break; |
thlu | 0:22bdcdc386df | 44 | case JS_CENTER: // center |
thlu | 0:22bdcdc386df | 45 | if ((prev_js != JS_CENTER) && (tm_joystick_running == JS_CENTER)) { // double click |
thlu | 0:22bdcdc386df | 46 | calib_on = 1; |
thlu | 0:22bdcdc386df | 47 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 48 | } else if (!tm_joystick_running) { |
thlu | 0:22bdcdc386df | 49 | tm_joystick_running = JS_CENTER; |
thlu | 0:22bdcdc386df | 50 | tm_joystick_dc.start(); |
thlu | 0:22bdcdc386df | 51 | |
thlu | 0:22bdcdc386df | 52 | } |
thlu | 0:22bdcdc386df | 53 | mouse_info.button = MOUSE_MIDDLE; |
thlu | 0:22bdcdc386df | 54 | break; |
thlu | 0:22bdcdc386df | 55 | case JS_RIGHT: |
thlu | 0:22bdcdc386df | 56 | if ((prev_js != JS_RIGHT) && (tm_joystick_running == JS_RIGHT)) { |
thlu | 0:22bdcdc386df | 57 | debug_on = !debug_on; |
thlu | 0:22bdcdc386df | 58 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 59 | lcd.cls(); |
thlu | 0:22bdcdc386df | 60 | lcd.locate(0,0); |
thlu | 0:22bdcdc386df | 61 | if (debug_on) { |
thlu | 0:22bdcdc386df | 62 | lcd.printf("Debug print is ON\n"); |
thlu | 0:22bdcdc386df | 63 | debug_sel = JS_NONE; |
thlu | 0:22bdcdc386df | 64 | debug_sel_en = 0; |
thlu | 0:22bdcdc386df | 65 | } |
thlu | 0:22bdcdc386df | 66 | } else if (!tm_joystick_running) { |
thlu | 0:22bdcdc386df | 67 | tm_joystick_running = JS_RIGHT; |
thlu | 0:22bdcdc386df | 68 | tm_joystick_dc.start(); |
thlu | 0:22bdcdc386df | 69 | } |
thlu | 0:22bdcdc386df | 70 | mouse_info.button = MOUSE_RIGHT; |
thlu | 0:22bdcdc386df | 71 | break; |
thlu | 0:22bdcdc386df | 72 | case JS_DOWN: // down |
thlu | 0:22bdcdc386df | 73 | if (prev_js == JS_DOWN) { |
thlu | 0:22bdcdc386df | 74 | mouse_scroll++; |
thlu | 0:22bdcdc386df | 75 | } else { |
thlu | 0:22bdcdc386df | 76 | mouse_scroll = 1; // >0 means down |
thlu | 0:22bdcdc386df | 77 | } |
thlu | 0:22bdcdc386df | 78 | debug.printf("down scroll = %0d\r\n", mouse_info.scroll); |
thlu | 0:22bdcdc386df | 79 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 80 | mouse_info.scroll = mouse_scroll; |
thlu | 0:22bdcdc386df | 81 | |
thlu | 0:22bdcdc386df | 82 | break; |
thlu | 0:22bdcdc386df | 83 | case JS_UP: // up |
thlu | 0:22bdcdc386df | 84 | if (prev_js == JS_UP) { |
thlu | 0:22bdcdc386df | 85 | mouse_scroll--; |
thlu | 0:22bdcdc386df | 86 | } else { |
thlu | 0:22bdcdc386df | 87 | mouse_scroll = -1; |
thlu | 0:22bdcdc386df | 88 | } |
thlu | 0:22bdcdc386df | 89 | debug.printf("up scroll = %0d\r\n", mouse_info.scroll); |
thlu | 0:22bdcdc386df | 90 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 91 | mouse_info.scroll = mouse_scroll; |
thlu | 0:22bdcdc386df | 92 | break; |
thlu | 0:22bdcdc386df | 93 | } |
thlu | 0:22bdcdc386df | 94 | |
thlu | 0:22bdcdc386df | 95 | |
thlu | 0:22bdcdc386df | 96 | if (tm_joystick_dc.read_ms() > 1000) { // timeout for double-click detection |
thlu | 0:22bdcdc386df | 97 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 98 | } |
thlu | 0:22bdcdc386df | 99 | |
thlu | 0:22bdcdc386df | 100 | prev_js = joyb; |
thlu | 0:22bdcdc386df | 101 | } |
thlu | 0:22bdcdc386df | 102 | |
thlu | 0:22bdcdc386df | 103 | |
thlu | 0:22bdcdc386df | 104 | void sample_mma() // Accelerometer value ranges from -1.5 to 1.5 |
thlu | 0:22bdcdc386df | 105 | { |
thlu | 0:22bdcdc386df | 106 | mma_g.x = mma.x(); |
thlu | 0:22bdcdc386df | 107 | mma_g.y = mma.y(); |
thlu | 0:22bdcdc386df | 108 | mma_g.z = mma.z(); |
thlu | 0:22bdcdc386df | 109 | G_int_t current; |
thlu | 0:22bdcdc386df | 110 | |
thlu | 0:22bdcdc386df | 111 | if (mma_g.x > peaks.max_x) { |
thlu | 0:22bdcdc386df | 112 | peaks.max_x = mma_g.x; |
thlu | 0:22bdcdc386df | 113 | } else if (mma_g.x < peaks.min_x) { |
thlu | 0:22bdcdc386df | 114 | peaks.min_x = mma_g.x; |
thlu | 0:22bdcdc386df | 115 | } |
thlu | 0:22bdcdc386df | 116 | if (mma_g.y > peaks.max_y) { |
thlu | 0:22bdcdc386df | 117 | peaks.max_y = mma_g.y; |
thlu | 0:22bdcdc386df | 118 | } else if (mma_g.y < peaks.min_y) { |
thlu | 0:22bdcdc386df | 119 | peaks.min_y = mma_g.y; |
thlu | 0:22bdcdc386df | 120 | } |
thlu | 0:22bdcdc386df | 121 | if (mma_g.z > peaks.max_z) { |
thlu | 0:22bdcdc386df | 122 | peaks.max_z = mma_g.z; |
thlu | 0:22bdcdc386df | 123 | } else if (mma_g.z < peaks.min_z) { |
thlu | 0:22bdcdc386df | 124 | peaks.min_z = mma_g.z; |
thlu | 0:22bdcdc386df | 125 | } |
thlu | 0:22bdcdc386df | 126 | |
thlu | 0:22bdcdc386df | 127 | current = conv_g2int(mma_g); |
thlu | 0:22bdcdc386df | 128 | if (calib_on) { |
thlu | 0:22bdcdc386df | 129 | calib_mma(current); |
thlu | 0:22bdcdc386df | 130 | } |
thlu | 0:22bdcdc386df | 131 | mouse_info.x = current.x - offset.x; |
thlu | 0:22bdcdc386df | 132 | mouse_info.y = current.y - offset.y; |
thlu | 0:22bdcdc386df | 133 | mouse_info.z = current.z - offset.z; |
thlu | 0:22bdcdc386df | 134 | detect_mma_rest(); |
thlu | 0:22bdcdc386df | 135 | } |
thlu | 0:22bdcdc386df | 136 | |
thlu | 0:22bdcdc386df | 137 | void drive_mouse() |
thlu | 0:22bdcdc386df | 138 | { |
thlu | 0:22bdcdc386df | 139 | // x-direction is reversed on PC screen |
thlu | 0:22bdcdc386df | 140 | mouse.move(-mouse_info.x, mouse_info.y); |
thlu | 0:22bdcdc386df | 141 | mouse.press(mouse_info.button); |
thlu | 0:22bdcdc386df | 142 | mouse.scroll(mouse_info.scroll); |
thlu | 0:22bdcdc386df | 143 | if (mouse_info.dc) { |
thlu | 0:22bdcdc386df | 144 | mouse.doubleClick(); |
thlu | 0:22bdcdc386df | 145 | } |
thlu | 0:22bdcdc386df | 146 | } |
thlu | 0:22bdcdc386df | 147 | |
thlu | 0:22bdcdc386df | 148 | // Used for debugging |
thlu | 0:22bdcdc386df | 149 | void print_debug_msg() |
thlu | 0:22bdcdc386df | 150 | { |
thlu | 0:22bdcdc386df | 151 | if (debug_on) { |
thlu | 0:22bdcdc386df | 152 | switch (debug_sel) { |
thlu | 0:22bdcdc386df | 153 | case JS_LEFT: |
thlu | 0:22bdcdc386df | 154 | debug.printf("Mx = %1.2f, mx = %1.2f ", peaks.max_x, peaks.min_x); |
thlu | 0:22bdcdc386df | 155 | debug.printf("My = %1.2f, my = %1.2f ", peaks.max_y, peaks.min_y); |
thlu | 0:22bdcdc386df | 156 | debug.printf("Mz = %1.2f, mz = %1.2f\r\n", peaks.max_z, peaks.min_z); |
thlu | 0:22bdcdc386df | 157 | break; |
thlu | 0:22bdcdc386df | 158 | case JS_CENTER: |
thlu | 0:22bdcdc386df | 159 | debug.printf("x=%1.2f y=%1.2f z=%1.2f\r\n", mma_g.x, mma_g.y, mma_g.z); |
thlu | 0:22bdcdc386df | 160 | debug.printf("x=%0d, y=%0d, z=%0d, button=%0d, scroll=%0d, dc=%0d\r\n\n", |
thlu | 0:22bdcdc386df | 161 | mouse_info.x, mouse_info.y, mouse_info.z, mouse_info.button, |
thlu | 0:22bdcdc386df | 162 | mouse_info.scroll, mouse_info.dc); |
thlu | 0:22bdcdc386df | 163 | break; |
thlu | 0:22bdcdc386df | 164 | case JS_RIGHT: |
thlu | 0:22bdcdc386df | 165 | debug.printf("offset.x=%0d, y=%0d, z=%0d\r\n", offset.x, offset.y, offset.z); |
thlu | 0:22bdcdc386df | 166 | break; |
thlu | 0:22bdcdc386df | 167 | } |
thlu | 0:22bdcdc386df | 168 | } |
thlu | 0:22bdcdc386df | 169 | } |
thlu | 0:22bdcdc386df | 170 | |
thlu | 0:22bdcdc386df | 171 | // calibrate the accelerometer for leveling |
thlu | 0:22bdcdc386df | 172 | void calib_mma(const G_int_t current) |
thlu | 0:22bdcdc386df | 173 | { |
thlu | 0:22bdcdc386df | 174 | static uint8_t ctr = 0; |
thlu | 0:22bdcdc386df | 175 | static G_int_t prev[CALIB_SMPLS]; // average array |
thlu | 0:22bdcdc386df | 176 | |
thlu | 0:22bdcdc386df | 177 | int temp; |
thlu | 0:22bdcdc386df | 178 | |
thlu | 0:22bdcdc386df | 179 | if (ctr == 0) { |
thlu | 0:22bdcdc386df | 180 | lcd.cls(); |
thlu | 0:22bdcdc386df | 181 | lcd.locate(0,0); |
thlu | 0:22bdcdc386df | 182 | lcd.printf("Calibrating mma"); |
thlu | 0:22bdcdc386df | 183 | wait(3); |
thlu | 0:22bdcdc386df | 184 | } else { |
thlu | 0:22bdcdc386df | 185 | lcd.printf("."); |
thlu | 0:22bdcdc386df | 186 | } |
thlu | 0:22bdcdc386df | 187 | prev[ctr++] = current; |
thlu | 0:22bdcdc386df | 188 | |
thlu | 0:22bdcdc386df | 189 | if (ctr == CALIB_SMPLS) { |
thlu | 0:22bdcdc386df | 190 | temp = 0; |
thlu | 0:22bdcdc386df | 191 | for (uint8_t i=0; i<CALIB_SMPLS; i++) { |
thlu | 0:22bdcdc386df | 192 | debug.printf("CALIB[%0d]: x=%0d, y=%0d, z=%0d\r\n", i, prev[i].x, prev[i].y, prev[i].z); |
thlu | 0:22bdcdc386df | 193 | temp += prev[i].x; |
thlu | 0:22bdcdc386df | 194 | } |
thlu | 0:22bdcdc386df | 195 | offset.x = temp/CALIB_SMPLS; // average |
thlu | 0:22bdcdc386df | 196 | |
thlu | 0:22bdcdc386df | 197 | temp = 0; |
thlu | 0:22bdcdc386df | 198 | for (uint8_t i=0; i<CALIB_SMPLS; i++) { |
thlu | 0:22bdcdc386df | 199 | temp += prev[i].y; |
thlu | 0:22bdcdc386df | 200 | } |
thlu | 0:22bdcdc386df | 201 | offset.y = temp/CALIB_SMPLS; |
thlu | 0:22bdcdc386df | 202 | |
thlu | 0:22bdcdc386df | 203 | temp = 0; |
thlu | 0:22bdcdc386df | 204 | for (uint8_t i=0; i<CALIB_SMPLS; i++) { |
thlu | 0:22bdcdc386df | 205 | temp += prev[i].z; |
thlu | 0:22bdcdc386df | 206 | } |
thlu | 0:22bdcdc386df | 207 | offset.z = temp/CALIB_SMPLS; |
thlu | 0:22bdcdc386df | 208 | |
thlu | 0:22bdcdc386df | 209 | ctr = 0; |
thlu | 0:22bdcdc386df | 210 | calib_on = 0; // calibration done |
thlu | 0:22bdcdc386df | 211 | lcd.cls(); |
thlu | 0:22bdcdc386df | 212 | lcd.locate(0,0); |
thlu | 0:22bdcdc386df | 213 | lcd.printf("Calibration Completed!\n"); |
thlu | 0:22bdcdc386df | 214 | wait(1); |
thlu | 0:22bdcdc386df | 215 | } |
thlu | 0:22bdcdc386df | 216 | } |
thlu | 0:22bdcdc386df | 217 | |
thlu | 0:22bdcdc386df | 218 | void detect_mma_rest () |
thlu | 0:22bdcdc386df | 219 | { |
thlu | 0:22bdcdc386df | 220 | if ((abs(mouse_info.z) <= 0.06*SCALE_Z) && |
thlu | 0:22bdcdc386df | 221 | (abs(mouse_info.x) <= 0.10*SCALE_X) && |
thlu | 0:22bdcdc386df | 222 | (abs(mouse_info.y) <= 0.10*SCALE_Y)) { |
thlu | 0:22bdcdc386df | 223 | mouse_info.x = 0; |
thlu | 0:22bdcdc386df | 224 | mouse_info.y = 0; |
thlu | 0:22bdcdc386df | 225 | } |
thlu | 0:22bdcdc386df | 226 | } |
thlu | 0:22bdcdc386df | 227 | |
thlu | 0:22bdcdc386df | 228 | // convert mma signed g float value into signed int value |
thlu | 0:22bdcdc386df | 229 | G_int_t conv_g2int (G_float_t mma_g) |
thlu | 0:22bdcdc386df | 230 | { |
thlu | 0:22bdcdc386df | 231 | G_int_t temp; |
thlu | 0:22bdcdc386df | 232 | |
thlu | 0:22bdcdc386df | 233 | temp.x = (mma_g.x * SCALE_X); |
thlu | 0:22bdcdc386df | 234 | temp.y = (mma_g.y * SCALE_Y); |
thlu | 0:22bdcdc386df | 235 | temp.z = (mma_g.z * SCALE_Z); |
thlu | 0:22bdcdc386df | 236 | return temp; |
thlu | 0:22bdcdc386df | 237 | } |
thlu | 0:22bdcdc386df | 238 | |
thlu | 0:22bdcdc386df | 239 | // |
thlu | 0:22bdcdc386df | 240 | void flash_led_alive() |
thlu | 0:22bdcdc386df | 241 | { |
thlu | 0:22bdcdc386df | 242 | static bool led_state = 0; |
thlu | 0:22bdcdc386df | 243 | led_alive = led_state; |
thlu | 0:22bdcdc386df | 244 | led_state = !led_state; |
thlu | 0:22bdcdc386df | 245 | |
thlu | 0:22bdcdc386df | 246 | } |
thlu | 0:22bdcdc386df | 247 | |
thlu | 0:22bdcdc386df | 248 | int8_t init_accelestick() |
thlu | 0:22bdcdc386df | 249 | { |
thlu | 0:22bdcdc386df | 250 | lcd.cls(); |
thlu | 0:22bdcdc386df | 251 | reset_tm_joystick_dc(); |
thlu | 0:22bdcdc386df | 252 | |
thlu | 0:22bdcdc386df | 253 | offset.x = 0; |
thlu | 0:22bdcdc386df | 254 | offset.y = 0; |
thlu | 0:22bdcdc386df | 255 | offset.z = 1.0*SCALE_Z; |
thlu | 0:22bdcdc386df | 256 | |
thlu | 0:22bdcdc386df | 257 | peaks.max_x=ACCEL_MIN, peaks.max_y=ACCEL_MIN, peaks.max_z=ACCEL_MIN; |
thlu | 0:22bdcdc386df | 258 | peaks.min_x=ACCEL_MAX, peaks.min_y=ACCEL_MAX, peaks.min_z=ACCEL_MAX; |
thlu | 0:22bdcdc386df | 259 | |
thlu | 0:22bdcdc386df | 260 | if (!mma.testConnection()) { |
thlu | 0:22bdcdc386df | 261 | lcd.printf("Error in MMA init\n"); |
thlu | 0:22bdcdc386df | 262 | return -1; |
thlu | 0:22bdcdc386df | 263 | } |
thlu | 0:22bdcdc386df | 264 | tk_led_alive.attach(&flash_led_alive, 1.0); |
thlu | 0:22bdcdc386df | 265 | tk_print_debug.attach(&print_debug_msg, 1.0); |
thlu | 0:22bdcdc386df | 266 | return 0; |
thlu | 0:22bdcdc386df | 267 | |
thlu | 0:22bdcdc386df | 268 | } |
thlu | 0:22bdcdc386df | 269 | |
thlu | 0:22bdcdc386df | 270 | int8_t run_accelestick() |
thlu | 0:22bdcdc386df | 271 | { |
thlu | 0:22bdcdc386df | 272 | int8_t status; |
thlu | 0:22bdcdc386df | 273 | |
thlu | 0:22bdcdc386df | 274 | status = init_accelestick(); |
thlu | 0:22bdcdc386df | 275 | |
thlu | 0:22bdcdc386df | 276 | if (status != 0) { |
thlu | 0:22bdcdc386df | 277 | return -1; |
thlu | 0:22bdcdc386df | 278 | } |
thlu | 0:22bdcdc386df | 279 | |
thlu | 0:22bdcdc386df | 280 | while(1) { |
thlu | 0:22bdcdc386df | 281 | get_joystick_input(); |
thlu | 0:22bdcdc386df | 282 | sample_mma(); |
thlu | 0:22bdcdc386df | 283 | drive_mouse(); |
thlu | 0:22bdcdc386df | 284 | } |
thlu | 0:22bdcdc386df | 285 | |
thlu | 0:22bdcdc386df | 286 | } |
thlu | 0:22bdcdc386df | 287 | |
thlu | 0:22bdcdc386df | 288 | int main() |
thlu | 0:22bdcdc386df | 289 | { |
thlu | 0:22bdcdc386df | 290 | run_accelestick(); |
thlu | 0:22bdcdc386df | 291 | } |