With Stretch Senser and Accelerometer

Dependencies:   ADXL345 USBDevice mbed

Fork of Slingshot by Simon Ford

main.cpp

Committer:
SRINATHMADHU
Date:
2015-10-15
Revision:
1:5a2ea4e2e236
Parent:
0:6fef570fcbc4

File content as of revision 1:5a2ea4e2e236:

/* 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);
    }
}