mbed USB Slingshot code

Dependencies:   mbed ADXL345

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);
+    }
+}