DreamForce 2013 Mini-Hack Challenge Project

Dependencies:   ADXL345 USBDevice filter mbed

Fork of df-minihack-slingshot by Doug Anson

Committer:
ansond
Date:
Wed Oct 30 19:07:09 2013 +0000
Revision:
0:a2c33a8eded1
Child:
1:d9d593d4ea39
initial check-in

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ansond 0:a2c33a8eded1 1 /* mbed USB Slingshot,
ansond 0:a2c33a8eded1 2 *
ansond 0:a2c33a8eded1 3 * Copyright (c) 2010-2011 mbed.org, MIT License
ansond 0:a2c33a8eded1 4 *
ansond 0:a2c33a8eded1 5 * smokrani, sford, danson, sgrove
ansond 0:a2c33a8eded1 6 *
ansond 0:a2c33a8eded1 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
ansond 0:a2c33a8eded1 8 * and associated documentation files (the "Software"), to deal in the Software without
ansond 0:a2c33a8eded1 9 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
ansond 0:a2c33a8eded1 10 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
ansond 0:a2c33a8eded1 11 * Software is furnished to do so, subject to the following conditions:
ansond 0:a2c33a8eded1 12 *
ansond 0:a2c33a8eded1 13 * The above copyright notice and this permission notice shall be included in all copies or
ansond 0:a2c33a8eded1 14 * substantial portions of the Software.
ansond 0:a2c33a8eded1 15 *
ansond 0:a2c33a8eded1 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
ansond 0:a2c33a8eded1 17 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ansond 0:a2c33a8eded1 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
ansond 0:a2c33a8eded1 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ansond 0:a2c33a8eded1 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ansond 0:a2c33a8eded1 21 */
ansond 0:a2c33a8eded1 22
ansond 0:a2c33a8eded1 23 #include "mbed.h"
ansond 0:a2c33a8eded1 24 #include "USBMouse.h"
ansond 0:a2c33a8eded1 25 #include "ADXL345.h"
ansond 0:a2c33a8eded1 26
ansond 0:a2c33a8eded1 27 // Physical interfaces
ansond 0:a2c33a8eded1 28 USBMouse mouse;
ansond 0:a2c33a8eded1 29 ADXL345 accelerometer(p5, p6, p7, p8);
ansond 0:a2c33a8eded1 30 AnalogIn stretch_sensor(p15);
ansond 0:a2c33a8eded1 31 BusOut leds(LED1, LED2, LED3, LED4);
ansond 0:a2c33a8eded1 32
ansond 0:a2c33a8eded1 33 //
ansond 0:a2c33a8eded1 34 // DreamForce 2013 Challenge:
ansond 0:a2c33a8eded1 35 // - Adjust the resultant slingshot angle for the difference between the accelerometer angle and the relative angle of the sling to the slingshot body.
ansond 0:a2c33a8eded1 36 // - Result should be in radians: up > 0 > down just like with get_angle() below - except adjusted!
ansond 0:a2c33a8eded1 37 // - Note: You may need to add some filters to optimize (and stabilize) the readings from the potentiometers
ansond 0:a2c33a8eded1 38 //
ansond 0:a2c33a8eded1 39 float adjust_for_sling_angle(float slingshot_body_angle) {
ansond 0:a2c33a8eded1 40 float modified_angle = slingshot_body_angle; // default
ansond 0:a2c33a8eded1 41
ansond 0:a2c33a8eded1 42 // innovate!!!
ansond 0:a2c33a8eded1 43
ansond 0:a2c33a8eded1 44 // return the modified angle taking into account the sling angle relative to the slingshot body
ansond 0:a2c33a8eded1 45 return modified_angle;
ansond 0:a2c33a8eded1 46 }
ansond 0:a2c33a8eded1 47
ansond 0:a2c33a8eded1 48 // Return slingshot angle in radians, up > 0 > down
ansond 0:a2c33a8eded1 49 float get_angle() {
ansond 0:a2c33a8eded1 50 int readings[3];
ansond 0:a2c33a8eded1 51 accelerometer.getOutput(readings);
ansond 0:a2c33a8eded1 52 float x = (int16_t)readings[0];
ansond 0:a2c33a8eded1 53 float z = (int16_t)readings[2];
ansond 0:a2c33a8eded1 54 return atan(z / x);
ansond 0:a2c33a8eded1 55 }
ansond 0:a2c33a8eded1 56
ansond 0:a2c33a8eded1 57 // Return normalised stretch value based on bounds of all readings seen
ansond 0:a2c33a8eded1 58 float get_stretch() {
ansond 0:a2c33a8eded1 59 static float min_strength = 0.7;
ansond 0:a2c33a8eded1 60 static float max_strength = 0.7;
ansond 0:a2c33a8eded1 61 float current_strength = stretch_sensor.read();
ansond 0:a2c33a8eded1 62 if(current_strength > max_strength) { max_strength = current_strength; }
ansond 0:a2c33a8eded1 63 if(current_strength < min_strength) { min_strength = current_strength; }
ansond 0:a2c33a8eded1 64 float stretch = (current_strength - min_strength) / (max_strength - min_strength);
ansond 0:a2c33a8eded1 65 return 1.0 - stretch;
ansond 0:a2c33a8eded1 66 }
ansond 0:a2c33a8eded1 67
ansond 0:a2c33a8eded1 68 // move mouse to a location relative to the start point, stepping as needed
ansond 0:a2c33a8eded1 69 void move_mouse(int x, int y) {
ansond 0:a2c33a8eded1 70 const int STEP = 10;
ansond 0:a2c33a8eded1 71 static int current_x = 0;
ansond 0:a2c33a8eded1 72 static int current_y = 0;
ansond 0:a2c33a8eded1 73
ansond 0:a2c33a8eded1 74 int move_x = x - current_x;
ansond 0:a2c33a8eded1 75 int move_y = y - current_y;
ansond 0:a2c33a8eded1 76
ansond 0:a2c33a8eded1 77 // Move the mouse, in steps of max step size to ensure it is picked up by OS
ansond 0:a2c33a8eded1 78 while(move_x > STEP) { mouse.move(STEP, 0); move_x -= STEP; }
ansond 0:a2c33a8eded1 79 while(move_x < -STEP) { mouse.move(-STEP, 0); move_x += STEP; }
ansond 0:a2c33a8eded1 80 while(move_y > STEP) { mouse.move(0, STEP); move_y -= STEP; }
ansond 0:a2c33a8eded1 81 while(move_y < -STEP) { mouse.move(0, -STEP); move_y += STEP; }
ansond 0:a2c33a8eded1 82 mouse.move(move_x, move_y);
ansond 0:a2c33a8eded1 83
ansond 0:a2c33a8eded1 84 current_x = x;
ansond 0:a2c33a8eded1 85 current_y = y;
ansond 0:a2c33a8eded1 86 }
ansond 0:a2c33a8eded1 87
ansond 0:a2c33a8eded1 88 template <class T>
ansond 0:a2c33a8eded1 89 T filter(T* array, int len, T value) {
ansond 0:a2c33a8eded1 90 T mean = 0.0;
ansond 0:a2c33a8eded1 91 for(int i = 0; i<len - 1; i++) {
ansond 0:a2c33a8eded1 92 mean += array[i + 1];
ansond 0:a2c33a8eded1 93 array[i] = array[i + 1];
ansond 0:a2c33a8eded1 94 }
ansond 0:a2c33a8eded1 95 mean += value;
ansond 0:a2c33a8eded1 96 array[len - 1] = value;
ansond 0:a2c33a8eded1 97 return mean / (T)len;
ansond 0:a2c33a8eded1 98 }
ansond 0:a2c33a8eded1 99
ansond 0:a2c33a8eded1 100 typedef enum {
ansond 0:a2c33a8eded1 101 WAITING = 2,
ansond 0:a2c33a8eded1 102 AIMING = 4,
ansond 0:a2c33a8eded1 103 FIRING = 8
ansond 0:a2c33a8eded1 104 } state_t;
ansond 0:a2c33a8eded1 105
ansond 0:a2c33a8eded1 106 int main() {
ansond 0:a2c33a8eded1 107 leds = 1;
ansond 0:a2c33a8eded1 108
ansond 0:a2c33a8eded1 109 // setup accelerometer
ansond 0:a2c33a8eded1 110 accelerometer.setPowerControl(0x00);
ansond 0:a2c33a8eded1 111 accelerometer.setDataFormatControl(0x0B);
ansond 0:a2c33a8eded1 112 accelerometer.setDataRate(ADXL345_3200HZ);
ansond 0:a2c33a8eded1 113 accelerometer.setPowerControl(0x08);
ansond 0:a2c33a8eded1 114
ansond 0:a2c33a8eded1 115 state_t state = WAITING;
ansond 0:a2c33a8eded1 116 Timer timer;
ansond 0:a2c33a8eded1 117
ansond 0:a2c33a8eded1 118 float angles[8] = {0};
ansond 0:a2c33a8eded1 119 float stretches[8] = {0};
ansond 0:a2c33a8eded1 120
ansond 0:a2c33a8eded1 121 while(1) {
ansond 0:a2c33a8eded1 122
ansond 0:a2c33a8eded1 123 // get the slingshot parameters
ansond 0:a2c33a8eded1 124 float this_stretch = get_stretch();
ansond 0:a2c33a8eded1 125 float this_angle = get_angle();
ansond 0:a2c33a8eded1 126
ansond 0:a2c33a8eded1 127 // apply some filtering
ansond 0:a2c33a8eded1 128 float stretch = filter(stretches, 8, this_stretch);
ansond 0:a2c33a8eded1 129 float angle = filter(angles, 8, this_angle);
ansond 0:a2c33a8eded1 130
ansond 0:a2c33a8eded1 131 // DreamForce 2013 Challenge: Adjust the angle to account for the relative angle between the sling and the slingshot body
ansond 0:a2c33a8eded1 132 angle = adjust_for_sling_angle(angle);
ansond 0:a2c33a8eded1 133
ansond 0:a2c33a8eded1 134 leds = state;
ansond 0:a2c33a8eded1 135
ansond 0:a2c33a8eded1 136 // act based on the current state
ansond 0:a2c33a8eded1 137 switch (state) {
ansond 0:a2c33a8eded1 138 case WAITING:
ansond 0:a2c33a8eded1 139 if(stretch > 0.5) { // significant stretch, considered starting
ansond 0:a2c33a8eded1 140 mouse.press(MOUSE_LEFT);
ansond 0:a2c33a8eded1 141 state = AIMING;
ansond 0:a2c33a8eded1 142 }
ansond 0:a2c33a8eded1 143 break;
ansond 0:a2c33a8eded1 144
ansond 0:a2c33a8eded1 145 case AIMING:
ansond 0:a2c33a8eded1 146 if(stretch - this_stretch > 0.1) { // rapid de-stretch, considered a fire
ansond 0:a2c33a8eded1 147 mouse.release(MOUSE_LEFT);
ansond 0:a2c33a8eded1 148 move_mouse(0, 0);
ansond 0:a2c33a8eded1 149 timer.start();
ansond 0:a2c33a8eded1 150 state = FIRING;
ansond 0:a2c33a8eded1 151 } else {
ansond 0:a2c33a8eded1 152 int x = 0.0 - cos(angle) * stretch * 200;
ansond 0:a2c33a8eded1 153 int y = sin(angle) * stretch * 200;
ansond 0:a2c33a8eded1 154 move_mouse(x, y);
ansond 0:a2c33a8eded1 155 }
ansond 0:a2c33a8eded1 156 break;
ansond 0:a2c33a8eded1 157
ansond 0:a2c33a8eded1 158 case FIRING:
ansond 0:a2c33a8eded1 159 if(timer > 3.0) {
ansond 0:a2c33a8eded1 160 timer.stop();
ansond 0:a2c33a8eded1 161 timer.reset();
ansond 0:a2c33a8eded1 162 state = WAITING;
ansond 0:a2c33a8eded1 163 }
ansond 0:a2c33a8eded1 164 break;
ansond 0:a2c33a8eded1 165 };
ansond 0:a2c33a8eded1 166
ansond 0:a2c33a8eded1 167 wait(0.01);
ansond 0:a2c33a8eded1 168 }
ansond 0:a2c33a8eded1 169 }