Simon Ford
/
Slingshot
mbed USB Slingshot code
Diff: main.cpp
- Revision:
- 0:6fef570fcbc4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Feb 26 02:51:40 2012 +0000 @@ -0,0 +1,151 @@ +/* mbed USB Slingshot, + * + * Copyright (c) 2010-2011 mbed.org, MIT License + * + * smokrani, sford + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "mbed.h" +#include "USBMouse.h" +#include "ADXL345.h" + +// Physical interfaces +USBMouse mouse; +ADXL345 accelerometer(p5, p6, p7, p8); +AnalogIn stretch_sensor(p15); +BusOut leds(LED1, LED2, LED3, LED4); + +// Return slingshot angle in radians, up > 0 > down +float get_angle() { + int readings[3]; + accelerometer.getOutput(readings); + float x = (int16_t)readings[0]; + float z = (int16_t)readings[2]; + return atan(z / x); +} + +// Return normalised stretch value based on bounds of all readings seen +float get_stretch() { + static float min_strength = 0.7; + static float max_strength = 0.7; + float current_strength = stretch_sensor.read(); + if(current_strength > max_strength) { max_strength = current_strength; } + if(current_strength < min_strength) { min_strength = current_strength; } + float stretch = (current_strength - min_strength) / (max_strength - min_strength); + return 1.0 - stretch; +} + +// move mouse to a location relative to the start point, stepping as needed +void move_mouse(int x, int y) { + const int STEP = 10; + static int current_x = 0; + static int current_y = 0; + + int move_x = x - current_x; + int move_y = y - current_y; + + // Move the mouse, in steps of max step size to ensure it is picked up by OS + while(move_x > STEP) { mouse.move(STEP, 0); move_x -= STEP; } + while(move_x < -STEP) { mouse.move(-STEP, 0); move_x += STEP; } + while(move_y > STEP) { mouse.move(0, STEP); move_y -= STEP; } + while(move_y < -STEP) { mouse.move(0, -STEP); move_y += STEP; } + mouse.move(move_x, move_y); + + current_x = x; + current_y = y; +} + +template <class T> +T filter(T* array, int len, T value) { + T mean = 0.0; + for(int i = 0; i<len - 1; i++) { + mean += array[i + 1]; + array[i] = array[i + 1]; + } + mean += value; + array[len - 1] = value; + return mean / (T)len; +} + +typedef enum { + WAITING = 2, + AIMING = 4, + FIRING = 8 +} state_t; + +int main() { + leds = 1; + + // setup accelerometer + accelerometer.setPowerControl(0x00); + accelerometer.setDataFormatControl(0x0B); + accelerometer.setDataRate(ADXL345_3200HZ); + accelerometer.setPowerControl(0x08); + + state_t state = WAITING; + Timer timer; + + float angles[8] = {0}; + float stretches[8] = {0}; + + while(1) { + + // get the slingshot parameters + float this_stretch = get_stretch(); + float this_angle = get_angle(); + + // apply some filtering + float stretch = filter(stretches, 8, this_stretch); + float angle = filter(angles, 8, this_angle); + + leds = state; + + // act based on the current state + switch (state) { + case WAITING: + if(stretch > 0.5) { // significant stretch, considered starting + mouse.press(MOUSE_LEFT); + state = AIMING; + } + break; + + case AIMING: + if(stretch - this_stretch > 0.1) { // rapid de-stretch, considered a fire + mouse.release(MOUSE_LEFT); + move_mouse(0, 0); + timer.start(); + state = FIRING; + } else { + int x = 0.0 - cos(angle) * stretch * 200; + int y = sin(angle) * stretch * 200; + move_mouse(x, y); + } + break; + + case FIRING: + if(timer > 3.0) { + timer.stop(); + timer.reset(); + state = WAITING; + } + break; + }; + + wait(0.01); + } +}