Project Paint / Mbed 2 deprecated arm_control

Dependencies:   mbed QEI biquadFilter

Committer:
Jankoekenpan
Date:
Fri Nov 04 13:26:28 2016 +0000
Revision:
29:1c5254b27851
Parent:
27:91dc5174333a
documented the processEMG function

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jankoekenpan 15:5d2bce2abd41 1 #include "controller.h"
Jankoekenpan 15:5d2bce2abd41 2 #include "BiQuad.h"
Jankoekenpan 1:7d218e9d2111 3
Jankoekenpan 1:7d218e9d2111 4 // ====== Hardware stuff ======
Jankoekenpan 1:7d218e9d2111 5
Jankoekenpan 15:5d2bce2abd41 6 /* The robot controller */
Jankoekenpan 15:5d2bce2abd41 7 RobotController robotController;
Jankoekenpan 1:7d218e9d2111 8
Jankoekenpan 15:5d2bce2abd41 9 /* The EMG inputs */
Jankoekenpan 5:23c850380b86 10 AnalogIn emg1(A0);
Jankoekenpan 5:23c850380b86 11 AnalogIn emg2(A1);
Jankoekenpan 1:7d218e9d2111 12
Jankoekenpan 15:5d2bce2abd41 13 /* Used in calibration */
Jankoekenpan 15:5d2bce2abd41 14 DigitalIn calibrating(SW2);
Jankoekenpan 15:5d2bce2abd41 15 /* Used to start calibrating */
Jankoekenpan 15:5d2bce2abd41 16 InterruptIn calibrateButton(SW3);
Jankoekenpan 15:5d2bce2abd41 17
Jankoekenpan 15:5d2bce2abd41 18 /* LEDs
Jankoekenpan 15:5d2bce2abd41 19 RED FLICKERING --> Ready to calibrate (press button SW3 to start)
Jankoekenpan 15:5d2bce2abd41 20 GREEN FlICKERING --> Calibration success
Jankoekenpan 15:5d2bce2abd41 21 BLUE --> Busy calibrating
Jankoekenpan 15:5d2bce2abd41 22 */
Jankoekenpan 15:5d2bce2abd41 23 DigitalOut led_red(LED_RED);
Jankoekenpan 15:5d2bce2abd41 24 DigitalOut led_green(LED_GREEN);
Jankoekenpan 15:5d2bce2abd41 25 DigitalOut led_blue(LED_BLUE);
Jankoekenpan 15:5d2bce2abd41 26
Jankoekenpan 22:cda3e5ad89c0 27 /* ABORT! ABORT! */
Jankoekenpan 22:cda3e5ad89c0 28 InterruptIn killButton(D3);
Jankoekenpan 22:cda3e5ad89c0 29
Jankoekenpan 15:5d2bce2abd41 30 /*For debuggin purposes*/
Jankoekenpan 23:dba0233303b6 31 Serial pc(USBTX, USBRX);
Jankoekenpan 8:874fe459b10a 32
Jankoekenpan 8:874fe459b10a 33 //====== Constants =====
Jankoekenpan 1:7d218e9d2111 34
Jankoekenpan 11:57f0ab4d0e99 35 enum RobotCommand{NOTHING, UP, DOWN, FORWARD, BACKWARD};
Jankoekenpan 9:3193094ba3b2 36 enum ProgramState{CALIBRATING, UPDOWN, FORBACK};
Jankoekenpan 1:7d218e9d2111 37
Jankoekenpan 8:874fe459b10a 38 const float sampleFrequency = 500;
Jankoekenpan 8:874fe459b10a 39 const float sampleTime = 1.0f/sampleFrequency;
Jankoekenpan 8:874fe459b10a 40
Jankoekenpan 8:874fe459b10a 41
Jankoekenpan 1:7d218e9d2111 42 //====== Program Variables ======
Jankoekenpan 1:7d218e9d2111 43
Jankoekenpan 15:5d2bce2abd41 44 volatile ProgramState progState;
Jankoekenpan 15:5d2bce2abd41 45 volatile RobotCommand robotCommand;
Jankoekenpan 15:5d2bce2abd41 46
Jankoekenpan 15:5d2bce2abd41 47 /*The 'main' ticker which samples our emg signals at the control state*/
Jankoekenpan 15:5d2bce2abd41 48 Ticker ticker;
Jankoekenpan 15:5d2bce2abd41 49 /*The ticker used for calibration*/
Jankoekenpan 15:5d2bce2abd41 50 Ticker sampler;
Jankoekenpan 15:5d2bce2abd41 51
Jankoekenpan 15:5d2bce2abd41 52 const float sample_frequency = 500.0f; //Hz
Jankoekenpan 15:5d2bce2abd41 53 const float Ts = 1.0f / sample_frequency;
Jankoekenpan 29:1c5254b27851 54
Jankoekenpan 29:1c5254b27851 55 //Counts how many signals have passed. Resets at 50. See processEMG.
Jankoekenpan 29:1c5254b27851 56 volatile int count = 0;
Jankoekenpan 15:5d2bce2abd41 57
Jankoekenpan 15:5d2bce2abd41 58 /*Function used to send data to the motor*/
Jankoekenpan 15:5d2bce2abd41 59 void (*motorFunc)(bool, bool);
Jankoekenpan 15:5d2bce2abd41 60
Jankoekenpan 15:5d2bce2abd41 61
Jankoekenpan 15:5d2bce2abd41 62
Jankoekenpan 15:5d2bce2abd41 63 /* EMG BiQuadChain 1 */
Jankoekenpan 15:5d2bce2abd41 64 BiQuadChain bqc1;
Jankoekenpan 15:5d2bce2abd41 65 //Notch iir filter.
Jankoekenpan 15:5d2bce2abd41 66 //Notch: 50 +- 2 Hz
Jankoekenpan 15:5d2bce2abd41 67 BiQuad bq1(9.93756e-01, -1.89024e+00, 9.93756e-01, -1.89024e+00, 9.87512e-01 );
Jankoekenpan 15:5d2bce2abd41 68
Jankoekenpan 15:5d2bce2abd41 69
Jankoekenpan 15:5d2bce2abd41 70 /* EMG BiQuadChain 2 */
Jankoekenpan 15:5d2bce2abd41 71 BiQuadChain bqc2;
Jankoekenpan 15:5d2bce2abd41 72 //Notch iir filter.
Jankoekenpan 15:5d2bce2abd41 73 //Notch: 50 +- 2 Hz
Jankoekenpan 15:5d2bce2abd41 74 BiQuad bq2( 9.93756e-01, -1.89024e+00, 9.93756e-01, -1.89024e+00, 9.87512e-01 );
Jankoekenpan 15:5d2bce2abd41 75
Jankoekenpan 15:5d2bce2abd41 76
Jankoekenpan 15:5d2bce2abd41 77 // Arrays used in the calibrationi phase
Jankoekenpan 15:5d2bce2abd41 78 // Values in these arrays contain samples that are already notched and rectified.
Jankoekenpan 15:5d2bce2abd41 79 const int calibrateNumEmgCache = 100;
Jankoekenpan 15:5d2bce2abd41 80 float calibrateEmgCache1[calibrateNumEmgCache]; //sorted from new to old;
Jankoekenpan 15:5d2bce2abd41 81 float calibrateEmgCache2[calibrateNumEmgCache]; //sorted from new to old;
Jankoekenpan 15:5d2bce2abd41 82
Jankoekenpan 15:5d2bce2abd41 83 // Arrays used to calculate the moving average
Jankoekenpan 15:5d2bce2abd41 84 // Values in these arrays contain samples that are already notched and rectified.
Jankoekenpan 15:5d2bce2abd41 85 const int numEmgCache = 50;
Jankoekenpan 15:5d2bce2abd41 86 float emgCache1[numEmgCache]; //sorted from new to old;
Jankoekenpan 15:5d2bce2abd41 87 float emgCache2[numEmgCache]; //sorted from new to old;
Jankoekenpan 15:5d2bce2abd41 88
Jankoekenpan 15:5d2bce2abd41 89
Jankoekenpan 15:5d2bce2abd41 90 // Thresholds for the decisioin. by default 0.2,
Jankoekenpan 15:5d2bce2abd41 91 // The values are changed during calibration.
Jankoekenpan 15:5d2bce2abd41 92 volatile float threshold1 = 0.2;
Jankoekenpan 15:5d2bce2abd41 93 volatile float threshold2 = 0.2;
Jankoekenpan 15:5d2bce2abd41 94
Jankoekenpan 15:5d2bce2abd41 95 // The last 50 signals that have been dititalised.
Jankoekenpan 15:5d2bce2abd41 96 // Only contains ones and zeros.
Jankoekenpan 15:5d2bce2abd41 97 int decided1[numEmgCache];
Jankoekenpan 15:5d2bce2abd41 98 int decided2[numEmgCache];
Jankoekenpan 1:7d218e9d2111 99
Jankoekenpan 8:874fe459b10a 100
Jankoekenpan 1:7d218e9d2111 101 //====== Functions ======
Jankoekenpan 1:7d218e9d2111 102
Jankoekenpan 15:5d2bce2abd41 103 // Helper Functions
Jankoekenpan 1:7d218e9d2111 104
Jankoekenpan 15:5d2bce2abd41 105 void resetLeds() {
Jankoekenpan 15:5d2bce2abd41 106 led_red = true;
Jankoekenpan 15:5d2bce2abd41 107 led_green = true;
Jankoekenpan 15:5d2bce2abd41 108 led_blue = true;
Jankoekenpan 15:5d2bce2abd41 109 }
Jankoekenpan 15:5d2bce2abd41 110
Jankoekenpan 15:5d2bce2abd41 111 // Rotates the array one position, replacing the first value with the new value
Jankoekenpan 15:5d2bce2abd41 112 void addFirst(float newValue, float array[], int size) {
Jankoekenpan 15:5d2bce2abd41 113 for (int i = size - 2; i >= 0; i--) {
Jankoekenpan 15:5d2bce2abd41 114 array[i+1] = array[i];
Jankoekenpan 15:5d2bce2abd41 115 }
Jankoekenpan 15:5d2bce2abd41 116 array[0] = newValue;
Jankoekenpan 15:5d2bce2abd41 117 }
Jankoekenpan 15:5d2bce2abd41 118
Jankoekenpan 15:5d2bce2abd41 119 // Rotates the array one position, replacing the first value with the new value
Jankoekenpan 15:5d2bce2abd41 120 void addFirst(int newValue, int array[], int size) {
Jankoekenpan 15:5d2bce2abd41 121 for (int i = size - 2; i >= 0; i--) {
Jankoekenpan 15:5d2bce2abd41 122 array[i+1] = array[i];
Jankoekenpan 15:5d2bce2abd41 123 }
Jankoekenpan 15:5d2bce2abd41 124 array[0] = newValue;
Jankoekenpan 15:5d2bce2abd41 125 }
Jankoekenpan 15:5d2bce2abd41 126
Jankoekenpan 15:5d2bce2abd41 127
Jankoekenpan 15:5d2bce2abd41 128 float sum(float array[], int size) {
Jankoekenpan 15:5d2bce2abd41 129 float sum = 0;
Jankoekenpan 15:5d2bce2abd41 130 for (int i = 0; i < size; i++) {
Jankoekenpan 15:5d2bce2abd41 131 sum += array[i];
Jankoekenpan 15:5d2bce2abd41 132 }
Jankoekenpan 15:5d2bce2abd41 133 return sum;
Jankoekenpan 15:5d2bce2abd41 134 }
Jankoekenpan 15:5d2bce2abd41 135
Jankoekenpan 15:5d2bce2abd41 136 float mean(float array[], int size) {
Jankoekenpan 15:5d2bce2abd41 137 return sum(array, size) / size;
Jankoekenpan 15:5d2bce2abd41 138 }
Jankoekenpan 15:5d2bce2abd41 139
Jankoekenpan 15:5d2bce2abd41 140 // 'Digitize' an analog value by comparing to a threshold
Jankoekenpan 15:5d2bce2abd41 141 int decide(float value, float threshold) {
Jankoekenpan 15:5d2bce2abd41 142 return value < threshold ? 0 : 1;
Jankoekenpan 15:5d2bce2abd41 143 }
Jankoekenpan 15:5d2bce2abd41 144
Jankoekenpan 15:5d2bce2abd41 145 //shifts the array by adding the new emg value up front.
Jankoekenpan 15:5d2bce2abd41 146 //returns the new calculated average
Jankoekenpan 15:5d2bce2abd41 147 float movingAverage(float newValue, float array[], int size) {
Jankoekenpan 15:5d2bce2abd41 148 float sum = 0;
Jankoekenpan 15:5d2bce2abd41 149 for (int i = size - 2; i >= 0; i--) {
Jankoekenpan 15:5d2bce2abd41 150 array[i+1] = array[i];
Jankoekenpan 15:5d2bce2abd41 151 sum += array[i];
Jankoekenpan 15:5d2bce2abd41 152 }
Jankoekenpan 15:5d2bce2abd41 153 array[0] = newValue;
Jankoekenpan 15:5d2bce2abd41 154 sum += newValue;
Jankoekenpan 15:5d2bce2abd41 155 return sum / size;
Jankoekenpan 15:5d2bce2abd41 156 }
Jankoekenpan 15:5d2bce2abd41 157
Jankoekenpan 15:5d2bce2abd41 158
Jankoekenpan 15:5d2bce2abd41 159 float rectifier(float value) {
Jankoekenpan 15:5d2bce2abd41 160 return fabs(value - 0.5f)*2.0f;
Jankoekenpan 1:7d218e9d2111 161 }
Jankoekenpan 1:7d218e9d2111 162
Jankoekenpan 15:5d2bce2abd41 163 void sendToMotor(void (*func)(bool, bool), bool arg1, bool arg2) {
Jankoekenpan 15:5d2bce2abd41 164 func(arg1, arg2);
Jankoekenpan 15:5d2bce2abd41 165 }
Jankoekenpan 15:5d2bce2abd41 166
Jankoekenpan 15:5d2bce2abd41 167
Jankoekenpan 15:5d2bce2abd41 168 // ====== Functions used for calibrations =====
Jankoekenpan 15:5d2bce2abd41 169
Jankoekenpan 15:5d2bce2abd41 170 void sample() {
Jankoekenpan 15:5d2bce2abd41 171 float emgOne = emg1.read();
Jankoekenpan 15:5d2bce2abd41 172 float notch1 = bqc1.step( emgOne );
Jankoekenpan 15:5d2bce2abd41 173
Jankoekenpan 15:5d2bce2abd41 174 float emgTwo = emg2.read();
Jankoekenpan 15:5d2bce2abd41 175 float notch2 = bqc2.step( emgTwo );
Jankoekenpan 15:5d2bce2abd41 176
Jankoekenpan 15:5d2bce2abd41 177 float rect1 = rectifier(notch1);
Jankoekenpan 15:5d2bce2abd41 178 float rect2 = rectifier(notch2);
Jankoekenpan 15:5d2bce2abd41 179
Jankoekenpan 15:5d2bce2abd41 180 float filtered1 = movingAverage( rect1, calibrateEmgCache1, calibrateNumEmgCache);
Jankoekenpan 15:5d2bce2abd41 181 float filtered2 = movingAverage( rect2, calibrateEmgCache2, calibrateNumEmgCache);
Jankoekenpan 15:5d2bce2abd41 182 }
Jankoekenpan 15:5d2bce2abd41 183
Jankoekenpan 15:5d2bce2abd41 184 void calibrate() {
Jankoekenpan 15:5d2bce2abd41 185 while(calibrating) {
Jankoekenpan 15:5d2bce2abd41 186 led_red = false;
Jankoekenpan 15:5d2bce2abd41 187 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 188 led_red = true;
Jankoekenpan 15:5d2bce2abd41 189 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 190 }
Jankoekenpan 15:5d2bce2abd41 191
Jankoekenpan 15:5d2bce2abd41 192 // Button pressed for rest measurement
Jankoekenpan 15:5d2bce2abd41 193 led_red = true;
Jankoekenpan 15:5d2bce2abd41 194 sampler.attach(&sample, Ts);
Jankoekenpan 15:5d2bce2abd41 195 led_blue = false;
Jankoekenpan 15:5d2bce2abd41 196 wait(10);
Jankoekenpan 15:5d2bce2abd41 197 // 10 seconds sampled
Jankoekenpan 15:5d2bce2abd41 198 led_blue = true;
Jankoekenpan 15:5d2bce2abd41 199 sampler.detach();
Jankoekenpan 15:5d2bce2abd41 200 float restAvg1 = mean(calibrateEmgCache1, calibrateNumEmgCache);
Jankoekenpan 15:5d2bce2abd41 201 float restAvg2 = mean(calibrateEmgCache2, calibrateNumEmgCache);
Jankoekenpan 15:5d2bce2abd41 202
Jankoekenpan 15:5d2bce2abd41 203 int i =0;
Jankoekenpan 15:5d2bce2abd41 204 while(i<3) {
Jankoekenpan 15:5d2bce2abd41 205 led_green = false;
Jankoekenpan 15:5d2bce2abd41 206 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 207 led_green = true;
Jankoekenpan 15:5d2bce2abd41 208 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 209 i++;
Jankoekenpan 15:5d2bce2abd41 210 }
Jankoekenpan 15:5d2bce2abd41 211 led_green = true;
Jankoekenpan 15:5d2bce2abd41 212
Jankoekenpan 15:5d2bce2abd41 213 while(calibrating) {
Jankoekenpan 15:5d2bce2abd41 214 led_red = false;
Jankoekenpan 15:5d2bce2abd41 215 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 216 led_red = true;
Jankoekenpan 15:5d2bce2abd41 217 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 218 }
Jankoekenpan 15:5d2bce2abd41 219 // Button pressed for contracted measurement
Jankoekenpan 15:5d2bce2abd41 220 led_red = true;
Jankoekenpan 15:5d2bce2abd41 221 sampler.attach(&sample, Ts);
Jankoekenpan 15:5d2bce2abd41 222 led_blue = false;
Jankoekenpan 15:5d2bce2abd41 223 wait(10);
Jankoekenpan 15:5d2bce2abd41 224
Jankoekenpan 15:5d2bce2abd41 225 // 10 seconds sampled
Jankoekenpan 15:5d2bce2abd41 226 led_blue = true;
Jankoekenpan 15:5d2bce2abd41 227 sampler.detach();
Jankoekenpan 15:5d2bce2abd41 228
Jankoekenpan 15:5d2bce2abd41 229 i =0;
Jankoekenpan 15:5d2bce2abd41 230 while(i<3) {
Jankoekenpan 15:5d2bce2abd41 231 led_green = false;
Jankoekenpan 15:5d2bce2abd41 232 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 233 led_green = true;
Jankoekenpan 15:5d2bce2abd41 234 wait(0.5);
Jankoekenpan 15:5d2bce2abd41 235 i++;
Jankoekenpan 15:5d2bce2abd41 236 }
Jankoekenpan 15:5d2bce2abd41 237
Jankoekenpan 15:5d2bce2abd41 238 float contAvg1 = mean(calibrateEmgCache1, calibrateNumEmgCache);
Jankoekenpan 15:5d2bce2abd41 239 float contAvg2 = mean(calibrateEmgCache2, calibrateNumEmgCache);
Jankoekenpan 15:5d2bce2abd41 240
Jankoekenpan 15:5d2bce2abd41 241 threshold1 = (contAvg1 + restAvg1)/2;
Jankoekenpan 15:5d2bce2abd41 242 threshold2 = (contAvg2 + restAvg2)/2;
Jankoekenpan 15:5d2bce2abd41 243 //pc.printf("threshold1: %f\tthreshold2:%f\n\r", threshold1, threshold2);
Jankoekenpan 9:3193094ba3b2 244
Jankoekenpan 9:3193094ba3b2 245 }
Jankoekenpan 9:3193094ba3b2 246
Jankoekenpan 15:5d2bce2abd41 247 // ===== The main functions called by our main ticker ======
Jankoekenpan 29:1c5254b27851 248
Jankoekenpan 29:1c5254b27851 249 /**
Jankoekenpan 29:1c5254b27851 250 * processEMG function
Jankoekenpan 29:1c5254b27851 251 * This function is called by our ticker.
Jankoekenpan 29:1c5254b27851 252 * This function measures emg and applies the filters.
Jankoekenpan 29:1c5254b27851 253 * out of 50 emg values, a 1 or 0 is chosen depending on which occurs the most
Jankoekenpan 29:1c5254b27851 254 * then that value is used in the motor func.
Jankoekenpan 29:1c5254b27851 255 */
Jankoekenpan 15:5d2bce2abd41 256 void processEMG() {
Jankoekenpan 29:1c5254b27851 257 //read emg
Jankoekenpan 15:5d2bce2abd41 258 float emgOne = emg1.read();
Jankoekenpan 15:5d2bce2abd41 259 float emgTwo = emg2.read();
Jankoekenpan 29:1c5254b27851 260
Jankoekenpan 29:1c5254b27851 261 //apply notch filter
Jankoekenpan 15:5d2bce2abd41 262 float notch1 = bqc1.step( emgOne );
Jankoekenpan 15:5d2bce2abd41 263 float notch2 = bqc2.step( emgTwo );
Jankoekenpan 29:1c5254b27851 264
Jankoekenpan 29:1c5254b27851 265 //then apply rectifier
Jankoekenpan 15:5d2bce2abd41 266 float rect1 = rectifier(notch1);
Jankoekenpan 15:5d2bce2abd41 267 float rect2 = rectifier(notch2);
Jankoekenpan 15:5d2bce2abd41 268
Jankoekenpan 29:1c5254b27851 269 //then apply moving average
Jankoekenpan 15:5d2bce2abd41 270 float filtered1 = movingAverage( rect1, emgCache1, numEmgCache);
Jankoekenpan 15:5d2bce2abd41 271 float filtered2 = movingAverage( rect2, emgCache2, numEmgCache);
Jankoekenpan 1:7d218e9d2111 272
Jankoekenpan 29:1c5254b27851 273 //decide on wether the signal was strong enough (1) or too weak (0)
Jankoekenpan 15:5d2bce2abd41 274 int decide1 = decide(mean(emgCache1, numEmgCache ), threshold1);
Jankoekenpan 15:5d2bce2abd41 275 int decide2 = decide(mean(emgCache2, numEmgCache ), threshold2);
Jankoekenpan 29:1c5254b27851 276
Jankoekenpan 29:1c5254b27851 277 //add boolean value in front of the boolean arrays
Jankoekenpan 15:5d2bce2abd41 278 addFirst(decide1, decided1, numEmgCache);
Jankoekenpan 15:5d2bce2abd41 279 addFirst(decide2, decided2, numEmgCache);
Jankoekenpan 15:5d2bce2abd41 280
Jankoekenpan 29:1c5254b27851 281 //after 50 calls of this function, control the motor.
Jankoekenpan 15:5d2bce2abd41 282 if (count >= 49) {
Jankoekenpan 15:5d2bce2abd41 283 int counter1=0;
Jankoekenpan 15:5d2bce2abd41 284 int counter2=0;
Jankoekenpan 15:5d2bce2abd41 285 for(int i = 0; i < numEmgCache; ++i){
Jankoekenpan 15:5d2bce2abd41 286 if(decided1[i] == 0)
Jankoekenpan 15:5d2bce2abd41 287 ++counter1;
Jankoekenpan 15:5d2bce2abd41 288 if(decided2[i] == 0)
Jankoekenpan 15:5d2bce2abd41 289 ++counter2;
Jankoekenpan 15:5d2bce2abd41 290 }
Jankoekenpan 29:1c5254b27851 291 // avgDecide1 = true if the decided1 array contains mostly ones, otherwise false.
Jankoekenpan 15:5d2bce2abd41 292 int avgDecide1 = counter1 > std::ceil(numEmgCache/2.0) ? 0: 1;
Jankoekenpan 29:1c5254b27851 293 // avgDecide2 = true if the decided2 array contains mostly ones, otherwise false.
Jankoekenpan 15:5d2bce2abd41 294 int avgDecide2 = counter2 > std::ceil(numEmgCache/2.0) ? 0: 1;
Jankoekenpan 29:1c5254b27851 295
Jankoekenpan 29:1c5254b27851 296 // Use these values to contorl the motor.
Jankoekenpan 15:5d2bce2abd41 297 sendToMotor(motorFunc,avgDecide1, avgDecide2);
Jankoekenpan 15:5d2bce2abd41 298
Jankoekenpan 29:1c5254b27851 299 //reset function call count to 0
Jankoekenpan 15:5d2bce2abd41 300 count =0;
Jankoekenpan 15:5d2bce2abd41 301 } else {
Jankoekenpan 15:5d2bce2abd41 302 count++;
Jankoekenpan 15:5d2bce2abd41 303 }
Jankoekenpan 15:5d2bce2abd41 304 }
Jankoekenpan 15:5d2bce2abd41 305
Jankoekenpan 20:66513b3c09b7 306 void getXandY(float &x, float &y) {
Jankoekenpan 20:66513b3c09b7 307 float lower = robotController.getLowerArmLength();
Jankoekenpan 20:66513b3c09b7 308 float upper = robotController.getUpperArmLength();
Jankoekenpan 20:66513b3c09b7 309 getRollerPositionForArmLengths(upper, lower, x, y);
Jankoekenpan 20:66513b3c09b7 310 }
Jankoekenpan 20:66513b3c09b7 311
Jankoekenpan 23:dba0233303b6 312 //wheter the user can still execute a command
Jankoekenpan 23:dba0233303b6 313 Timeout commandDelayer;
Jankoekenpan 23:dba0233303b6 314 volatile bool canCommand = true;
Jankoekenpan 23:dba0233303b6 315 void enableCommand() {
Jankoekenpan 23:dba0233303b6 316 canCommand = true;
Jankoekenpan 23:dba0233303b6 317 }
Jankoekenpan 23:dba0233303b6 318
Jankoekenpan 23:dba0233303b6 319 Timeout commandSequencer;
Jankoekenpan 23:dba0233303b6 320 void doPaintUp() {
Jankoekenpan 23:dba0233303b6 321 robotController.paintUp();
Jankoekenpan 23:dba0233303b6 322 }
Jankoekenpan 23:dba0233303b6 323 void doPaintDown() {
Jankoekenpan 23:dba0233303b6 324 robotController.paintDown();
Jankoekenpan 23:dba0233303b6 325 }
Jankoekenpan 20:66513b3c09b7 326
Jankoekenpan 27:91dc5174333a 327 float xmin = 25;
Jankoekenpan 27:91dc5174333a 328 float xmax = 40;
Jankoekenpan 27:91dc5174333a 329 float ymin = 20;
Jankoekenpan 27:91dc5174333a 330 float ymax = 50;
Jankoekenpan 27:91dc5174333a 331
Jankoekenpan 15:5d2bce2abd41 332 /* executes the robot command */
Jankoekenpan 15:5d2bce2abd41 333 void processCommand(RobotCommand cmd) {
Jankoekenpan 23:dba0233303b6 334 if (!canCommand || cmd == robotCommand) return;
Jankoekenpan 15:5d2bce2abd41 335
Jankoekenpan 15:5d2bce2abd41 336 robotCommand = cmd;
Jankoekenpan 15:5d2bce2abd41 337
Jankoekenpan 23:dba0233303b6 338 //user can only switch commands once every 2 seconds
Jankoekenpan 23:dba0233303b6 339 canCommand = false;
Jankoekenpan 23:dba0233303b6 340 commandDelayer.attach(&enableCommand, 2.0f);
Jankoekenpan 23:dba0233303b6 341
Jankoekenpan 15:5d2bce2abd41 342 switch (robotCommand) {
Jankoekenpan 20:66513b3c09b7 343 float x;
Jankoekenpan 20:66513b3c09b7 344 float y;
Jankoekenpan 15:5d2bce2abd41 345 case UP:
Jankoekenpan 23:dba0233303b6 346 robotController.goToBottom();
Jankoekenpan 23:dba0233303b6 347 commandSequencer.attach(&doPaintUp, 3.0f);
Jankoekenpan 15:5d2bce2abd41 348 break;
Jankoekenpan 15:5d2bce2abd41 349 case DOWN:
Jankoekenpan 23:dba0233303b6 350 robotController.goToTop();
Jankoekenpan 23:dba0233303b6 351 commandSequencer.attach(&doPaintDown, 3.0f);
Jankoekenpan 15:5d2bce2abd41 352 break;
Jankoekenpan 15:5d2bce2abd41 353 case FORWARD:
Jankoekenpan 20:66513b3c09b7 354 getXandY(x, y);
Jankoekenpan 27:91dc5174333a 355 robotController.moveTo(xmax, h + 0.5*d);
Jankoekenpan 15:5d2bce2abd41 356 break;
Jankoekenpan 15:5d2bce2abd41 357 case BACKWARD:
Jankoekenpan 20:66513b3c09b7 358 getXandY(x, y);
Jankoekenpan 27:91dc5174333a 359 robotController.moveTo(xmin, h + 0.5*d);
Jankoekenpan 15:5d2bce2abd41 360 break;
Jankoekenpan 15:5d2bce2abd41 361 case NOTHING:
Jankoekenpan 15:5d2bce2abd41 362
Jankoekenpan 15:5d2bce2abd41 363 break;
Jankoekenpan 15:5d2bce2abd41 364 }
Jankoekenpan 15:5d2bce2abd41 365 }
Jankoekenpan 15:5d2bce2abd41 366
Jankoekenpan 15:5d2bce2abd41 367 //some little utils used by the function below
Jankoekenpan 15:5d2bce2abd41 368 Timeout switchBlocker;
Jankoekenpan 15:5d2bce2abd41 369 volatile bool justSwitched;
Jankoekenpan 15:5d2bce2abd41 370 void unblockSwitch() {
Jankoekenpan 15:5d2bce2abd41 371 justSwitched = false;
Jankoekenpan 15:5d2bce2abd41 372 }
Jankoekenpan 15:5d2bce2abd41 373
Jankoekenpan 15:5d2bce2abd41 374 //tries to switch the state.
Jankoekenpan 15:5d2bce2abd41 375 //returns true if it was successfull
Jankoekenpan 15:5d2bce2abd41 376 //or false if we couldn't switch.
Jankoekenpan 15:5d2bce2abd41 377 bool switchState() {
Jankoekenpan 15:5d2bce2abd41 378 if (justSwitched) return false;
Jankoekenpan 15:5d2bce2abd41 379 justSwitched = true;
Jankoekenpan 15:5d2bce2abd41 380 switch(progState) {
Jankoekenpan 15:5d2bce2abd41 381 case UPDOWN:
Jankoekenpan 15:5d2bce2abd41 382 progState = FORBACK;
Jankoekenpan 15:5d2bce2abd41 383 break;
Jankoekenpan 15:5d2bce2abd41 384 case FORBACK:
Jankoekenpan 15:5d2bce2abd41 385 progState = UPDOWN;
Jankoekenpan 27:91dc5174333a 386 break;
Jankoekenpan 15:5d2bce2abd41 387 }
Jankoekenpan 27:91dc5174333a 388 pc.printf("\r\n\n\n1 and 1, switch state to %s.\r\n\n\n", progState == UPDOWN ? "UPDOWN" : "FORBACK");
Jankoekenpan 15:5d2bce2abd41 389 //we can only switch once per 2 seconds
Jankoekenpan 15:5d2bce2abd41 390 switchBlocker.attach(&unblockSwitch, 2.0f);
Jankoekenpan 15:5d2bce2abd41 391 return true;
Jankoekenpan 15:5d2bce2abd41 392 }
Jankoekenpan 15:5d2bce2abd41 393
Jankoekenpan 15:5d2bce2abd41 394 /* Translates our two digital signals to robot commands */
Jankoekenpan 15:5d2bce2abd41 395 void onSignal(bool emg1, bool emg2) {
Jankoekenpan 15:5d2bce2abd41 396 RobotCommand command = NOTHING;
Jankoekenpan 15:5d2bce2abd41 397 if (emg1 && emg2) {
Jankoekenpan 15:5d2bce2abd41 398 switchState();
Jankoekenpan 15:5d2bce2abd41 399 processCommand(command);
Jankoekenpan 15:5d2bce2abd41 400 return;
Jankoekenpan 15:5d2bce2abd41 401 }
Jankoekenpan 15:5d2bce2abd41 402 switch(progState) {
Jankoekenpan 15:5d2bce2abd41 403 case UPDOWN:
Jankoekenpan 15:5d2bce2abd41 404 if (emg1) {
Jankoekenpan 15:5d2bce2abd41 405 command = UP;
Jankoekenpan 27:91dc5174333a 406 pc.printf("1 and 0, command = UP\r\n");
Jankoekenpan 15:5d2bce2abd41 407 } else if (emg2) {
Jankoekenpan 15:5d2bce2abd41 408 command = DOWN;
Jankoekenpan 27:91dc5174333a 409 pc.printf("0 and 1, command = DOWN\r\n");
Jankoekenpan 15:5d2bce2abd41 410 }
Jankoekenpan 15:5d2bce2abd41 411 break;
Jankoekenpan 15:5d2bce2abd41 412 case FORBACK:
Jankoekenpan 15:5d2bce2abd41 413 if (emg1) {
Jankoekenpan 15:5d2bce2abd41 414 command = FORWARD;
Jankoekenpan 27:91dc5174333a 415 pc.printf("1 and 0, command = FORWARD\r\n");
Jankoekenpan 15:5d2bce2abd41 416 } else if (emg2) {
Jankoekenpan 15:5d2bce2abd41 417 command = BACKWARD;
Jankoekenpan 27:91dc5174333a 418 pc.printf("0 and 1, command = BACKWARD\r\n");
Jankoekenpan 15:5d2bce2abd41 419 }
Jankoekenpan 15:5d2bce2abd41 420 break;
Jankoekenpan 15:5d2bce2abd41 421 }
Jankoekenpan 15:5d2bce2abd41 422
Jankoekenpan 27:91dc5174333a 423 if (!emg1 && !emg2) {
Jankoekenpan 27:91dc5174333a 424 pc.printf("0 and 0\r\n");
Jankoekenpan 27:91dc5174333a 425 }
Jankoekenpan 27:91dc5174333a 426
Jankoekenpan 15:5d2bce2abd41 427 //execute the command
Jankoekenpan 15:5d2bce2abd41 428 processCommand(command);
Jankoekenpan 15:5d2bce2abd41 429 }
Jankoekenpan 15:5d2bce2abd41 430
Jankoekenpan 15:5d2bce2abd41 431 void consumeBools(bool x, bool y) {
Jankoekenpan 15:5d2bce2abd41 432 onSignal(x, y);
Jankoekenpan 15:5d2bce2abd41 433 }
Jankoekenpan 15:5d2bce2abd41 434
Jankoekenpan 15:5d2bce2abd41 435
Jankoekenpan 15:5d2bce2abd41 436 // ====== The entry point of our programme ======
Jankoekenpan 15:5d2bce2abd41 437
Jankoekenpan 22:cda3e5ad89c0 438
Jankoekenpan 21:2aed81380bc3 439 int main() //TODO this will become the actual main!
Jankoekenpan 15:5d2bce2abd41 440 {
Jankoekenpan 23:dba0233303b6 441 pc.baud(115200);
Jankoekenpan 22:cda3e5ad89c0 442 killButton.fall(robotController.getRobot(), &Robot::kill);
Jankoekenpan 15:5d2bce2abd41 443
Jankoekenpan 15:5d2bce2abd41 444 // initial state
Jankoekenpan 15:5d2bce2abd41 445 resetLeds();
Jankoekenpan 15:5d2bce2abd41 446 progState = CALIBRATING;
Jankoekenpan 15:5d2bce2abd41 447 robotCommand = NOTHING;
Jankoekenpan 15:5d2bce2abd41 448
Jankoekenpan 15:5d2bce2abd41 449 // initialize notch filters
Jankoekenpan 15:5d2bce2abd41 450 bqc1.add( &bq1 );
Jankoekenpan 15:5d2bce2abd41 451 bqc2.add( &bq2 );
Jankoekenpan 15:5d2bce2abd41 452
Jankoekenpan 15:5d2bce2abd41 453 // Attach cablitrate function to the button to be able to calibrate again
Jankoekenpan 15:5d2bce2abd41 454 // If the user desires so
Jankoekenpan 15:5d2bce2abd41 455 calibrateButton.fall(&calibrate);
Jankoekenpan 15:5d2bce2abd41 456
Jankoekenpan 15:5d2bce2abd41 457 // The function that takes our ditised signals and controls the robot
Jankoekenpan 15:5d2bce2abd41 458 motorFunc = &consumeBools;
Jankoekenpan 15:5d2bce2abd41 459
Jankoekenpan 15:5d2bce2abd41 460
Jankoekenpan 15:5d2bce2abd41 461 // call the calibrating function once at the start
Jankoekenpan 15:5d2bce2abd41 462 // this function blocks until the calibration phase is over
Jankoekenpan 15:5d2bce2abd41 463 calibrate();
Jankoekenpan 15:5d2bce2abd41 464
Jankoekenpan 15:5d2bce2abd41 465 // After calibration the program state is UPDOWN
Jankoekenpan 15:5d2bce2abd41 466 progState = UPDOWN;
Jankoekenpan 15:5d2bce2abd41 467
Jankoekenpan 15:5d2bce2abd41 468
Jankoekenpan 15:5d2bce2abd41 469 // 500 HZ Ticker
Jankoekenpan 15:5d2bce2abd41 470 ticker.attach(&processEMG, Ts);
Jankoekenpan 15:5d2bce2abd41 471
Jankoekenpan 15:5d2bce2abd41 472 while (true);
Jankoekenpan 21:2aed81380bc3 473 }