![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
EMG to motor
Dependencies: biquadFilter FastPWM MODSERIAL QEI mbed
main.cpp@0:aa126aa2ff8b, 2018-11-02 (annotated)
- Committer:
- EvaKrolis
- Date:
- Fri Nov 02 08:53:55 2018 +0000
- Revision:
- 0:aa126aa2ff8b
First try controlling the motors from the EMG without kinematics
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
EvaKrolis | 0:aa126aa2ff8b | 1 | // ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ PREPARATION ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ |
EvaKrolis | 0:aa126aa2ff8b | 2 | // Libraries |
EvaKrolis | 0:aa126aa2ff8b | 3 | #include "mbed.h" |
EvaKrolis | 0:aa126aa2ff8b | 4 | #include "BiQuad.h" |
EvaKrolis | 0:aa126aa2ff8b | 5 | #include "FastPWM.h" |
EvaKrolis | 0:aa126aa2ff8b | 6 | #include "MODSERIAL.h" |
EvaKrolis | 0:aa126aa2ff8b | 7 | #include "QEI.h" |
EvaKrolis | 0:aa126aa2ff8b | 8 | #include <algorithm> |
EvaKrolis | 0:aa126aa2ff8b | 9 | #include <math.h> |
EvaKrolis | 0:aa126aa2ff8b | 10 | #include <cmath> |
EvaKrolis | 0:aa126aa2ff8b | 11 | #define PI 3.14159265 |
EvaKrolis | 0:aa126aa2ff8b | 12 | |
EvaKrolis | 0:aa126aa2ff8b | 13 | // LEDs |
EvaKrolis | 0:aa126aa2ff8b | 14 | DigitalOut ledRed(LED_RED,1); // red LED K64F |
EvaKrolis | 0:aa126aa2ff8b | 15 | DigitalOut ledGreen(LED_GREEN,1); // green LED K64F |
EvaKrolis | 0:aa126aa2ff8b | 16 | DigitalOut ledBlue(LED_BLUE,1); // blue LED K64F |
EvaKrolis | 0:aa126aa2ff8b | 17 | |
EvaKrolis | 0:aa126aa2ff8b | 18 | Ticker blinkTimer; // LED ticker |
EvaKrolis | 0:aa126aa2ff8b | 19 | Timer EMGtransition_timer; // Timer for the transition from EMG calibration to homing |
EvaKrolis | 0:aa126aa2ff8b | 20 | |
EvaKrolis | 0:aa126aa2ff8b | 21 | // Buttons/inputs |
EvaKrolis | 0:aa126aa2ff8b | 22 | InterruptIn buttonBio1(D0); // button 1 BioRobotics shield |
EvaKrolis | 0:aa126aa2ff8b | 23 | InterruptIn buttonBio2(D1); // button 2 BioRobotics shield |
EvaKrolis | 0:aa126aa2ff8b | 24 | InterruptIn buttonEmergency(SW2); // emergency button on K64F |
EvaKrolis | 0:aa126aa2ff8b | 25 | InterruptIn buttonHome(SW3); // button on K64F |
EvaKrolis | 0:aa126aa2ff8b | 26 | |
EvaKrolis | 0:aa126aa2ff8b | 27 | // Potmeters |
EvaKrolis | 0:aa126aa2ff8b | 28 | AnalogIn pot2(A2); |
EvaKrolis | 0:aa126aa2ff8b | 29 | |
EvaKrolis | 0:aa126aa2ff8b | 30 | // Motor pins input |
EvaKrolis | 0:aa126aa2ff8b | 31 | DigitalIn pin8(D8); // Encoder L B |
EvaKrolis | 0:aa126aa2ff8b | 32 | DigitalIn pin9(D9); // Encoder L A |
EvaKrolis | 0:aa126aa2ff8b | 33 | DigitalIn pin10(D10); // Encoder R B |
EvaKrolis | 0:aa126aa2ff8b | 34 | DigitalIn pin11(D11); // Encoder R A |
EvaKrolis | 0:aa126aa2ff8b | 35 | DigitalIn pin12(D12); // Encoder F B |
EvaKrolis | 0:aa126aa2ff8b | 36 | DigitalIn pin13(D13); // Encoder F A |
EvaKrolis | 0:aa126aa2ff8b | 37 | |
EvaKrolis | 0:aa126aa2ff8b | 38 | // Motor pins output |
EvaKrolis | 0:aa126aa2ff8b | 39 | DigitalOut pin2(D2); // Motor F direction = motor flip |
EvaKrolis | 0:aa126aa2ff8b | 40 | FastPWM pin3(A5); // Motor F pwm = motor flip |
EvaKrolis | 0:aa126aa2ff8b | 41 | DigitalOut pin4(D4); // Motor R direction = motor right |
EvaKrolis | 0:aa126aa2ff8b | 42 | FastPWM pin5(D5); // Motor R pwm = motor right |
EvaKrolis | 0:aa126aa2ff8b | 43 | FastPWM pin6(D6); // Motor L pwm = motor left |
EvaKrolis | 0:aa126aa2ff8b | 44 | DigitalOut pin7(D7); // Motor L direction = motor left |
EvaKrolis | 0:aa126aa2ff8b | 45 | |
EvaKrolis | 0:aa126aa2ff8b | 46 | // Utilisation of libraries |
EvaKrolis | 0:aa126aa2ff8b | 47 | MODSERIAL pc(USBTX, USBRX); // communication with pc |
EvaKrolis | 0:aa126aa2ff8b | 48 | QEI encoderL(D9,D8,NC,4200); // Encoder input of motor L |
EvaKrolis | 0:aa126aa2ff8b | 49 | QEI encoderR(D10,D11,NC,4200); // Encoder input of motor R |
EvaKrolis | 0:aa126aa2ff8b | 50 | QEI encoderF(D12,D13,NC,4200); // Encoder input of motor F |
EvaKrolis | 0:aa126aa2ff8b | 51 | Ticker motorL; |
EvaKrolis | 0:aa126aa2ff8b | 52 | Ticker motorR; |
EvaKrolis | 0:aa126aa2ff8b | 53 | Ticker motorF; |
EvaKrolis | 0:aa126aa2ff8b | 54 | |
EvaKrolis | 0:aa126aa2ff8b | 55 | // Define & initialise state machine |
EvaKrolis | 0:aa126aa2ff8b | 56 | const float dt = 0.002f; |
EvaKrolis | 0:aa126aa2ff8b | 57 | enum states { calibratingMotorL, calibratingMotorR, calibratingMotorF, |
EvaKrolis | 0:aa126aa2ff8b | 58 | calibratingEMG, homing, reading, operating, failing, demoing |
EvaKrolis | 0:aa126aa2ff8b | 59 | }; |
EvaKrolis | 0:aa126aa2ff8b | 60 | |
EvaKrolis | 0:aa126aa2ff8b | 61 | states currentState = calibratingMotorL; // start in motor L mode |
EvaKrolis | 0:aa126aa2ff8b | 62 | bool changeState = true; // initialise the first state |
EvaKrolis | 0:aa126aa2ff8b | 63 | |
EvaKrolis | 0:aa126aa2ff8b | 64 | Ticker stateTimer; // state machine ticker |
EvaKrolis | 0:aa126aa2ff8b | 65 | |
EvaKrolis | 0:aa126aa2ff8b | 66 | //------------------------ Parameters for the EMG ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 67 | |
EvaKrolis | 0:aa126aa2ff8b | 68 | // EMG inputs |
EvaKrolis | 0:aa126aa2ff8b | 69 | AnalogIn EMG0In(A0); // EMG input 0 |
EvaKrolis | 0:aa126aa2ff8b | 70 | AnalogIn EMG1In(A1); // EMG input 1 |
EvaKrolis | 0:aa126aa2ff8b | 71 | |
EvaKrolis | 0:aa126aa2ff8b | 72 | // Timers |
EvaKrolis | 0:aa126aa2ff8b | 73 | Ticker FindMax0_timer; // Timer for finding the max muscle |
EvaKrolis | 0:aa126aa2ff8b | 74 | Ticker FindMax1_timer; // Timer for finding the max muscle |
EvaKrolis | 0:aa126aa2ff8b | 75 | |
EvaKrolis | 0:aa126aa2ff8b | 76 | // Constants |
EvaKrolis | 0:aa126aa2ff8b | 77 | const int Length = 10000; // Length of the array for the calibration |
EvaKrolis | 0:aa126aa2ff8b | 78 | const int Parts = 50; // Mean average filter over 50 values |
EvaKrolis | 0:aa126aa2ff8b | 79 | |
EvaKrolis | 0:aa126aa2ff8b | 80 | // Parameters for the first EMG signal |
EvaKrolis | 0:aa126aa2ff8b | 81 | float EMG0; // float for EMG input |
EvaKrolis | 0:aa126aa2ff8b | 82 | float EMG0filt; // float for filtered EMG |
EvaKrolis | 0:aa126aa2ff8b | 83 | float EMG0filtArray[Parts]; // Array for the filtered array |
EvaKrolis | 0:aa126aa2ff8b | 84 | float EMG0Average; // float for the value after Moving Average Filter |
EvaKrolis | 0:aa126aa2ff8b | 85 | float Sum0 = 0; // Sum0 for the moving average filter |
EvaKrolis | 0:aa126aa2ff8b | 86 | float EMG0Calibrate[Length]; // Array for the calibration |
EvaKrolis | 0:aa126aa2ff8b | 87 | int ReadCal0 = 0; // Integer to read over the calibration array |
EvaKrolis | 0:aa126aa2ff8b | 88 | float MaxValue0 = 0; // float to save the max muscle |
EvaKrolis | 0:aa126aa2ff8b | 89 | float Threshold0 = 0; // Threshold for the first EMG signal |
EvaKrolis | 0:aa126aa2ff8b | 90 | |
EvaKrolis | 0:aa126aa2ff8b | 91 | // Parameters for the second EMG signal |
EvaKrolis | 0:aa126aa2ff8b | 92 | float EMG1; // float for EMG input |
EvaKrolis | 0:aa126aa2ff8b | 93 | float EMG1filt; // float for filtered EMG |
EvaKrolis | 0:aa126aa2ff8b | 94 | float EMG1filtArray[Parts]; // Array for the filtered array |
EvaKrolis | 0:aa126aa2ff8b | 95 | float EMG1Average; // float for the value after Moving Average Filter |
EvaKrolis | 0:aa126aa2ff8b | 96 | float Sum1 = 0; // Sum0 for the moving average filter |
EvaKrolis | 0:aa126aa2ff8b | 97 | float EMG1Calibrate[Length]; // Array for the calibration |
EvaKrolis | 0:aa126aa2ff8b | 98 | int ReadCal1 = 0; // Integer to read over the calibration array |
EvaKrolis | 0:aa126aa2ff8b | 99 | float MaxValue1 = 0; // float to save the max muscle |
EvaKrolis | 0:aa126aa2ff8b | 100 | float Threshold1 = 0; // Threshold for the second EMG signal |
EvaKrolis | 0:aa126aa2ff8b | 101 | |
EvaKrolis | 0:aa126aa2ff8b | 102 | //Filter variables |
EvaKrolis | 0:aa126aa2ff8b | 103 | BiQuad Notch50_0(0.9049,-1.4641,0.9049,-1.4641,0.8098); //Make Notch filter around 50 Hz |
EvaKrolis | 0:aa126aa2ff8b | 104 | BiQuad Notch50_1(0.9049,-1.4641,0.9049,-1.4641,0.8098); //Make Notch filter around 50 Hz |
EvaKrolis | 0:aa126aa2ff8b | 105 | BiQuad Notch100_0(0.8427,-0.5097,0.8247,-0.5097,0.6494); //Make Notch filter around 100 Hz |
EvaKrolis | 0:aa126aa2ff8b | 106 | BiQuad Notch100_1(0.8427,-0.5097,0.8247,-0.5097,0.6494); //Make Notch filter around 100 Hz |
EvaKrolis | 0:aa126aa2ff8b | 107 | BiQuad Notch150_0(0.7548,0.4665,0.7544,0.4665,0.5095); //Make Notch filter around 150 Hz |
EvaKrolis | 0:aa126aa2ff8b | 108 | BiQuad Notch150_1(0.7548,0.4665,0.7544,0.4665,0.5095); //Make Notch filter around 150 Hz |
EvaKrolis | 0:aa126aa2ff8b | 109 | BiQuad Notch200_0(0.6919,1.1196,0.6919,1.1196,0.3839); //Make Notch filter around 200 Hz |
EvaKrolis | 0:aa126aa2ff8b | 110 | BiQuad Notch200_1(0.6919,1.1196,0.6919,1.1196,0.3839); //Make Notch filter around 200 Hz |
EvaKrolis | 0:aa126aa2ff8b | 111 | BiQuad High_0(0.9150,-1.8299,0.9150,-1.8227,0.8372); //Make high-pass filter |
EvaKrolis | 0:aa126aa2ff8b | 112 | BiQuad High_1(0.9150,-1.8299,0.9150,-1.8227,0.8372); //Make high-pass filter |
EvaKrolis | 0:aa126aa2ff8b | 113 | BiQuad Low_0(0.6389,1.2779,0.6389,1.143,0.4128); //Make low-pass filter |
EvaKrolis | 0:aa126aa2ff8b | 114 | BiQuad Low_1(0.6389,1.2779,0.6389,1.143,0.4128); //Make low-pass filter |
EvaKrolis | 0:aa126aa2ff8b | 115 | BiQuadChain filter0; //Make chain of filters for the first EMG signal |
EvaKrolis | 0:aa126aa2ff8b | 116 | BiQuadChain filter1; //Make chain of filters for the second EMG signal |
EvaKrolis | 0:aa126aa2ff8b | 117 | |
EvaKrolis | 0:aa126aa2ff8b | 118 | //Bool for movement |
EvaKrolis | 0:aa126aa2ff8b | 119 | bool xMove = false; //Bool for the x-movement |
EvaKrolis | 0:aa126aa2ff8b | 120 | bool yMove = false; //Bool for the y-movement |
EvaKrolis | 0:aa126aa2ff8b | 121 | |
EvaKrolis | 0:aa126aa2ff8b | 122 | // -------------------- Parameters for the kinematics ------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 123 | double theta1 = PI*0.40; //Angle of the left motor |
EvaKrolis | 0:aa126aa2ff8b | 124 | double theta4 = PI*0.40; //Angle of the right motor |
EvaKrolis | 0:aa126aa2ff8b | 125 | // ---------------------- Parameters for the motors --------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 126 | const float countsRad = 4200.0f; |
EvaKrolis | 0:aa126aa2ff8b | 127 | int countsL; |
EvaKrolis | 0:aa126aa2ff8b | 128 | int countsR; |
EvaKrolis | 0:aa126aa2ff8b | 129 | int countsF; |
EvaKrolis | 0:aa126aa2ff8b | 130 | int countsCalibratedL; |
EvaKrolis | 0:aa126aa2ff8b | 131 | int countsCalibratedR; |
EvaKrolis | 0:aa126aa2ff8b | 132 | int countsCalibratedF; |
EvaKrolis | 0:aa126aa2ff8b | 133 | int countsOffsetL; |
EvaKrolis | 0:aa126aa2ff8b | 134 | int countsOffsetR; |
EvaKrolis | 0:aa126aa2ff8b | 135 | int countsOffsetF; |
EvaKrolis | 0:aa126aa2ff8b | 136 | float angleCurrentL; |
EvaKrolis | 0:aa126aa2ff8b | 137 | float angleCurrentR; |
EvaKrolis | 0:aa126aa2ff8b | 138 | float angleCurrentF; |
EvaKrolis | 0:aa126aa2ff8b | 139 | float errorL; |
EvaKrolis | 0:aa126aa2ff8b | 140 | float errorR; |
EvaKrolis | 0:aa126aa2ff8b | 141 | float errorF; |
EvaKrolis | 0:aa126aa2ff8b | 142 | float errorCalibratedL; |
EvaKrolis | 0:aa126aa2ff8b | 143 | float errorCalibratedR; |
EvaKrolis | 0:aa126aa2ff8b | 144 | float errorCalibratedF; |
EvaKrolis | 0:aa126aa2ff8b | 145 | |
EvaKrolis | 0:aa126aa2ff8b | 146 | int countsCalibration = 4200/4; |
EvaKrolis | 0:aa126aa2ff8b | 147 | |
EvaKrolis | 0:aa126aa2ff8b | 148 | // ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ FUNCTIONS ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ |
EvaKrolis | 0:aa126aa2ff8b | 149 | // ============================ GENERAL FUNCTIONS ============================= |
EvaKrolis | 0:aa126aa2ff8b | 150 | void stopProgram(void) |
EvaKrolis | 0:aa126aa2ff8b | 151 | { |
EvaKrolis | 0:aa126aa2ff8b | 152 | // Error message |
EvaKrolis | 0:aa126aa2ff8b | 153 | pc.printf("[ERROR] emergency button pressed\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 154 | currentState = failing; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 155 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 156 | } |
EvaKrolis | 0:aa126aa2ff8b | 157 | |
EvaKrolis | 0:aa126aa2ff8b | 158 | void blinkLedRed(void) |
EvaKrolis | 0:aa126aa2ff8b | 159 | { |
EvaKrolis | 0:aa126aa2ff8b | 160 | ledRed =! ledRed; // toggle LED |
EvaKrolis | 0:aa126aa2ff8b | 161 | } |
EvaKrolis | 0:aa126aa2ff8b | 162 | void blinkLedGreen(void) |
EvaKrolis | 0:aa126aa2ff8b | 163 | { |
EvaKrolis | 0:aa126aa2ff8b | 164 | ledGreen =! ledGreen; // toggle LED |
EvaKrolis | 0:aa126aa2ff8b | 165 | } |
EvaKrolis | 0:aa126aa2ff8b | 166 | void blinkLedBlue(void) |
EvaKrolis | 0:aa126aa2ff8b | 167 | { |
EvaKrolis | 0:aa126aa2ff8b | 168 | ledBlue =! ledBlue; // toggle LED |
EvaKrolis | 0:aa126aa2ff8b | 169 | } |
EvaKrolis | 0:aa126aa2ff8b | 170 | |
EvaKrolis | 0:aa126aa2ff8b | 171 | float angleCurrent(float counts) // Calculates the current angle of the motor (between -2*PI to 2*PI) based on the counts from the encoder |
EvaKrolis | 0:aa126aa2ff8b | 172 | { |
EvaKrolis | 0:aa126aa2ff8b | 173 | float angle = ((float)counts*2.0f*PI)/countsRad; |
EvaKrolis | 0:aa126aa2ff8b | 174 | while (angle > 2.0f*PI) { |
EvaKrolis | 0:aa126aa2ff8b | 175 | angle = angle-2.0f*PI; |
EvaKrolis | 0:aa126aa2ff8b | 176 | } |
EvaKrolis | 0:aa126aa2ff8b | 177 | while (angle < -2.0f*PI) { |
EvaKrolis | 0:aa126aa2ff8b | 178 | angle = angle+2.0f*PI; |
EvaKrolis | 0:aa126aa2ff8b | 179 | } |
EvaKrolis | 0:aa126aa2ff8b | 180 | return angle; |
EvaKrolis | 0:aa126aa2ff8b | 181 | } |
EvaKrolis | 0:aa126aa2ff8b | 182 | |
EvaKrolis | 0:aa126aa2ff8b | 183 | // ============================= EMG FUNCTIONS =============================== |
EvaKrolis | 0:aa126aa2ff8b | 184 | |
EvaKrolis | 0:aa126aa2ff8b | 185 | //Function to read and filter the EMG |
EvaKrolis | 0:aa126aa2ff8b | 186 | void ReadUseEMG0() |
EvaKrolis | 0:aa126aa2ff8b | 187 | { |
EvaKrolis | 0:aa126aa2ff8b | 188 | for(int i = Parts ; i > 0 ; i--) { //Make a first in, first out array |
EvaKrolis | 0:aa126aa2ff8b | 189 | EMG0filtArray[i] = EMG0filtArray[i-1]; //Every value moves one up |
EvaKrolis | 0:aa126aa2ff8b | 190 | } |
EvaKrolis | 0:aa126aa2ff8b | 191 | |
EvaKrolis | 0:aa126aa2ff8b | 192 | Sum0 = 0; |
EvaKrolis | 0:aa126aa2ff8b | 193 | EMG0 = EMG0In; //Save EMG input in float |
EvaKrolis | 0:aa126aa2ff8b | 194 | EMG0filt = filter0.step(EMG0); //Filter the signal |
EvaKrolis | 0:aa126aa2ff8b | 195 | EMG0filt = abs(EMG0filt); //Take the absolute value |
EvaKrolis | 0:aa126aa2ff8b | 196 | EMG0filtArray[0] = EMG0filt; //Save the filtered signal on the first place in the array |
EvaKrolis | 0:aa126aa2ff8b | 197 | |
EvaKrolis | 0:aa126aa2ff8b | 198 | for(int i = 0 ; i < Parts ; i++) { //Moving Average filter |
EvaKrolis | 0:aa126aa2ff8b | 199 | Sum0 += EMG0filtArray[i]; //Sum the new value and the previous 49 |
EvaKrolis | 0:aa126aa2ff8b | 200 | } |
EvaKrolis | 0:aa126aa2ff8b | 201 | EMG0Average = (float)Sum0/Parts; //Divide the sum by 50 |
EvaKrolis | 0:aa126aa2ff8b | 202 | |
EvaKrolis | 0:aa126aa2ff8b | 203 | if (EMG0Average > Threshold0) { //If the value is higher than the threshold value |
EvaKrolis | 0:aa126aa2ff8b | 204 | xMove = true; //Set movement to true |
EvaKrolis | 0:aa126aa2ff8b | 205 | } else { |
EvaKrolis | 0:aa126aa2ff8b | 206 | xMove = false; //Otherwise set movement to false |
EvaKrolis | 0:aa126aa2ff8b | 207 | } |
EvaKrolis | 0:aa126aa2ff8b | 208 | } |
EvaKrolis | 0:aa126aa2ff8b | 209 | |
EvaKrolis | 0:aa126aa2ff8b | 210 | //Function to read and filter the EMG |
EvaKrolis | 0:aa126aa2ff8b | 211 | void ReadUseEMG1() |
EvaKrolis | 0:aa126aa2ff8b | 212 | { |
EvaKrolis | 0:aa126aa2ff8b | 213 | for(int i = Parts ; i > 0 ; i--) { //Make a first in, first out array |
EvaKrolis | 0:aa126aa2ff8b | 214 | EMG1filtArray[i] = EMG1filtArray[i-1]; //Every value moves one up |
EvaKrolis | 0:aa126aa2ff8b | 215 | } |
EvaKrolis | 0:aa126aa2ff8b | 216 | |
EvaKrolis | 0:aa126aa2ff8b | 217 | Sum1 = 0; |
EvaKrolis | 0:aa126aa2ff8b | 218 | EMG1 = EMG1In; //Save EMG input in float |
EvaKrolis | 0:aa126aa2ff8b | 219 | EMG1filt = filter1.step(EMG1); //Filter the signal |
EvaKrolis | 0:aa126aa2ff8b | 220 | EMG1filt = abs(EMG1filt); //Take the absolute value |
EvaKrolis | 0:aa126aa2ff8b | 221 | EMG1filtArray[0] = EMG1filt; //Save the filtered signal on the first place in the array |
EvaKrolis | 0:aa126aa2ff8b | 222 | |
EvaKrolis | 0:aa126aa2ff8b | 223 | for(int i = 0 ; i < Parts ; i++) { //Moving Average filter |
EvaKrolis | 0:aa126aa2ff8b | 224 | Sum1 += EMG1filtArray[i]; //Sum the new value and the previous 49 |
EvaKrolis | 0:aa126aa2ff8b | 225 | } |
EvaKrolis | 0:aa126aa2ff8b | 226 | EMG1Average = (float)Sum1/Parts; //Divide the sum by 50 |
EvaKrolis | 0:aa126aa2ff8b | 227 | |
EvaKrolis | 0:aa126aa2ff8b | 228 | if (EMG1Average > Threshold1) { //If the value is higher than the threshold value |
EvaKrolis | 0:aa126aa2ff8b | 229 | yMove = true; //Set y movement to true |
EvaKrolis | 0:aa126aa2ff8b | 230 | } else { |
EvaKrolis | 0:aa126aa2ff8b | 231 | yMove = false; //Otherwise set y movement to false |
EvaKrolis | 0:aa126aa2ff8b | 232 | } |
EvaKrolis | 0:aa126aa2ff8b | 233 | } |
EvaKrolis | 0:aa126aa2ff8b | 234 | |
EvaKrolis | 0:aa126aa2ff8b | 235 | //Function to make an array during the calibration |
EvaKrolis | 0:aa126aa2ff8b | 236 | void CalibrateEMG0() |
EvaKrolis | 0:aa126aa2ff8b | 237 | { |
EvaKrolis | 0:aa126aa2ff8b | 238 | for(int i = Parts ; i > 0 ; i--) { //Make a first in, first out array |
EvaKrolis | 0:aa126aa2ff8b | 239 | EMG0filtArray[i] = EMG0filtArray[i-1]; //Every value moves one up |
EvaKrolis | 0:aa126aa2ff8b | 240 | } |
EvaKrolis | 0:aa126aa2ff8b | 241 | |
EvaKrolis | 0:aa126aa2ff8b | 242 | Sum0 = 0; |
EvaKrolis | 0:aa126aa2ff8b | 243 | EMG0 = EMG0In; //Save EMG input in float |
EvaKrolis | 0:aa126aa2ff8b | 244 | EMG0filt = filter0.step(EMG0); //Filter the signal |
EvaKrolis | 0:aa126aa2ff8b | 245 | EMG0filt = abs(EMG0filt); //Take the absolute value |
EvaKrolis | 0:aa126aa2ff8b | 246 | EMG0filtArray[0] = EMG0filt; //Save the filtered signal on the first place in the array |
EvaKrolis | 0:aa126aa2ff8b | 247 | |
EvaKrolis | 0:aa126aa2ff8b | 248 | for(int i = 0 ; i < Parts ; i++) { //Moving Average filter |
EvaKrolis | 0:aa126aa2ff8b | 249 | Sum0 += EMG0filtArray[i]; //Sum the new value and the previous 49 |
EvaKrolis | 0:aa126aa2ff8b | 250 | } |
EvaKrolis | 0:aa126aa2ff8b | 251 | EMG0Calibrate[ReadCal0] = (float)Sum0/Parts; //Divide the sum by 50 |
EvaKrolis | 0:aa126aa2ff8b | 252 | |
EvaKrolis | 0:aa126aa2ff8b | 253 | ReadCal0++; |
EvaKrolis | 0:aa126aa2ff8b | 254 | } |
EvaKrolis | 0:aa126aa2ff8b | 255 | |
EvaKrolis | 0:aa126aa2ff8b | 256 | //Function to make an array during the calibration |
EvaKrolis | 0:aa126aa2ff8b | 257 | void CalibrateEMG1() |
EvaKrolis | 0:aa126aa2ff8b | 258 | { |
EvaKrolis | 0:aa126aa2ff8b | 259 | for(int i = Parts ; i > 0 ; i--) { //Make a first in, first out array |
EvaKrolis | 0:aa126aa2ff8b | 260 | EMG1filtArray[i] = EMG1filtArray[i-1]; //Every value moves one up |
EvaKrolis | 0:aa126aa2ff8b | 261 | } |
EvaKrolis | 0:aa126aa2ff8b | 262 | |
EvaKrolis | 0:aa126aa2ff8b | 263 | Sum1 = 0; |
EvaKrolis | 0:aa126aa2ff8b | 264 | EMG1 = EMG1In; //Save EMG input in float |
EvaKrolis | 0:aa126aa2ff8b | 265 | EMG1filt = filter1.step(EMG1); //Filter the signal |
EvaKrolis | 0:aa126aa2ff8b | 266 | EMG1filt = abs(EMG1filt); //Take the absolute value |
EvaKrolis | 0:aa126aa2ff8b | 267 | EMG1filtArray[0] = EMG1filt; //Save the filtered signal on the first place in the array |
EvaKrolis | 0:aa126aa2ff8b | 268 | |
EvaKrolis | 0:aa126aa2ff8b | 269 | for(int i = 0 ; i < Parts ; i++) { //Moving Average filter |
EvaKrolis | 0:aa126aa2ff8b | 270 | Sum1 += EMG1filtArray[i]; //Sum the new value and the previous 49 |
EvaKrolis | 0:aa126aa2ff8b | 271 | } |
EvaKrolis | 0:aa126aa2ff8b | 272 | EMG1Calibrate[ReadCal1] = (float)Sum1/Parts; //Divide the sum by 50 |
EvaKrolis | 0:aa126aa2ff8b | 273 | |
EvaKrolis | 0:aa126aa2ff8b | 274 | ReadCal1++; |
EvaKrolis | 0:aa126aa2ff8b | 275 | } |
EvaKrolis | 0:aa126aa2ff8b | 276 | |
EvaKrolis | 0:aa126aa2ff8b | 277 | //Function to find the max value during the calibration |
EvaKrolis | 0:aa126aa2ff8b | 278 | void FindMax0() |
EvaKrolis | 0:aa126aa2ff8b | 279 | { |
EvaKrolis | 0:aa126aa2ff8b | 280 | MaxValue0 = *max_element(EMG0Calibrate+500,EMG0Calibrate+Length); //Find max value, but discard the first 100 values |
EvaKrolis | 0:aa126aa2ff8b | 281 | Threshold0 = 0.30f*MaxValue0; //The threshold is a percentage of the max value |
EvaKrolis | 0:aa126aa2ff8b | 282 | pc.printf("The calibration value of the first EMG is %f.\n\r The threshold is %f. \n\r",MaxValue0,Threshold0); //Print the max value and the threshold |
EvaKrolis | 0:aa126aa2ff8b | 283 | FindMax0_timer.detach(); //Detach the timer, so you only use this once |
EvaKrolis | 0:aa126aa2ff8b | 284 | } |
EvaKrolis | 0:aa126aa2ff8b | 285 | |
EvaKrolis | 0:aa126aa2ff8b | 286 | //Function to find the max value during the calibration |
EvaKrolis | 0:aa126aa2ff8b | 287 | void FindMax1() |
EvaKrolis | 0:aa126aa2ff8b | 288 | { |
EvaKrolis | 0:aa126aa2ff8b | 289 | MaxValue1 = *max_element(EMG1Calibrate+500,EMG1Calibrate+Length); //Find max value, but discard the first 100 values |
EvaKrolis | 0:aa126aa2ff8b | 290 | Threshold1 = 0.30f*MaxValue1; //The threshold is a percentage of the max value |
EvaKrolis | 0:aa126aa2ff8b | 291 | pc.printf("The calibration value of the second EMG is %f.\n\r The threshold is %f. \n\r",MaxValue1,Threshold1); //Print the Max value and the threshold |
EvaKrolis | 0:aa126aa2ff8b | 292 | FindMax1_timer.detach(); //Detach the timer, so you only use this once |
EvaKrolis | 0:aa126aa2ff8b | 293 | } |
EvaKrolis | 0:aa126aa2ff8b | 294 | |
EvaKrolis | 0:aa126aa2ff8b | 295 | // ================ FUNCTIONS TO LINK THE EMG TO THE MOTORS=================== |
EvaKrolis | 0:aa126aa2ff8b | 296 | void EMGMotorLink(){ |
EvaKrolis | 0:aa126aa2ff8b | 297 | if (xMove == true){ |
EvaKrolis | 0:aa126aa2ff8b | 298 | theta1 = theta1*0.0001; |
EvaKrolis | 0:aa126aa2ff8b | 299 | theta4 = -theta4*0.0001; |
EvaKrolis | 0:aa126aa2ff8b | 300 | } |
EvaKrolis | 0:aa126aa2ff8b | 301 | if(yMove == true){ |
EvaKrolis | 0:aa126aa2ff8b | 302 | theta1 = -theta1*0.0001; |
EvaKrolis | 0:aa126aa2ff8b | 303 | theta4 = theta4*0.0001; |
EvaKrolis | 0:aa126aa2ff8b | 304 | } |
EvaKrolis | 0:aa126aa2ff8b | 305 | } |
EvaKrolis | 0:aa126aa2ff8b | 306 | |
EvaKrolis | 0:aa126aa2ff8b | 307 | // ============================ MOTOR FUNCTIONS =============================== |
EvaKrolis | 0:aa126aa2ff8b | 308 | // angleDesired now defined as angle of potmeter and not the angle as output from the kinematics |
EvaKrolis | 0:aa126aa2ff8b | 309 | // So, the angleDesired needs to be defined again and the part in which the potmeter value is calculated needs to be commented |
EvaKrolis | 0:aa126aa2ff8b | 310 | |
EvaKrolis | 0:aa126aa2ff8b | 311 | // ------------------------ General motor functions ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 312 | int countsInputL() // Gets the counts from encoder 1 |
EvaKrolis | 0:aa126aa2ff8b | 313 | { |
EvaKrolis | 0:aa126aa2ff8b | 314 | countsL = encoderL.getPulses(); |
EvaKrolis | 0:aa126aa2ff8b | 315 | return countsL; |
EvaKrolis | 0:aa126aa2ff8b | 316 | } |
EvaKrolis | 0:aa126aa2ff8b | 317 | int countsInputR() // Gets the counts from encoder 2 |
EvaKrolis | 0:aa126aa2ff8b | 318 | { |
EvaKrolis | 0:aa126aa2ff8b | 319 | countsR = encoderR.getPulses(); |
EvaKrolis | 0:aa126aa2ff8b | 320 | return countsR; |
EvaKrolis | 0:aa126aa2ff8b | 321 | } |
EvaKrolis | 0:aa126aa2ff8b | 322 | int countsInputF() // Gets the counts from encoder 3 |
EvaKrolis | 0:aa126aa2ff8b | 323 | { |
EvaKrolis | 0:aa126aa2ff8b | 324 | countsF = encoderF.getPulses(); |
EvaKrolis | 0:aa126aa2ff8b | 325 | return countsF; |
EvaKrolis | 0:aa126aa2ff8b | 326 | } |
EvaKrolis | 0:aa126aa2ff8b | 327 | |
EvaKrolis | 0:aa126aa2ff8b | 328 | float errorCalc(float angleReference,float angleCurrent) // Calculates the error of the system, based on the current angle and the reference value |
EvaKrolis | 0:aa126aa2ff8b | 329 | { |
EvaKrolis | 0:aa126aa2ff8b | 330 | float error = angleReference - angleCurrent; |
EvaKrolis | 0:aa126aa2ff8b | 331 | return error; |
EvaKrolis | 0:aa126aa2ff8b | 332 | } |
EvaKrolis | 0:aa126aa2ff8b | 333 | |
EvaKrolis | 0:aa126aa2ff8b | 334 | float angleDesired() // Sets the desired angle for the controller dependent on the scaled angle of potmeter 1 |
EvaKrolis | 0:aa126aa2ff8b | 335 | { |
EvaKrolis | 0:aa126aa2ff8b | 336 | float angle = (pot2*2.0f*PI)-PI; |
EvaKrolis | 0:aa126aa2ff8b | 337 | return angle; |
EvaKrolis | 0:aa126aa2ff8b | 338 | } |
EvaKrolis | 0:aa126aa2ff8b | 339 | |
EvaKrolis | 0:aa126aa2ff8b | 340 | // ------------------------- MOTOR FUNCTIONS FOR MOTOR LEFT -------------------- |
EvaKrolis | 0:aa126aa2ff8b | 341 | float PIDControllerL(float angleReference,float angleCurrent) // PID controller for the motors, based on the reference value and the current angle of the motor |
EvaKrolis | 0:aa126aa2ff8b | 342 | { |
EvaKrolis | 0:aa126aa2ff8b | 343 | float Kp = 19.24f; |
EvaKrolis | 0:aa126aa2ff8b | 344 | float Ki = 1.02f; |
EvaKrolis | 0:aa126aa2ff8b | 345 | float Kd = 0.827f; |
EvaKrolis | 0:aa126aa2ff8b | 346 | float error = errorCalc(angleReference,angleCurrent); |
EvaKrolis | 0:aa126aa2ff8b | 347 | static float errorIntegralL = 0.0; |
EvaKrolis | 0:aa126aa2ff8b | 348 | static float errorPreviousL = error; // initialization with this value only done once! |
EvaKrolis | 0:aa126aa2ff8b | 349 | static BiQuad PIDFilterL(0.0640, 0.1279, 0.0640, -1.1683, 0.4241); |
EvaKrolis | 0:aa126aa2ff8b | 350 | // Proportional part: |
EvaKrolis | 0:aa126aa2ff8b | 351 | float u_k = Kp * error; |
EvaKrolis | 0:aa126aa2ff8b | 352 | // Integral part |
EvaKrolis | 0:aa126aa2ff8b | 353 | errorIntegralL = errorIntegralL + error * dt; |
EvaKrolis | 0:aa126aa2ff8b | 354 | float u_i = Ki * errorIntegralL; |
EvaKrolis | 0:aa126aa2ff8b | 355 | // Derivative part |
EvaKrolis | 0:aa126aa2ff8b | 356 | float errorDerivative = (error - errorPreviousL)/dt; |
EvaKrolis | 0:aa126aa2ff8b | 357 | float errorDerivativeFiltered = PIDFilterL.step(errorDerivative); |
EvaKrolis | 0:aa126aa2ff8b | 358 | float u_d = Kd * errorDerivativeFiltered; |
EvaKrolis | 0:aa126aa2ff8b | 359 | errorPreviousL = error; |
EvaKrolis | 0:aa126aa2ff8b | 360 | // Sum all parts and return it |
EvaKrolis | 0:aa126aa2ff8b | 361 | return u_k + u_i + u_d; |
EvaKrolis | 0:aa126aa2ff8b | 362 | } |
EvaKrolis | 0:aa126aa2ff8b | 363 | |
EvaKrolis | 0:aa126aa2ff8b | 364 | int countsInputCalibratedL() // Gets the counts from encoder 1 |
EvaKrolis | 0:aa126aa2ff8b | 365 | { |
EvaKrolis | 0:aa126aa2ff8b | 366 | countsL = encoderL.getPulses()- countsOffsetL + countsCalibration; |
EvaKrolis | 0:aa126aa2ff8b | 367 | return countsL; |
EvaKrolis | 0:aa126aa2ff8b | 368 | } |
EvaKrolis | 0:aa126aa2ff8b | 369 | |
EvaKrolis | 0:aa126aa2ff8b | 370 | void motorTurnL() // main function for movement of motor 1, all above functions with an extra tab are called |
EvaKrolis | 0:aa126aa2ff8b | 371 | { |
EvaKrolis | 0:aa126aa2ff8b | 372 | float angleReferenceL = theta1; // insert kinematics output here instead of angleDesired() |
EvaKrolis | 0:aa126aa2ff8b | 373 | angleReferenceL = -angleReferenceL; // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 374 | countsL = countsInputCalibratedL(); // different encoder pins per motor |
EvaKrolis | 0:aa126aa2ff8b | 375 | angleCurrentL = angleCurrent(countsL); // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 376 | errorL = errorCalc(angleReferenceL,angleCurrentL); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 377 | |
EvaKrolis | 0:aa126aa2ff8b | 378 | float PIDControlL = PIDControllerL(angleReferenceL,angleCurrentL); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 379 | pin6 = fabs(PIDControlL); // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 380 | pin7 = PIDControlL > 0.0f; // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 381 | } |
EvaKrolis | 0:aa126aa2ff8b | 382 | |
EvaKrolis | 0:aa126aa2ff8b | 383 | void calibrationL() // Partially the same as motorTurnL, only with potmeter input |
EvaKrolis | 0:aa126aa2ff8b | 384 | // How it works: manually turn motor using potmeters until the robot arm touches the bookholder. |
EvaKrolis | 0:aa126aa2ff8b | 385 | // This program sets the counts from the motor to the reference counts (an angle of PI/4.0) |
EvaKrolis | 0:aa126aa2ff8b | 386 | // Do this for every motor and after calibrated all motors, press a button |
EvaKrolis | 0:aa126aa2ff8b | 387 | { |
EvaKrolis | 0:aa126aa2ff8b | 388 | float angleReferenceL = angleDesired(); // insert kinematics output here instead of angleDesired() |
EvaKrolis | 0:aa126aa2ff8b | 389 | angleReferenceL = -angleReferenceL; // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 390 | countsL = countsInputL(); // different encoder pins per motor |
EvaKrolis | 0:aa126aa2ff8b | 391 | angleCurrentL = angleCurrent(countsL); // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 392 | errorL = errorCalc(angleReferenceL,angleCurrentL); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 393 | |
EvaKrolis | 0:aa126aa2ff8b | 394 | if (fabs(errorL) >= 0.01f) { |
EvaKrolis | 0:aa126aa2ff8b | 395 | float PIDControlL = PIDControllerL(angleReferenceL,angleCurrentL); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 396 | pin6 = fabs(PIDControlL); // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 397 | pin7 = PIDControlL > 0.0f; // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 398 | } else if (fabs(errorL) < 0.01f) { |
EvaKrolis | 0:aa126aa2ff8b | 399 | countsOffsetL = countsL; |
EvaKrolis | 0:aa126aa2ff8b | 400 | countsL = countsL - countsOffsetL + countsCalibration; |
EvaKrolis | 0:aa126aa2ff8b | 401 | //countsL = 0; |
EvaKrolis | 0:aa126aa2ff8b | 402 | pin6 = 0.0f; |
EvaKrolis | 0:aa126aa2ff8b | 403 | // BUTTON PRESS: TO NEXT STATE |
EvaKrolis | 0:aa126aa2ff8b | 404 | } |
EvaKrolis | 0:aa126aa2ff8b | 405 | } |
EvaKrolis | 0:aa126aa2ff8b | 406 | |
EvaKrolis | 0:aa126aa2ff8b | 407 | // ------------------------ MOTOR FUNCTIONS FOR MOTOR RIGHT -------------------- |
EvaKrolis | 0:aa126aa2ff8b | 408 | float PIDControllerR(float angleReference,float angleCurrent) // PID controller for the motors, based on the reference value and the current angle of the motor |
EvaKrolis | 0:aa126aa2ff8b | 409 | { |
EvaKrolis | 0:aa126aa2ff8b | 410 | float Kp = 19.24f; |
EvaKrolis | 0:aa126aa2ff8b | 411 | float Ki = 1.02f; |
EvaKrolis | 0:aa126aa2ff8b | 412 | float Kd = 0.827f; |
EvaKrolis | 0:aa126aa2ff8b | 413 | float error = errorCalc(angleReference,angleCurrent); |
EvaKrolis | 0:aa126aa2ff8b | 414 | static float errorIntegralR = 0.0; |
EvaKrolis | 0:aa126aa2ff8b | 415 | static float errorPreviousR = error; // initialization with this value only done once! |
EvaKrolis | 0:aa126aa2ff8b | 416 | static BiQuad PIDFilterR(0.0640, 0.1279, 0.0640, -1.1683, 0.4241); |
EvaKrolis | 0:aa126aa2ff8b | 417 | // Proportional part: |
EvaKrolis | 0:aa126aa2ff8b | 418 | float u_k = Kp * error; |
EvaKrolis | 0:aa126aa2ff8b | 419 | // Integral part |
EvaKrolis | 0:aa126aa2ff8b | 420 | errorIntegralR = errorIntegralR + error * dt; |
EvaKrolis | 0:aa126aa2ff8b | 421 | float u_i = Ki * errorIntegralR; |
EvaKrolis | 0:aa126aa2ff8b | 422 | // Derivative part |
EvaKrolis | 0:aa126aa2ff8b | 423 | float errorDerivative = (error - errorPreviousR)/dt; |
EvaKrolis | 0:aa126aa2ff8b | 424 | float errorDerivativeFiltered = PIDFilterR.step(errorDerivative); |
EvaKrolis | 0:aa126aa2ff8b | 425 | float u_d = Kd * errorDerivativeFiltered; |
EvaKrolis | 0:aa126aa2ff8b | 426 | errorPreviousR = error; |
EvaKrolis | 0:aa126aa2ff8b | 427 | // Sum all parts and return it |
EvaKrolis | 0:aa126aa2ff8b | 428 | return u_k + u_i + u_d; |
EvaKrolis | 0:aa126aa2ff8b | 429 | } |
EvaKrolis | 0:aa126aa2ff8b | 430 | |
EvaKrolis | 0:aa126aa2ff8b | 431 | int countsInputCalibratedR() // Gets the counts from encoder 1 |
EvaKrolis | 0:aa126aa2ff8b | 432 | { |
EvaKrolis | 0:aa126aa2ff8b | 433 | countsR = encoderR.getPulses()- countsOffsetR + countsCalibration; |
EvaKrolis | 0:aa126aa2ff8b | 434 | return countsR; |
EvaKrolis | 0:aa126aa2ff8b | 435 | } |
EvaKrolis | 0:aa126aa2ff8b | 436 | |
EvaKrolis | 0:aa126aa2ff8b | 437 | void motorTurnR() // main function for movement of motor 1, all above functions with an extra tab are called |
EvaKrolis | 0:aa126aa2ff8b | 438 | { |
EvaKrolis | 0:aa126aa2ff8b | 439 | float angleReferenceR = theta4; // insert kinematics output here instead of angleDesired() |
EvaKrolis | 0:aa126aa2ff8b | 440 | angleReferenceR = -angleReferenceR; // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 441 | countsR = countsInputCalibratedR(); // different encoder pins per motor |
EvaKrolis | 0:aa126aa2ff8b | 442 | angleCurrentR = angleCurrent(countsR); // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 443 | errorR = errorCalc(angleReferenceR,angleCurrentR); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 444 | |
EvaKrolis | 0:aa126aa2ff8b | 445 | float PIDControlR = PIDControllerR(angleReferenceR,angleCurrentR); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 446 | pin5 = fabs(PIDControlR); // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 447 | pin4 = PIDControlR > 0.0f; // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 448 | } |
EvaKrolis | 0:aa126aa2ff8b | 449 | |
EvaKrolis | 0:aa126aa2ff8b | 450 | void calibrationR() // Partially the same as motorTurnR, only with potmeter input |
EvaKrolis | 0:aa126aa2ff8b | 451 | // How it works: manually turn motor using potmeters until the robot arm touches the bookholder. |
EvaKrolis | 0:aa126aa2ff8b | 452 | // This program sets the counts from the motor to the reference counts (an angle of PI/4.0) |
EvaKrolis | 0:aa126aa2ff8b | 453 | // Do this for every motor and after calibrated all motors, press a button |
EvaKrolis | 0:aa126aa2ff8b | 454 | { |
EvaKrolis | 0:aa126aa2ff8b | 455 | float angleReferenceR = angleDesired(); // insert kinematics output here instead of angleDesired() |
EvaKrolis | 0:aa126aa2ff8b | 456 | angleReferenceR = -angleReferenceR; // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 457 | countsR = countsInputR(); // different encoder pins per motor |
EvaKrolis | 0:aa126aa2ff8b | 458 | angleCurrentR = angleCurrent(countsR); // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 459 | errorR = errorCalc(angleReferenceR,angleCurrentR); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 460 | |
EvaKrolis | 0:aa126aa2ff8b | 461 | if (fabs(errorR) >= 0.01f) { |
EvaKrolis | 0:aa126aa2ff8b | 462 | float PIDControlR = PIDControllerR(angleReferenceR,angleCurrentR); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 463 | pin5 = fabs(PIDControlR); // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 464 | pin4 = PIDControlR > 0.0f; // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 465 | } else if (fabs(errorR) < 0.01f) { |
EvaKrolis | 0:aa126aa2ff8b | 466 | countsOffsetR = countsR; |
EvaKrolis | 0:aa126aa2ff8b | 467 | countsR = countsR - countsOffsetR + countsCalibration; |
EvaKrolis | 0:aa126aa2ff8b | 468 | //countsR = 0; |
EvaKrolis | 0:aa126aa2ff8b | 469 | pin5 = 0.0f; |
EvaKrolis | 0:aa126aa2ff8b | 470 | // BUTTON PRESS: TO NEXT STATE |
EvaKrolis | 0:aa126aa2ff8b | 471 | } |
EvaKrolis | 0:aa126aa2ff8b | 472 | } |
EvaKrolis | 0:aa126aa2ff8b | 473 | |
EvaKrolis | 0:aa126aa2ff8b | 474 | // ------------------------- MOTOR FUNCTIONS FOR MOTOR FLIP -------------------- |
EvaKrolis | 0:aa126aa2ff8b | 475 | |
EvaKrolis | 0:aa126aa2ff8b | 476 | float PIDControllerF(float angleReference,float angleCurrent) // PID controller for the motors, based on the reference value and the current angle of the motor |
EvaKrolis | 0:aa126aa2ff8b | 477 | { float Kp = 19.24f; |
EvaKrolis | 0:aa126aa2ff8b | 478 | float Ki = 1.02f; |
EvaKrolis | 0:aa126aa2ff8b | 479 | float Kd = 0.827f; |
EvaKrolis | 0:aa126aa2ff8b | 480 | float error = errorCalc(angleReference,angleCurrent); |
EvaKrolis | 0:aa126aa2ff8b | 481 | static float errorIntegralF = 0.0; |
EvaKrolis | 0:aa126aa2ff8b | 482 | static float errorPreviousF = error; // initialization with this value only done once! |
EvaKrolis | 0:aa126aa2ff8b | 483 | static BiQuad PIDFilterF(0.0640, 0.1279, 0.0640, -1.1683, 0.4241); |
EvaKrolis | 0:aa126aa2ff8b | 484 | // Proportional part: |
EvaKrolis | 0:aa126aa2ff8b | 485 | float u_k = Kp * error; |
EvaKrolis | 0:aa126aa2ff8b | 486 | // Integral part |
EvaKrolis | 0:aa126aa2ff8b | 487 | errorIntegralF = errorIntegralF + error * dt; |
EvaKrolis | 0:aa126aa2ff8b | 488 | float u_i = Ki * errorIntegralF; |
EvaKrolis | 0:aa126aa2ff8b | 489 | // Derivative part |
EvaKrolis | 0:aa126aa2ff8b | 490 | float errorDerivative = (error - errorPreviousF)/dt; |
EvaKrolis | 0:aa126aa2ff8b | 491 | float errorDerivativeFiltered = PIDFilterF.step(errorDerivative); |
EvaKrolis | 0:aa126aa2ff8b | 492 | float u_d = Kd * errorDerivativeFiltered; |
EvaKrolis | 0:aa126aa2ff8b | 493 | errorPreviousF = error; |
EvaKrolis | 0:aa126aa2ff8b | 494 | // Sum all parts and return it |
EvaKrolis | 0:aa126aa2ff8b | 495 | return u_k + u_i + u_d; |
EvaKrolis | 0:aa126aa2ff8b | 496 | } |
EvaKrolis | 0:aa126aa2ff8b | 497 | |
EvaKrolis | 0:aa126aa2ff8b | 498 | int countsInputCalibratedF() // Gets the counts from encoder 1 |
EvaKrolis | 0:aa126aa2ff8b | 499 | { countsF = encoderF.getPulses()- countsOffsetF + countsCalibration; |
EvaKrolis | 0:aa126aa2ff8b | 500 | return countsF; |
EvaKrolis | 0:aa126aa2ff8b | 501 | } |
EvaKrolis | 0:aa126aa2ff8b | 502 | |
EvaKrolis | 0:aa126aa2ff8b | 503 | void motorTurnF() // main function for movement of motor 1, all above functions with an extra tab are called |
EvaKrolis | 0:aa126aa2ff8b | 504 | { |
EvaKrolis | 0:aa126aa2ff8b | 505 | float angleReferenceF = 0.0f; // insert kinematics output here instead of angleDesired() |
EvaKrolis | 0:aa126aa2ff8b | 506 | angleReferenceF = -angleReferenceF; // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 507 | countsF = countsInputCalibratedF(); // different encoder pins per motor |
EvaKrolis | 0:aa126aa2ff8b | 508 | angleCurrentF = angleCurrent(countsF); // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 509 | errorF = errorCalc(angleReferenceF,angleCurrentF); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 510 | |
EvaKrolis | 0:aa126aa2ff8b | 511 | float PIDControlF = PIDControllerF(angleReferenceF,angleCurrentF); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 512 | pin5 = fabs(PIDControlF); // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 513 | pin4 = PIDControlF > 0.0f; // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 514 | } |
EvaKrolis | 0:aa126aa2ff8b | 515 | |
EvaKrolis | 0:aa126aa2ff8b | 516 | void calibrationF() // Partially the same as motorTurnF, only with potmeter input |
EvaKrolis | 0:aa126aa2ff8b | 517 | // How it works: manually turn motor using potmeters until the robot arm touches the bookholder. |
EvaKrolis | 0:aa126aa2ff8b | 518 | // This program sets the counts from the motor to the reference counts (an angle of PI/4.0) |
EvaKrolis | 0:aa126aa2ff8b | 519 | // Do this for every motor and after calibrated all motors, press a button |
EvaKrolis | 0:aa126aa2ff8b | 520 | { float angleReferenceF = 0.0f; // insert kinematics output here instead of angleDesired() |
EvaKrolis | 0:aa126aa2ff8b | 521 | angleReferenceF = -angleReferenceF; // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 522 | countsF = countsInputF(); // different encoder pins per motor |
EvaKrolis | 0:aa126aa2ff8b | 523 | angleCurrentF = angleCurrent(countsF); // different minus sign per motor |
EvaKrolis | 0:aa126aa2ff8b | 524 | errorF = errorCalc(angleReferenceF,angleCurrentF); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 525 | |
EvaKrolis | 0:aa126aa2ff8b | 526 | if (fabs(errorF) >= 0.01f) |
EvaKrolis | 0:aa126aa2ff8b | 527 | { float PIDControlF = PIDControllerF(angleReferenceF,angleCurrentF); // same for every motor |
EvaKrolis | 0:aa126aa2ff8b | 528 | pin5 = fabs(PIDControlF); // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 529 | pin4 = PIDControlF > 0.0f; // different pins for every motor |
EvaKrolis | 0:aa126aa2ff8b | 530 | } |
EvaKrolis | 0:aa126aa2ff8b | 531 | else if (fabs(errorF) < 0.01f) |
EvaKrolis | 0:aa126aa2ff8b | 532 | { countsOffsetF = countsF; |
EvaKrolis | 0:aa126aa2ff8b | 533 | countsF = countsF - countsOffsetF + countsCalibration; |
EvaKrolis | 0:aa126aa2ff8b | 534 | //countsF = 0; |
EvaKrolis | 0:aa126aa2ff8b | 535 | pin5 = 0.0f; |
EvaKrolis | 0:aa126aa2ff8b | 536 | // BUTTON PRESS: TO NEXT STATE |
EvaKrolis | 0:aa126aa2ff8b | 537 | } |
EvaKrolis | 0:aa126aa2ff8b | 538 | } |
EvaKrolis | 0:aa126aa2ff8b | 539 | |
EvaKrolis | 0:aa126aa2ff8b | 540 | // ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ STATE MACHINE ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ |
EvaKrolis | 0:aa126aa2ff8b | 541 | void stateMachine(void) |
EvaKrolis | 0:aa126aa2ff8b | 542 | { |
EvaKrolis | 0:aa126aa2ff8b | 543 | switch (currentState) { // determine which state Odin is in |
EvaKrolis | 0:aa126aa2ff8b | 544 | |
EvaKrolis | 0:aa126aa2ff8b | 545 | // ======================== MOTOR L CALIBRATION MODE ========================= |
EvaKrolis | 0:aa126aa2ff8b | 546 | case calibratingMotorL: |
EvaKrolis | 0:aa126aa2ff8b | 547 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 548 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 549 | pc.printf("[MODE] calibrating motor L...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 550 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 551 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 552 | |
EvaKrolis | 0:aa126aa2ff8b | 553 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 554 | ledRed = 1; // green blinking LED |
EvaKrolis | 0:aa126aa2ff8b | 555 | ledGreen = 1; |
EvaKrolis | 0:aa126aa2ff8b | 556 | ledBlue = 1; |
EvaKrolis | 0:aa126aa2ff8b | 557 | blinkTimer.attach(&blinkLedGreen,0.5); |
EvaKrolis | 0:aa126aa2ff8b | 558 | |
EvaKrolis | 0:aa126aa2ff8b | 559 | } |
EvaKrolis | 0:aa126aa2ff8b | 560 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 561 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 562 | calibrationL(); |
EvaKrolis | 0:aa126aa2ff8b | 563 | |
EvaKrolis | 0:aa126aa2ff8b | 564 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 565 | // Transition condition: when all motor errors smaller than 0.01, |
EvaKrolis | 0:aa126aa2ff8b | 566 | // start calibrating EMG |
EvaKrolis | 0:aa126aa2ff8b | 567 | if (errorL < 0.01f && buttonBio1 == false) { |
EvaKrolis | 0:aa126aa2ff8b | 568 | |
EvaKrolis | 0:aa126aa2ff8b | 569 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 570 | blinkTimer.detach(); |
EvaKrolis | 0:aa126aa2ff8b | 571 | |
EvaKrolis | 0:aa126aa2ff8b | 572 | currentState = calibratingMotorR; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 573 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 574 | } |
EvaKrolis | 0:aa126aa2ff8b | 575 | |
EvaKrolis | 0:aa126aa2ff8b | 576 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 577 | |
EvaKrolis | 0:aa126aa2ff8b | 578 | // ======================== MOTOR R CALIBRATION MODE ========================= |
EvaKrolis | 0:aa126aa2ff8b | 579 | case calibratingMotorR: |
EvaKrolis | 0:aa126aa2ff8b | 580 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 581 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 582 | pc.printf("[MODE] calibrating motor R...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 583 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 584 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 585 | |
EvaKrolis | 0:aa126aa2ff8b | 586 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 587 | ledRed = 1; // cyan-green blinking LED |
EvaKrolis | 0:aa126aa2ff8b | 588 | ledGreen = 0; |
EvaKrolis | 0:aa126aa2ff8b | 589 | ledBlue = 1; |
EvaKrolis | 0:aa126aa2ff8b | 590 | blinkTimer.attach(&blinkLedBlue,0.5); |
EvaKrolis | 0:aa126aa2ff8b | 591 | |
EvaKrolis | 0:aa126aa2ff8b | 592 | } |
EvaKrolis | 0:aa126aa2ff8b | 593 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 594 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 595 | calibrationR(); |
EvaKrolis | 0:aa126aa2ff8b | 596 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 597 | // Transition condition: when all motor errors smaller than 0.01, |
EvaKrolis | 0:aa126aa2ff8b | 598 | // start calibrating EMG |
EvaKrolis | 0:aa126aa2ff8b | 599 | if (errorR < 0.01f && buttonBio2 == false) { |
EvaKrolis | 0:aa126aa2ff8b | 600 | |
EvaKrolis | 0:aa126aa2ff8b | 601 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 602 | blinkTimer.detach(); |
EvaKrolis | 0:aa126aa2ff8b | 603 | |
EvaKrolis | 0:aa126aa2ff8b | 604 | currentState = calibratingMotorF; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 605 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 606 | } |
EvaKrolis | 0:aa126aa2ff8b | 607 | |
EvaKrolis | 0:aa126aa2ff8b | 608 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 609 | |
EvaKrolis | 0:aa126aa2ff8b | 610 | // ======================== MOTOR F CALIBRATION MODE ========================= |
EvaKrolis | 0:aa126aa2ff8b | 611 | case calibratingMotorF: |
EvaKrolis | 0:aa126aa2ff8b | 612 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 613 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 614 | pc.printf("[MODE] calibrating motor F...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 615 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 616 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 617 | |
EvaKrolis | 0:aa126aa2ff8b | 618 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 619 | ledRed = 1; // green blinking LED |
EvaKrolis | 0:aa126aa2ff8b | 620 | ledGreen = 1; |
EvaKrolis | 0:aa126aa2ff8b | 621 | ledBlue = 1; |
EvaKrolis | 0:aa126aa2ff8b | 622 | blinkTimer.attach(&blinkLedGreen,0.5); |
EvaKrolis | 0:aa126aa2ff8b | 623 | |
EvaKrolis | 0:aa126aa2ff8b | 624 | } |
EvaKrolis | 0:aa126aa2ff8b | 625 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 626 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 627 | calibrationF(); |
EvaKrolis | 0:aa126aa2ff8b | 628 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 629 | // Transition condition: when all motor errors smaller than 0.01, |
EvaKrolis | 0:aa126aa2ff8b | 630 | // start calibrating EMG |
EvaKrolis | 0:aa126aa2ff8b | 631 | if (errorF < 0.01f && buttonHome == false) { |
EvaKrolis | 0:aa126aa2ff8b | 632 | |
EvaKrolis | 0:aa126aa2ff8b | 633 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 634 | blinkTimer.detach(); |
EvaKrolis | 0:aa126aa2ff8b | 635 | |
EvaKrolis | 0:aa126aa2ff8b | 636 | currentState = calibratingEMG; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 637 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 638 | } |
EvaKrolis | 0:aa126aa2ff8b | 639 | |
EvaKrolis | 0:aa126aa2ff8b | 640 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 641 | |
EvaKrolis | 0:aa126aa2ff8b | 642 | // =========================== EMG CALIBRATION MODE =========================== |
EvaKrolis | 0:aa126aa2ff8b | 643 | case calibratingEMG: |
EvaKrolis | 0:aa126aa2ff8b | 644 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 645 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 646 | pc.printf("[MODE] calibrating EMG...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 647 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 648 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 649 | |
EvaKrolis | 0:aa126aa2ff8b | 650 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 651 | ledRed = 1; // cyan-blue blinking LED |
EvaKrolis | 0:aa126aa2ff8b | 652 | ledGreen = 0; |
EvaKrolis | 0:aa126aa2ff8b | 653 | ledBlue = 0; |
EvaKrolis | 0:aa126aa2ff8b | 654 | blinkTimer.attach(&blinkLedGreen,0.5); |
EvaKrolis | 0:aa126aa2ff8b | 655 | |
EvaKrolis | 0:aa126aa2ff8b | 656 | FindMax0_timer.attach(&FindMax0,15); //Find the maximum value after 15 seconds |
EvaKrolis | 0:aa126aa2ff8b | 657 | FindMax1_timer.attach(&FindMax1,15); //Find the maximum value after 15 seconds |
EvaKrolis | 0:aa126aa2ff8b | 658 | |
EvaKrolis | 0:aa126aa2ff8b | 659 | EMGtransition_timer.reset(); |
EvaKrolis | 0:aa126aa2ff8b | 660 | EMGtransition_timer.start(); |
EvaKrolis | 0:aa126aa2ff8b | 661 | } |
EvaKrolis | 0:aa126aa2ff8b | 662 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 663 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 664 | CalibrateEMG0(); //start emg calibration every 0.005 seconds |
EvaKrolis | 0:aa126aa2ff8b | 665 | CalibrateEMG1(); //Start EMG calibration every 0.005 seconds |
EvaKrolis | 0:aa126aa2ff8b | 666 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 667 | |
EvaKrolis | 0:aa126aa2ff8b | 668 | |
EvaKrolis | 0:aa126aa2ff8b | 669 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 670 | // Transition condition: after 20 sec in state |
EvaKrolis | 0:aa126aa2ff8b | 671 | if (EMGtransition_timer.read() > 20) { |
EvaKrolis | 0:aa126aa2ff8b | 672 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 673 | blinkTimer.detach(); |
EvaKrolis | 0:aa126aa2ff8b | 674 | |
EvaKrolis | 0:aa126aa2ff8b | 675 | currentState = homing; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 676 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 677 | } |
EvaKrolis | 0:aa126aa2ff8b | 678 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 679 | |
EvaKrolis | 0:aa126aa2ff8b | 680 | // ============================== HOMING MODE ================================ |
EvaKrolis | 0:aa126aa2ff8b | 681 | case homing: |
EvaKrolis | 0:aa126aa2ff8b | 682 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 683 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 684 | pc.printf("[MODE] homing...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 685 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 686 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 687 | |
EvaKrolis | 0:aa126aa2ff8b | 688 | |
EvaKrolis | 0:aa126aa2ff8b | 689 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 690 | ledRed = 1; // cyan LED on |
EvaKrolis | 0:aa126aa2ff8b | 691 | ledGreen = 0; |
EvaKrolis | 0:aa126aa2ff8b | 692 | ledBlue = 0; |
EvaKrolis | 0:aa126aa2ff8b | 693 | |
EvaKrolis | 0:aa126aa2ff8b | 694 | } |
EvaKrolis | 0:aa126aa2ff8b | 695 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 696 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 697 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 698 | |
EvaKrolis | 0:aa126aa2ff8b | 699 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 700 | // Transition condition #1: with button press, enter reading mode, |
EvaKrolis | 0:aa126aa2ff8b | 701 | // but only when velocity == 0 |
EvaKrolis | 0:aa126aa2ff8b | 702 | if (errorCalibratedL < 0.01f && errorCalibratedR < 0.01f |
EvaKrolis | 0:aa126aa2ff8b | 703 | && errorCalibratedF < 0.01f && buttonBio1 == false) { |
EvaKrolis | 0:aa126aa2ff8b | 704 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 705 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 706 | |
EvaKrolis | 0:aa126aa2ff8b | 707 | currentState = reading; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 708 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 709 | } |
EvaKrolis | 0:aa126aa2ff8b | 710 | // Transition condition #2: with button press, enter demo mode |
EvaKrolis | 0:aa126aa2ff8b | 711 | // but only when velocity == 0 |
EvaKrolis | 0:aa126aa2ff8b | 712 | if (errorCalibratedL < 0.01f && errorCalibratedR < 0.01f |
EvaKrolis | 0:aa126aa2ff8b | 713 | && errorCalibratedF < 0.01f && buttonBio2 == false) { |
EvaKrolis | 0:aa126aa2ff8b | 714 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 715 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 716 | |
EvaKrolis | 0:aa126aa2ff8b | 717 | currentState = demoing; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 718 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 719 | } |
EvaKrolis | 0:aa126aa2ff8b | 720 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 721 | |
EvaKrolis | 0:aa126aa2ff8b | 722 | // ============================== READING MODE =============================== |
EvaKrolis | 0:aa126aa2ff8b | 723 | case reading: |
EvaKrolis | 0:aa126aa2ff8b | 724 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 725 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 726 | pc.printf("[MODE] reading...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 727 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 728 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 729 | |
EvaKrolis | 0:aa126aa2ff8b | 730 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 731 | ledRed = 1; // blue LED on |
EvaKrolis | 0:aa126aa2ff8b | 732 | ledGreen = 1; |
EvaKrolis | 0:aa126aa2ff8b | 733 | ledBlue = 0; |
EvaKrolis | 0:aa126aa2ff8b | 734 | |
EvaKrolis | 0:aa126aa2ff8b | 735 | // TERUGKLAPPEN |
EvaKrolis | 0:aa126aa2ff8b | 736 | |
EvaKrolis | 0:aa126aa2ff8b | 737 | } |
EvaKrolis | 0:aa126aa2ff8b | 738 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 739 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 740 | ReadUseEMG0(); //Start the use of EMG |
EvaKrolis | 0:aa126aa2ff8b | 741 | ReadUseEMG1(); //Start the use of EMG |
EvaKrolis | 0:aa126aa2ff8b | 742 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 743 | |
EvaKrolis | 0:aa126aa2ff8b | 744 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 745 | // Transition condition #1: when EMG signal detected, enter operating |
EvaKrolis | 0:aa126aa2ff8b | 746 | // mode |
EvaKrolis | 0:aa126aa2ff8b | 747 | if (xMove == true && yMove == true) { |
EvaKrolis | 0:aa126aa2ff8b | 748 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 749 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 750 | |
EvaKrolis | 0:aa126aa2ff8b | 751 | currentState = operating; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 752 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 753 | } |
EvaKrolis | 0:aa126aa2ff8b | 754 | // Transition condition #2: with button press, back to homing mode |
EvaKrolis | 0:aa126aa2ff8b | 755 | if (buttonHome == false) { |
EvaKrolis | 0:aa126aa2ff8b | 756 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 757 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 758 | |
EvaKrolis | 0:aa126aa2ff8b | 759 | currentState = homing; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 760 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 761 | } |
EvaKrolis | 0:aa126aa2ff8b | 762 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 763 | |
EvaKrolis | 0:aa126aa2ff8b | 764 | // ============================= OPERATING MODE ============================== |
EvaKrolis | 0:aa126aa2ff8b | 765 | case operating: |
EvaKrolis | 0:aa126aa2ff8b | 766 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 767 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 768 | pc.printf("[MODE] operating...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 769 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 770 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 771 | |
EvaKrolis | 0:aa126aa2ff8b | 772 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 773 | ledRed = 1; // blue fast blinking LED |
EvaKrolis | 0:aa126aa2ff8b | 774 | ledGreen = 1; |
EvaKrolis | 0:aa126aa2ff8b | 775 | ledBlue = 1; |
EvaKrolis | 0:aa126aa2ff8b | 776 | blinkTimer.attach(&blinkLedBlue,0.25); |
EvaKrolis | 0:aa126aa2ff8b | 777 | |
EvaKrolis | 0:aa126aa2ff8b | 778 | } |
EvaKrolis | 0:aa126aa2ff8b | 779 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 780 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 781 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 782 | |
EvaKrolis | 0:aa126aa2ff8b | 783 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 784 | // Transition condition: when path is over, back to reading mode |
EvaKrolis | 0:aa126aa2ff8b | 785 | if (errorCalibratedL < 0.01f && errorCalibratedR < 0.01f) { |
EvaKrolis | 0:aa126aa2ff8b | 786 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 787 | blinkTimer.detach(); |
EvaKrolis | 0:aa126aa2ff8b | 788 | |
EvaKrolis | 0:aa126aa2ff8b | 789 | currentState = reading; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 790 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 791 | } |
EvaKrolis | 0:aa126aa2ff8b | 792 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 793 | |
EvaKrolis | 0:aa126aa2ff8b | 794 | // ============================== DEMOING MODE =============================== |
EvaKrolis | 0:aa126aa2ff8b | 795 | case demoing: |
EvaKrolis | 0:aa126aa2ff8b | 796 | // ------------------------- initialisation -------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 797 | if (changeState) { // when entering the state |
EvaKrolis | 0:aa126aa2ff8b | 798 | pc.printf("[MODE] demoing...\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 799 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 800 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 801 | |
EvaKrolis | 0:aa126aa2ff8b | 802 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 803 | ledRed = 0; // yellow LED on |
EvaKrolis | 0:aa126aa2ff8b | 804 | ledGreen = 0; |
EvaKrolis | 0:aa126aa2ff8b | 805 | ledBlue = 1; |
EvaKrolis | 0:aa126aa2ff8b | 806 | |
EvaKrolis | 0:aa126aa2ff8b | 807 | } |
EvaKrolis | 0:aa126aa2ff8b | 808 | // ----------------------------- action ------------------------------ |
EvaKrolis | 0:aa126aa2ff8b | 809 | // Actions for each loop iteration |
EvaKrolis | 0:aa126aa2ff8b | 810 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 811 | ReadUseEMG0(); //Start the use of EMG |
EvaKrolis | 0:aa126aa2ff8b | 812 | ReadUseEMG1(); //Start the use of EMG |
EvaKrolis | 0:aa126aa2ff8b | 813 | pc.printf("theta1 and 4: %f \t\t %f \n\r",theta1,theta4); |
EvaKrolis | 0:aa126aa2ff8b | 814 | motorTurnL(); |
EvaKrolis | 0:aa126aa2ff8b | 815 | motorTurnR(); |
EvaKrolis | 0:aa126aa2ff8b | 816 | |
EvaKrolis | 0:aa126aa2ff8b | 817 | |
EvaKrolis | 0:aa126aa2ff8b | 818 | // --------------------------- transition ---------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 819 | // Transition condition: with button press, back to homing mode |
EvaKrolis | 0:aa126aa2ff8b | 820 | if (buttonHome == false) { |
EvaKrolis | 0:aa126aa2ff8b | 821 | // Actions when leaving state |
EvaKrolis | 0:aa126aa2ff8b | 822 | /* */ |
EvaKrolis | 0:aa126aa2ff8b | 823 | |
EvaKrolis | 0:aa126aa2ff8b | 824 | currentState = homing; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 825 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 826 | } |
EvaKrolis | 0:aa126aa2ff8b | 827 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 828 | |
EvaKrolis | 0:aa126aa2ff8b | 829 | // =============================== FAILING MODE ================================ |
EvaKrolis | 0:aa126aa2ff8b | 830 | case failing: |
EvaKrolis | 0:aa126aa2ff8b | 831 | changeState = false; // stay in this state |
EvaKrolis | 0:aa126aa2ff8b | 832 | |
EvaKrolis | 0:aa126aa2ff8b | 833 | // Actions when entering state |
EvaKrolis | 0:aa126aa2ff8b | 834 | ledRed = 0; // red LED on |
EvaKrolis | 0:aa126aa2ff8b | 835 | ledGreen = 1; |
EvaKrolis | 0:aa126aa2ff8b | 836 | ledBlue = 1; |
EvaKrolis | 0:aa126aa2ff8b | 837 | |
EvaKrolis | 0:aa126aa2ff8b | 838 | pin3 = 0; // all motor forces to zero |
EvaKrolis | 0:aa126aa2ff8b | 839 | pin5 = 0; |
EvaKrolis | 0:aa126aa2ff8b | 840 | pin6 = 0; |
EvaKrolis | 0:aa126aa2ff8b | 841 | exit (0); // stop all current functions |
EvaKrolis | 0:aa126aa2ff8b | 842 | break; // end case |
EvaKrolis | 0:aa126aa2ff8b | 843 | |
EvaKrolis | 0:aa126aa2ff8b | 844 | // ============================== DEFAULT MODE ================================= |
EvaKrolis | 0:aa126aa2ff8b | 845 | default: |
EvaKrolis | 0:aa126aa2ff8b | 846 | // ---------------------------- enter failing mode ----------------------------- |
EvaKrolis | 0:aa126aa2ff8b | 847 | currentState = failing; // change to state |
EvaKrolis | 0:aa126aa2ff8b | 848 | changeState = true; // next loop, switch states |
EvaKrolis | 0:aa126aa2ff8b | 849 | // print current state |
EvaKrolis | 0:aa126aa2ff8b | 850 | pc.printf("[ERROR] unknown or unimplemented state reached\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 851 | |
EvaKrolis | 0:aa126aa2ff8b | 852 | } // end switch |
EvaKrolis | 0:aa126aa2ff8b | 853 | } // end stateMachine |
EvaKrolis | 0:aa126aa2ff8b | 854 | |
EvaKrolis | 0:aa126aa2ff8b | 855 | |
EvaKrolis | 0:aa126aa2ff8b | 856 | |
EvaKrolis | 0:aa126aa2ff8b | 857 | // ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ MAIN LOOP ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ |
EvaKrolis | 0:aa126aa2ff8b | 858 | |
EvaKrolis | 0:aa126aa2ff8b | 859 | int main() |
EvaKrolis | 0:aa126aa2ff8b | 860 | { |
EvaKrolis | 0:aa126aa2ff8b | 861 | // ================================ EMERGENCY ================================ |
EvaKrolis | 0:aa126aa2ff8b | 862 | //If the emergency button is pressed, stop program via failing state |
EvaKrolis | 0:aa126aa2ff8b | 863 | buttonEmergency.rise(stopProgram); // Automatische triggers voor failure mode? -> ook error message in andere functies plaatsen! |
EvaKrolis | 0:aa126aa2ff8b | 864 | |
EvaKrolis | 0:aa126aa2ff8b | 865 | // ============================= PC-COMMUNICATION ============================ |
EvaKrolis | 0:aa126aa2ff8b | 866 | pc.baud(115200); // communication with terminal |
EvaKrolis | 0:aa126aa2ff8b | 867 | pc.printf("\n\n[START] starting O.D.I.N\r\n"); |
EvaKrolis | 0:aa126aa2ff8b | 868 | |
EvaKrolis | 0:aa126aa2ff8b | 869 | // ============================= PIN DEFINE PERIOD =========================== |
EvaKrolis | 0:aa126aa2ff8b | 870 | // If you give a period on one pin, c++ gives all pins this period |
EvaKrolis | 0:aa126aa2ff8b | 871 | pin3.period_us(15); |
EvaKrolis | 0:aa126aa2ff8b | 872 | |
EvaKrolis | 0:aa126aa2ff8b | 873 | // ==================================== LOOP ================================== |
EvaKrolis | 0:aa126aa2ff8b | 874 | // run state machine at 500 Hz |
EvaKrolis | 0:aa126aa2ff8b | 875 | stateTimer.attach(&stateMachine,dt); |
EvaKrolis | 0:aa126aa2ff8b | 876 | |
EvaKrolis | 0:aa126aa2ff8b | 877 | // =============================== ADD FILTERS =============================== |
EvaKrolis | 0:aa126aa2ff8b | 878 | //Make filter chain for the first EMG |
EvaKrolis | 0:aa126aa2ff8b | 879 | filter0.add(&Notch50_0).add(&Notch100_0).add(&Notch150_0).add(&Notch200_0).add(&Low_0).add(&High_0); |
EvaKrolis | 0:aa126aa2ff8b | 880 | //Make filter chain for the second EMG |
EvaKrolis | 0:aa126aa2ff8b | 881 | filter1.add(&Notch50_1).add(&Notch100_1).add(&Notch150_1).add(&Notch200_1).add(&Low_1).add(&High_1); |
EvaKrolis | 0:aa126aa2ff8b | 882 | } |