not working yet
Dependencies: Motor_with_encoder MODSERIAL mbed HIDScope
main.cpp@13:acd120520e80, 2017-10-30 (annotated)
- Committer:
- EvB
- Date:
- Mon Oct 30 15:01:26 2017 +0000
- Revision:
- 13:acd120520e80
- Parent:
- 12:5be2001abe62
- Child:
- 14:7a95e57b5364
Implemented kinematics and movement description. Not tested at all, but compilable.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MMartens | 0:9167ae5d9927 | 1 | #include "mbed.h" |
MMartens | 0:9167ae5d9927 | 2 | #include "MODSERIAL.h" |
MMartens | 0:9167ae5d9927 | 3 | #include "encoder.h" |
MMartens | 0:9167ae5d9927 | 4 | #include "math.h" |
MMartens | 3:e888f52a46bc | 5 | #include "HIDScope.h" |
vera1 | 8:9edf32e021a5 | 6 | #include "BiQuad.h" |
vera1 | 8:9edf32e021a5 | 7 | #include "EMG_filter.h" |
EvB | 13:acd120520e80 | 8 | #include "Matrix.h" |
EvB | 13:acd120520e80 | 9 | #include "MatrixMath.h" |
vera1 | 8:9edf32e021a5 | 10 | |
EvB | 13:acd120520e80 | 11 | const double pi = 3.14159265359; // Defining the constant pi |
vera1 | 11:bda77916d2ea | 12 | |
EvB | 13:acd120520e80 | 13 | MODSERIAL pc(USBTX,USBRX); // Enabling communication with the pc. |
EvB | 13:acd120520e80 | 14 | |
EvB | 13:acd120520e80 | 15 | enum r_states {R_HORIZONTAL, R_VERTICAL, R_BASE}; // Defining states of the robot |
vera1 | 11:bda77916d2ea | 16 | r_states state; |
vera1 | 11:bda77916d2ea | 17 | |
vera1 | 8:9edf32e021a5 | 18 | // ---- EMG parameters ---- |
EvB | 13:acd120520e80 | 19 | //HIDScope scope (2); |
vera1 | 8:9edf32e021a5 | 20 | EMG_filter emg1(A0); |
vera1 | 11:bda77916d2ea | 21 | EMG_filter emg2(A1); |
EvB | 13:acd120520e80 | 22 | float EMG_threshold = 0.2; // Threshold for the EMG signal |
EvB | 13:acd120520e80 | 23 | // ------------------------ |
vera1 | 8:9edf32e021a5 | 24 | |
vera1 | 8:9edf32e021a5 | 25 | // ---- Motor input and outputs ---- |
MMartens | 0:9167ae5d9927 | 26 | PwmOut speed1(D5); |
MMartens | 4:75f6e4845194 | 27 | PwmOut speed2(D6); |
vera1 | 12:5be2001abe62 | 28 | PwmOut speedservo1(D11); |
vera1 | 12:5be2001abe62 | 29 | //PwmOut speedservo2(D8); |
MMartens | 0:9167ae5d9927 | 30 | DigitalOut dir1(D4); |
MMartens | 4:75f6e4845194 | 31 | DigitalOut dir2(D7); |
vera1 | 6:fc46581fe3e0 | 32 | DigitalIn press(PTA4); |
vera1 | 11:bda77916d2ea | 33 | DigitalOut ledred(LED_RED); |
vera1 | 11:bda77916d2ea | 34 | DigitalOut ledgreen(LED_GREEN); |
vera1 | 11:bda77916d2ea | 35 | DigitalOut ledblue(LED_BLUE); |
vera1 | 12:5be2001abe62 | 36 | DigitalOut ledstateswitch(D3); |
vera1 | 12:5be2001abe62 | 37 | DigitalOut ledstatedef(D2); |
MMartens | 4:75f6e4845194 | 38 | AnalogIn pot(A2); |
vera1 | 11:bda77916d2ea | 39 | AnalogIn pot2(A3); |
MMartens | 0:9167ae5d9927 | 40 | Encoder motor1(PTD0,PTC4); |
MMartens | 4:75f6e4845194 | 41 | Encoder motor2(D12,D13); |
vera1 | 8:9edf32e021a5 | 42 | // ---------------------------------- |
vera1 | 8:9edf32e021a5 | 43 | |
vera1 | 8:9edf32e021a5 | 44 | // --- Define Ticker and Timeout --- |
EvB | 13:acd120520e80 | 45 | Ticker mainticker; //Ticker that calls every function. Functions are called by means of a variable named go, e.g. go_EMG |
vera1 | 8:9edf32e021a5 | 46 | Timeout calibrationgo; // Timeout that will determine the duration of the calibration. |
vera1 | 8:9edf32e021a5 | 47 | // --------------------------------- |
vera1 | 8:9edf32e021a5 | 48 | |
MMartens | 0:9167ae5d9927 | 49 | |
MMartens | 1:f3fe6d2b7639 | 50 | float PwmPeriod = 0.0001f; |
MMartens | 1:f3fe6d2b7639 | 51 | |
EvB | 13:acd120520e80 | 52 | volatile double Pos1; // Encoder readout of motor 1 [counts] |
EvB | 13:acd120520e80 | 53 | volatile double Pos2; // Encoder readout of motor 2 [counts] |
EvB | 13:acd120520e80 | 54 | volatile int count = 0; // Loop counts |
MMartens | 0:9167ae5d9927 | 55 | |
vera1 | 12:5be2001abe62 | 56 | double Kp = 250;// you can set these constants however you like depending on trial & error |
MMartens | 3:e888f52a46bc | 57 | double Ki = 100; |
MMartens | 2:7c6391c8ca71 | 58 | double Kd = 0; |
MMartens | 0:9167ae5d9927 | 59 | |
MMartens | 0:9167ae5d9927 | 60 | float last_error = 0; |
MMartens | 1:f3fe6d2b7639 | 61 | float error1 = 0; |
MMartens | 0:9167ae5d9927 | 62 | float changeError = 0; |
MMartens | 0:9167ae5d9927 | 63 | float totalError = 0; |
MMartens | 0:9167ae5d9927 | 64 | float pidTerm = 0; |
MMartens | 4:75f6e4845194 | 65 | float pidTerm_scaled = 0; |
MMartens | 4:75f6e4845194 | 66 | |
MMartens | 4:75f6e4845194 | 67 | float last_error2 = 0; |
MMartens | 4:75f6e4845194 | 68 | float error2 = 0; |
MMartens | 4:75f6e4845194 | 69 | float changeError2 = 0; |
MMartens | 4:75f6e4845194 | 70 | float totalError2 = 0; |
MMartens | 4:75f6e4845194 | 71 | float pidTerm2 = 0; |
MMartens | 4:75f6e4845194 | 72 | float pidTerm_scaled2 = 0;// if the total gain we get is not in the PWM range we scale it down so that it's not bigger than |255| |
MMartens | 0:9167ae5d9927 | 73 | |
MMartens | 0:9167ae5d9927 | 74 | volatile double potvalue = 0.0; |
MMartens | 4:75f6e4845194 | 75 | volatile double potvalue2 = 0.0; |
MMartens | 0:9167ae5d9927 | 76 | volatile double position = 0.0; |
MMartens | 4:75f6e4845194 | 77 | volatile double position2 = 0.0; |
MMartens | 3:e888f52a46bc | 78 | |
EvB | 13:acd120520e80 | 79 | // --- Kinematics parameter --- |
EvB | 13:acd120520e80 | 80 | float L1 = 0.38; // length of link 1 [m] |
EvB | 13:acd120520e80 | 81 | float L5 = 0.25; // length of link 5 [m] |
EvB | 13:acd120520e80 | 82 | float d = 0.03; // diameter of the pulley [m] |
EvB | 13:acd120520e80 | 83 | |
EvB | 13:acd120520e80 | 84 | volatile float xe; // x-coordinate of end-effector |
EvB | 13:acd120520e80 | 85 | volatile float ye; // y-coordinate of end-effector |
EvB | 13:acd120520e80 | 86 | volatile float ze; // z-coordinate of end-effector |
EvB | 13:acd120520e80 | 87 | |
EvB | 13:acd120520e80 | 88 | volatile float Q1; // Position of joint 1 [m] |
EvB | 13:acd120520e80 | 89 | volatile float Q2; // Position of joint 2 [rad] |
EvB | 13:acd120520e80 | 90 | volatile float Q3; // Position of joint 3 [rad] |
EvB | 13:acd120520e80 | 91 | |
EvB | 13:acd120520e80 | 92 | volatile float V1; // Desired velocity of joint 1 [m/s]; --> or normalize it? |
EvB | 13:acd120520e80 | 93 | volatile float W2; // Desired velocity of joint 2 [rad/s]; |
EvB | 13:acd120520e80 | 94 | volatile float W3; // Desired velocity of joint 3 [rad/s]; |
EvB | 13:acd120520e80 | 95 | |
EvB | 13:acd120520e80 | 96 | volatile float Vx_des; // Desired velocity end-effector in x-direction [m/s] |
EvB | 13:acd120520e80 | 97 | volatile float Vy_des; // Desired velocity end-effector in y-direction [m/s] |
EvB | 13:acd120520e80 | 98 | volatile float Vz_des; // Desired velocity end-effector in z-direction [m/s] |
EvB | 13:acd120520e80 | 99 | |
EvB | 13:acd120520e80 | 100 | const float T = 0.002; // Time interval of the readout of the EMG --> Check this with the ticker, etc!!! |
EvB | 13:acd120520e80 | 101 | |
EvB | 13:acd120520e80 | 102 | |
vera1 | 8:9edf32e021a5 | 103 | // --- Booleans for the maintickerfunction --- |
vera1 | 6:fc46581fe3e0 | 104 | //bool readoutsetpoint = true; |
vera1 | 8:9edf32e021a5 | 105 | bool go_EMG; // Boolean to put on/off the EMG readout |
EvB | 13:acd120520e80 | 106 | bool go_calibration; // Boolean to put on/off the calibration of the EMG |
EvB | 13:acd120520e80 | 107 | bool go_switch; // Boolean to go to different state |
EvB | 13:acd120520e80 | 108 | bool go_PID; // Boolean to calculate PID and motor aansturing --> probably replaced by go_move |
EvB | 13:acd120520e80 | 109 | bool go_move; //Boolean to move the robot arm and base |
EvB | 13:acd120520e80 | 110 | bool go_kinematics; // Boolean which will determine whether a new position will be calculated or not --> replace by go_move? |
vera1 | 8:9edf32e021a5 | 111 | // ------------------------------------------- |
vera1 | 8:9edf32e021a5 | 112 | |
vera1 | 8:9edf32e021a5 | 113 | // --- calibrate EMG signal ---- |
vera1 | 8:9edf32e021a5 | 114 | |
vera1 | 8:9edf32e021a5 | 115 | void calibrationGO() // Function for go or no go of calibration |
vera1 | 8:9edf32e021a5 | 116 | { |
vera1 | 8:9edf32e021a5 | 117 | go_calibration = false; |
EvB | 13:acd120520e80 | 118 | |
vera1 | 8:9edf32e021a5 | 119 | } |
vera1 | 8:9edf32e021a5 | 120 | |
vera1 | 8:9edf32e021a5 | 121 | /* |
vera1 | 8:9edf32e021a5 | 122 | Calibration of the robot works as follows: |
vera1 | 8:9edf32e021a5 | 123 | EMG signal is read out for 5 seconds, 1000 times a second. This signal is filtered and the maximum value is compared to the current value of the MVC. |
EvB | 13:acd120520e80 | 124 | The value of the MVC is overwritten when the value of the filtered signal is bigger than the current value. |
vera1 | 8:9edf32e021a5 | 125 | During the calibration the user should exert maximum force. |
vera1 | 8:9edf32e021a5 | 126 | */ |
vera1 | 8:9edf32e021a5 | 127 | void calibrationEMG() // Function for calibrating the EMG signal |
vera1 | 8:9edf32e021a5 | 128 | { |
EvB | 13:acd120520e80 | 129 | if (go_calibration) { |
EvB | 13:acd120520e80 | 130 | |
EvB | 13:acd120520e80 | 131 | emg1.calibration(); // Using the calibration function of the EMG_filter class |
EvB | 13:acd120520e80 | 132 | emg2.calibration(); |
vera1 | 8:9edf32e021a5 | 133 | } |
vera1 | 8:9edf32e021a5 | 134 | } |
vera1 | 8:9edf32e021a5 | 135 | |
vera1 | 8:9edf32e021a5 | 136 | // ------------------------------ |
EvB | 13:acd120520e80 | 137 | //Function that reads out the raw EMG and filters the signal |
EvB | 13:acd120520e80 | 138 | void processEMG () |
EvB | 13:acd120520e80 | 139 | { |
MMartens | 3:e888f52a46bc | 140 | |
EvB | 13:acd120520e80 | 141 | |
EvB | 13:acd120520e80 | 142 | emg1.filter(); //filter the incoming emg signal |
EvB | 13:acd120520e80 | 143 | emg2.filter(); |
EvB | 13:acd120520e80 | 144 | //emg3.filter(); |
EvB | 13:acd120520e80 | 145 | |
EvB | 13:acd120520e80 | 146 | /* scope.set(0, emg1.normalized); //views emg1.normalized on port 0 of HIDScope |
EvB | 13:acd120520e80 | 147 | scope.set(1, emg1.emg0); |
EvB | 13:acd120520e80 | 148 | scope.send();*/ |
EvB | 13:acd120520e80 | 149 | |
EvB | 13:acd120520e80 | 150 | } |
EvB | 13:acd120520e80 | 151 | |
EvB | 13:acd120520e80 | 152 | // --- Kinematics functions --- |
EvB | 13:acd120520e80 | 153 | |
EvB | 13:acd120520e80 | 154 | void Brockett(float q1, float q2, float q3) // Determine position of end-effector using Brockett |
vera1 | 11:bda77916d2ea | 155 | { |
vera1 | 11:bda77916d2ea | 156 | |
EvB | 13:acd120520e80 | 157 | Matrix E100b(4,4); // Complete matrix form of 1st joint |
EvB | 13:acd120520e80 | 158 | E100b = MatrixMath::Eye(4); |
EvB | 13:acd120520e80 | 159 | E100b(3,4) = q1; |
EvB | 13:acd120520e80 | 160 | |
EvB | 13:acd120520e80 | 161 | |
EvB | 13:acd120520e80 | 162 | Matrix E210b(4,4); // Complete matrix form of 2nd joint |
EvB | 13:acd120520e80 | 163 | E210b = MatrixMath::RotZ(q2); |
EvB | 13:acd120520e80 | 164 | |
EvB | 13:acd120520e80 | 165 | |
EvB | 13:acd120520e80 | 166 | Matrix E320b(4,4); // Complete matrix form of 3rd joint |
EvB | 13:acd120520e80 | 167 | E320b = MatrixMath::RotZ(q3-q2); |
EvB | 13:acd120520e80 | 168 | E320b(1,4) = L1 - L1*cos(q3-q2); |
EvB | 13:acd120520e80 | 169 | E320b(2,4) = -L1*sin(q3-q2); |
EvB | 13:acd120520e80 | 170 | |
EvB | 13:acd120520e80 | 171 | |
EvB | 13:acd120520e80 | 172 | Matrix HE0ref(4,4); // H-matrix of the robot in reference position |
EvB | 13:acd120520e80 | 173 | HE0ref = MatrixMath::Eye(4); |
EvB | 13:acd120520e80 | 174 | HE0ref(1,4) = L1; |
EvB | 13:acd120520e80 | 175 | HE0ref(2,4) = -L5; |
EvB | 13:acd120520e80 | 176 | |
EvB | 13:acd120520e80 | 177 | |
EvB | 13:acd120520e80 | 178 | Matrix HE0(4,4); // H-matrix to find the position of the end-effector, expressed in frame 0. |
EvB | 13:acd120520e80 | 179 | HE0 = E100b * E210b * E320b * HE0ref; // This H-matrix is not really correct. Check with matlab!!! |
EvB | 13:acd120520e80 | 180 | |
EvB | 13:acd120520e80 | 181 | |
EvB | 13:acd120520e80 | 182 | // Determine new position of end effector |
EvB | 13:acd120520e80 | 183 | xe = HE0(1,4); // New x-coordinate of the end-effector |
EvB | 13:acd120520e80 | 184 | ye = HE0(2,4); // New y-coordinate of the end-effector |
EvB | 13:acd120520e80 | 185 | ze = HE0(3,4); // New z-coordinate of the end-effector |
EvB | 13:acd120520e80 | 186 | |
vera1 | 11:bda77916d2ea | 187 | |
vera1 | 11:bda77916d2ea | 188 | } |
vera1 | 11:bda77916d2ea | 189 | |
EvB | 13:acd120520e80 | 190 | void Jacobian(float vx_des, float vy_des, float vz_des) // Function to determine the velocities with desired velocity as input |
vera1 | 11:bda77916d2ea | 191 | { |
EvB | 13:acd120520e80 | 192 | //kinematics_go = false; // putting boolean to false |
EvB | 13:acd120520e80 | 193 | |
EvB | 13:acd120520e80 | 194 | // Finding joint positions |
EvB | 13:acd120520e80 | 195 | Q1 = Pos1; // Position of joint 1 [m] |
EvB | 13:acd120520e80 | 196 | Q2 = Pos2; // Position of joint 2 [rad] |
EvB | 13:acd120520e80 | 197 | Q3 = 0; // Position of joint 3 [rad] --> need this from Servo! |
EvB | 13:acd120520e80 | 198 | |
EvB | 13:acd120520e80 | 199 | //pc.printf("\r\nq1 = %.3f, q2 = %.3f, q3 = %.3f\r\n", q1, q2, q3); |
EvB | 13:acd120520e80 | 200 | |
EvB | 13:acd120520e80 | 201 | Brockett(Q1,Q2,Q3); // Start with conducting Brockett to obtain the end-effector position |
EvB | 13:acd120520e80 | 202 | |
EvB | 13:acd120520e80 | 203 | Matrix T_des(3,1); // Twist of desired linear velocities |
EvB | 13:acd120520e80 | 204 | T_des(1,1) = vx_des; |
EvB | 13:acd120520e80 | 205 | T_des(2,1) = vy_des; |
EvB | 13:acd120520e80 | 206 | T_des(3,1) = vz_des; |
EvB | 13:acd120520e80 | 207 | |
EvB | 13:acd120520e80 | 208 | |
EvB | 13:acd120520e80 | 209 | Matrix T100j(1,4); // Unit twist of the first frame in current configuration |
EvB | 13:acd120520e80 | 210 | T100j(1,4) = 1; |
EvB | 13:acd120520e80 | 211 | |
EvB | 13:acd120520e80 | 212 | Matrix T210j(1,4); // Unit twist of the second frame in current configuration |
EvB | 13:acd120520e80 | 213 | T210j(1,1) = 1; |
EvB | 13:acd120520e80 | 214 | |
EvB | 13:acd120520e80 | 215 | Matrix T320j(1,4); // Unit twist of the third frame in current configuration |
EvB | 13:acd120520e80 | 216 | T320j(1,1) = 1; |
EvB | 13:acd120520e80 | 217 | T320j(1,2) = -L1*sin(Q2); |
EvB | 13:acd120520e80 | 218 | T320j(1,3) = -L1 * cos(Q2); |
EvB | 13:acd120520e80 | 219 | |
EvB | 13:acd120520e80 | 220 | Matrix J(4,3); // Jacobian matrix |
EvB | 13:acd120520e80 | 221 | |
EvB | 13:acd120520e80 | 222 | for (int i = 1 ; i < 5 ; i++) { |
EvB | 13:acd120520e80 | 223 | J(i,1) = T100j(1,i); |
EvB | 13:acd120520e80 | 224 | } |
EvB | 13:acd120520e80 | 225 | |
EvB | 13:acd120520e80 | 226 | for (int i = 1 ; i < 5 ; i++) { |
EvB | 13:acd120520e80 | 227 | J(i,2) = T210j(1,i); |
EvB | 13:acd120520e80 | 228 | } |
EvB | 13:acd120520e80 | 229 | |
EvB | 13:acd120520e80 | 230 | for (int i = 1 ; i < 5 ; i++) { |
EvB | 13:acd120520e80 | 231 | J(i,3) = T320j(1,i); |
EvB | 13:acd120520e80 | 232 | } |
EvB | 13:acd120520e80 | 233 | |
EvB | 13:acd120520e80 | 234 | |
EvB | 13:acd120520e80 | 235 | Matrix H0f(4,4); // H-matrix to transform Jacobian from frame 0 to frame f, which is attached to the end-effector, but not rotating with it. |
EvB | 13:acd120520e80 | 236 | H0f = MatrixMath::Eye(4); |
EvB | 13:acd120520e80 | 237 | H0f(1,4) = -xe; |
EvB | 13:acd120520e80 | 238 | H0f(2,4) = -ye; |
EvB | 13:acd120520e80 | 239 | H0f(3,4) = -ze; |
EvB | 13:acd120520e80 | 240 | |
EvB | 13:acd120520e80 | 241 | Matrix AdH0f(4,4); // Adjoint of H0f, necessary for twist transformations |
EvB | 13:acd120520e80 | 242 | AdH0f = MatrixMath::Eye(4); |
EvB | 13:acd120520e80 | 243 | AdH0f(2,1) = H0f(2,4); |
EvB | 13:acd120520e80 | 244 | AdH0f(3,1) = -H0f(1,4); |
EvB | 13:acd120520e80 | 245 | |
EvB | 13:acd120520e80 | 246 | Matrix Jprime(4,3); // Transformed Jacobian |
EvB | 13:acd120520e80 | 247 | Jprime = AdH0f*J; |
EvB | 13:acd120520e80 | 248 | |
EvB | 13:acd120520e80 | 249 | Matrix Jprimeprime(3,3); // Truncated Jacobian |
EvB | 13:acd120520e80 | 250 | for (int i = 1 ; i <4 ; i++) { |
EvB | 13:acd120520e80 | 251 | for (int j = 1 ; j < 4 ; j++) { |
EvB | 13:acd120520e80 | 252 | Jprimeprime(i,j) = Jprime(i+1,j); |
EvB | 13:acd120520e80 | 253 | } |
EvB | 13:acd120520e80 | 254 | } |
EvB | 13:acd120520e80 | 255 | |
EvB | 13:acd120520e80 | 256 | Matrix JprimeprimeT(3,3); // The transpose of the truncated Jacobian |
EvB | 13:acd120520e80 | 257 | JprimeprimeT = MatrixMath::Transpose(Jprimeprime); |
EvB | 13:acd120520e80 | 258 | |
EvB | 13:acd120520e80 | 259 | Matrix PseudoInverse(3,3); // The Pseudo-inverse of the truncated Jacobian |
EvB | 13:acd120520e80 | 260 | PseudoInverse = MatrixMath::Inv(JprimeprimeT*Jprimeprime)*JprimeprimeT; |
EvB | 13:acd120520e80 | 261 | |
EvB | 13:acd120520e80 | 262 | Matrix Q_dot(1,3); // Desired joint velocities |
EvB | 13:acd120520e80 | 263 | Q_dot = PseudoInverse * T_des; |
EvB | 13:acd120520e80 | 264 | |
EvB | 13:acd120520e80 | 265 | V1 = Q_dot(1,1); |
EvB | 13:acd120520e80 | 266 | W2 = Q_dot(2,1); |
EvB | 13:acd120520e80 | 267 | W3 = Q_dot(3,1); |
EvB | 13:acd120520e80 | 268 | |
EvB | 13:acd120520e80 | 269 | // pc.printf("\r\nv1 = %.3f, w2 = %.3f, w3 = %.3f\r\n", V1,W2,W3); |
EvB | 13:acd120520e80 | 270 | |
EvB | 13:acd120520e80 | 271 | // Eva - not sure if we need this... --> I think for the setpoint of the PID controller |
EvB | 13:acd120520e80 | 272 | Q1 += V1*T; // Predicted value for q1 [m] |
EvB | 13:acd120520e80 | 273 | Q2 += W2*T; // Predicted value for q2 [rad] |
EvB | 13:acd120520e80 | 274 | Q3 += W3*T; // Predicted value for q3 [rad] |
EvB | 13:acd120520e80 | 275 | |
EvB | 13:acd120520e80 | 276 | // pc.printf("\r\n q1 = %.3f, q2 = %.3f, q3 = %.3f\r\n", q1,q2,q3); |
vera1 | 11:bda77916d2ea | 277 | |
vera1 | 11:bda77916d2ea | 278 | } |
vera1 | 11:bda77916d2ea | 279 | |
vera1 | 11:bda77916d2ea | 280 | //--- State switch function ----- |
vera1 | 11:bda77916d2ea | 281 | void r_processStateSwitch() |
MMartens | 5:8c6d66a7c5da | 282 | { |
EvB | 13:acd120520e80 | 283 | go_switch = false; |
EvB | 13:acd120520e80 | 284 | switch(state) { |
EvB | 13:acd120520e80 | 285 | case R_HORIZONTAL: |
EvB | 13:acd120520e80 | 286 | state = R_VERTICAL; |
EvB | 13:acd120520e80 | 287 | ledblue = 1; |
EvB | 13:acd120520e80 | 288 | ledred = 1; |
EvB | 13:acd120520e80 | 289 | ledgreen = 0; |
EvB | 13:acd120520e80 | 290 | pc.printf("state is vertical"); |
EvB | 13:acd120520e80 | 291 | break; |
EvB | 13:acd120520e80 | 292 | case R_VERTICAL: |
EvB | 13:acd120520e80 | 293 | state = R_BASE; |
EvB | 13:acd120520e80 | 294 | ledgreen = 1; |
EvB | 13:acd120520e80 | 295 | ledblue = 1; |
EvB | 13:acd120520e80 | 296 | ledred = 0; |
EvB | 13:acd120520e80 | 297 | pc.printf("state is base"); |
EvB | 13:acd120520e80 | 298 | break; |
EvB | 13:acd120520e80 | 299 | case R_BASE: |
EvB | 13:acd120520e80 | 300 | state = R_HORIZONTAL; |
EvB | 13:acd120520e80 | 301 | ledgreen = 1; |
EvB | 13:acd120520e80 | 302 | ledred = 1; |
EvB | 13:acd120520e80 | 303 | ledblue = 0; |
EvB | 13:acd120520e80 | 304 | pc.printf("state is horizontal"); |
EvB | 13:acd120520e80 | 305 | break; |
EvB | 13:acd120520e80 | 306 | } |
EvB | 13:acd120520e80 | 307 | wait(1.0f); // waits 1 second to continue with the main function. I think ticker does run, but main is on hold. |
EvB | 13:acd120520e80 | 308 | ledstatedef = 1; |
EvB | 13:acd120520e80 | 309 | ledstateswitch = 0; |
EvB | 13:acd120520e80 | 310 | go_move = true; |
MMartens | 5:8c6d66a7c5da | 311 | } |
vera1 | 8:9edf32e021a5 | 312 | |
EvB | 13:acd120520e80 | 313 | // --- Determine the setpoints of the joint velocities |
EvB | 13:acd120520e80 | 314 | void setpointreadout(float v_des) |
vera1 | 8:9edf32e021a5 | 315 | { |
EvB | 13:acd120520e80 | 316 | /* |
vera1 | 11:bda77916d2ea | 317 | potvalue = pot.read(); |
vera1 | 11:bda77916d2ea | 318 | setpoint = emg1.normalized; |
EvB | 13:acd120520e80 | 319 | |
vera1 | 11:bda77916d2ea | 320 | potvalue2 = pot2.read(); |
vera1 | 11:bda77916d2ea | 321 | setpoint2 = emg2.normalized; |
EvB | 13:acd120520e80 | 322 | */ |
EvB | 13:acd120520e80 | 323 | |
EvB | 13:acd120520e80 | 324 | Pos1 = motor1.getPosition()/16800*d*pi; // Position of link 1 [m] |
EvB | 13:acd120520e80 | 325 | Pos2 = motor2.getPosition()/16800*2*pi; // Position of link 2 [m] |
EvB | 13:acd120520e80 | 326 | |
EvB | 13:acd120520e80 | 327 | if (emg1.normalized >= EMG_threshold && emg2.normalized <= EMG_threshold) { // Positive direction |
EvB | 13:acd120520e80 | 328 | v_des = emg1.normalized; |
EvB | 13:acd120520e80 | 329 | } |
MMartens | 2:7c6391c8ca71 | 330 | |
EvB | 13:acd120520e80 | 331 | if (emg1.normalized >= EMG_threshold && emg2.normalized <= EMG_threshold) { // Negative direction |
EvB | 13:acd120520e80 | 332 | v_des = -emg2.normalized; |
EvB | 13:acd120520e80 | 333 | } |
EvB | 13:acd120520e80 | 334 | |
EvB | 13:acd120520e80 | 335 | //pc.printf("\r\nv_des in setpoint function= %f\r\n", v_des); |
EvB | 13:acd120520e80 | 336 | } |
EvB | 13:acd120520e80 | 337 | void PIDcalculation(float q1, float q2, float q3) // inputs: potvalue, motor#, setpoint |
MMartens | 1:f3fe6d2b7639 | 338 | { |
EvB | 13:acd120520e80 | 339 | |
MMartens | 1:f3fe6d2b7639 | 340 | //pc.printf("pos: %d, speed %f reference position = %.2f\r ",motor1.getPosition(), motor1.getSpeed(), setpoint); |
MMartens | 0:9167ae5d9927 | 341 | //motorpid = PID(potvalue - position, M1_KP, M1_KI, M1_KD, M1_TS, m1_err_int, m1_prev_err, m1_f_v1, m1_f_v2, M1_F_A1, M1_F_A2, M1_F_B0, M1_F_B1, M1_F_B2); |
MMartens | 2:7c6391c8ca71 | 342 | |
EvB | 13:acd120520e80 | 343 | |
EvB | 13:acd120520e80 | 344 | error1 = q1 - Pos1; // Position error of link 1 [m] |
EvB | 13:acd120520e80 | 345 | error2 = q2 - Pos2; // Position error of link 2 [m] |
EvB | 13:acd120520e80 | 346 | |
MMartens | 3:e888f52a46bc | 347 | changeError = (error1 - last_error)/0.001f; // derivative term |
MMartens | 3:e888f52a46bc | 348 | totalError += error1*0.001f; //accumalate errors to find integral term |
MMartens | 3:e888f52a46bc | 349 | pidTerm = (Kp * error1) + (Ki * totalError) + (Kd * changeError);//total gain |
MMartens | 3:e888f52a46bc | 350 | pidTerm = pidTerm; |
MMartens | 3:e888f52a46bc | 351 | if (pidTerm >= 1000) { |
MMartens | 3:e888f52a46bc | 352 | pidTerm = 1000; |
MMartens | 3:e888f52a46bc | 353 | } else if (pidTerm <= -1000) { |
MMartens | 3:e888f52a46bc | 354 | pidTerm = -1000; |
MMartens | 3:e888f52a46bc | 355 | } else { |
MMartens | 3:e888f52a46bc | 356 | pidTerm = pidTerm; |
MMartens | 3:e888f52a46bc | 357 | } |
MMartens | 3:e888f52a46bc | 358 | //constraining to appropriate value |
EvB | 13:acd120520e80 | 359 | if (pidTerm >= 0) { |
vera1 | 12:5be2001abe62 | 360 | dir1 = 0;// Forward motion |
MMartens | 1:f3fe6d2b7639 | 361 | } else { |
vera1 | 12:5be2001abe62 | 362 | dir1 = 1;//Reverse motion |
MMartens | 1:f3fe6d2b7639 | 363 | } |
MMartens | 3:e888f52a46bc | 364 | pidTerm_scaled = abs(pidTerm)/1000.0f; //make sure it's a positive value |
EvB | 13:acd120520e80 | 365 | if(pidTerm_scaled >= 0.55f) { |
MMartens | 3:e888f52a46bc | 366 | pidTerm_scaled = 0.55f; |
MMartens | 1:f3fe6d2b7639 | 367 | } |
EvB | 13:acd120520e80 | 368 | |
MMartens | 4:75f6e4845194 | 369 | changeError2 = (error2 - last_error2)/0.001f; // derivative term |
MMartens | 4:75f6e4845194 | 370 | totalError2 += error2*0.001f; //accumalate errors to find integral term |
MMartens | 4:75f6e4845194 | 371 | pidTerm2 = (Kp * error2) + (Ki * totalError2) + (Kd * changeError2);//total gain |
MMartens | 4:75f6e4845194 | 372 | pidTerm2 = pidTerm2; |
MMartens | 4:75f6e4845194 | 373 | if (pidTerm2 >= 1000) { |
MMartens | 4:75f6e4845194 | 374 | pidTerm2 = 1000; |
MMartens | 4:75f6e4845194 | 375 | } else if (pidTerm2 <= -1000) { |
MMartens | 4:75f6e4845194 | 376 | pidTerm2 = -1000; |
MMartens | 4:75f6e4845194 | 377 | } else { |
MMartens | 4:75f6e4845194 | 378 | pidTerm2 = pidTerm2; |
MMartens | 4:75f6e4845194 | 379 | } |
MMartens | 4:75f6e4845194 | 380 | //constraining to appropriate value |
EvB | 13:acd120520e80 | 381 | if (pidTerm2 >= 0) { |
MMartens | 4:75f6e4845194 | 382 | dir2 = 1;// Forward motion |
MMartens | 4:75f6e4845194 | 383 | } else { |
MMartens | 4:75f6e4845194 | 384 | dir2 = 0;//Reverse motion |
MMartens | 4:75f6e4845194 | 385 | } |
MMartens | 4:75f6e4845194 | 386 | pidTerm_scaled2 = abs(pidTerm2)/1000.0f; //make sure it's a positive value |
EvB | 13:acd120520e80 | 387 | if(pidTerm_scaled2 >= 0.55f) { |
MMartens | 4:75f6e4845194 | 388 | pidTerm_scaled2 = 0.55f; |
MMartens | 4:75f6e4845194 | 389 | } |
EvB | 13:acd120520e80 | 390 | |
MMartens | 1:f3fe6d2b7639 | 391 | last_error = error1; |
MMartens | 3:e888f52a46bc | 392 | speed1 = pidTerm_scaled+0.45f; |
vera1 | 12:5be2001abe62 | 393 | //speedservo1 = speed1; |
MMartens | 4:75f6e4845194 | 394 | last_error2 = error2; |
MMartens | 4:75f6e4845194 | 395 | speed2 = pidTerm_scaled2+0.45f; |
vera1 | 12:5be2001abe62 | 396 | //speedservo2 = speed2; |
MMartens | 0:9167ae5d9927 | 397 | } |
MMartens | 0:9167ae5d9927 | 398 | |
EvB | 13:acd120520e80 | 399 | // --- Motor movements --- |
EvB | 13:acd120520e80 | 400 | void r_movehorizontal() |
EvB | 13:acd120520e80 | 401 | { |
EvB | 13:acd120520e80 | 402 | setpointreadout(Vx_des); // Start with obtaining the position of the robot and the desired velocities |
EvB | 13:acd120520e80 | 403 | //pc.printf("\r\n Vx_des outside setpoint function = %f\r\n", Vx_des); |
EvB | 13:acd120520e80 | 404 | Jacobian(Vx_des, 0, 0); // Give the obtained end-effector velocities as input to the Jacobian function. Output of this function is necessary joint velocities and predicted joint positions |
EvB | 13:acd120520e80 | 405 | PIDcalculation(Q1, Q2, Q3); // Ensure smooth motion. Uses new position of joints calculated by Jacobian. This function then converts the position into appropriate PWM out values. |
EvB | 13:acd120520e80 | 406 | |
EvB | 13:acd120520e80 | 407 | } |
EvB | 13:acd120520e80 | 408 | |
EvB | 13:acd120520e80 | 409 | void r_movevertical() |
EvB | 13:acd120520e80 | 410 | { |
EvB | 13:acd120520e80 | 411 | setpointreadout(Vy_des); // Start with obtaining the position of the robot and the desired velocities |
EvB | 13:acd120520e80 | 412 | //pc.printf("\r\n Vy_des outside setpoint function = %f\r\n", Vy_des); |
EvB | 13:acd120520e80 | 413 | Jacobian(0, Vy_des, 0); // Give the obtained end-effector velocities as input to the Jacobian function. Output of this function is necessary joint velocities and predicted joint positions |
EvB | 13:acd120520e80 | 414 | PIDcalculation(Q1, Q2, Q3); // Ensure smooth motion. Uses new position of joints calculated by Jacobian. This function then converts the position into appropriate PWM out values. |
EvB | 13:acd120520e80 | 415 | |
EvB | 13:acd120520e80 | 416 | } |
EvB | 13:acd120520e80 | 417 | |
EvB | 13:acd120520e80 | 418 | void r_movebase() |
EvB | 13:acd120520e80 | 419 | { |
EvB | 13:acd120520e80 | 420 | |
EvB | 13:acd120520e80 | 421 | setpointreadout(Vz_des); // Start with obtaining the position of the robot and the desired velocities |
EvB | 13:acd120520e80 | 422 | //pc.printf("\r\n Vz_des outside setpoint function = %f\r\n", Vz_des); |
EvB | 13:acd120520e80 | 423 | Jacobian(0, 0, Vz_des); // Give the obtained end-effector velocities as input to the Jacobian function. Output of this function is necessary joint velocities and predicted joint positions |
EvB | 13:acd120520e80 | 424 | PIDcalculation(Q1, Q2, Q3); // Ensure smooth motion. Uses new position of joints calculated by Jacobian. This function then converts the position into appropriate PWM out values. |
EvB | 13:acd120520e80 | 425 | |
EvB | 13:acd120520e80 | 426 | } |
EvB | 13:acd120520e80 | 427 | //-------------------------------- |
EvB | 13:acd120520e80 | 428 | |
EvB | 13:acd120520e80 | 429 | |
vera1 | 8:9edf32e021a5 | 430 | void maintickerfunction() |
EvB | 13:acd120520e80 | 431 | { |
EvB | 13:acd120520e80 | 432 | count++; |
EvB | 13:acd120520e80 | 433 | if (go_switch) { |
EvB | 13:acd120520e80 | 434 | r_processStateSwitch(); |
EvB | 13:acd120520e80 | 435 | } |
EvB | 13:acd120520e80 | 436 | |
EvB | 13:acd120520e80 | 437 | if(go_EMG && count%2 == 0) { |
vera1 | 8:9edf32e021a5 | 438 | processEMG(); |
vera1 | 8:9edf32e021a5 | 439 | } |
EvB | 13:acd120520e80 | 440 | |
EvB | 13:acd120520e80 | 441 | if (go_move) { |
EvB | 13:acd120520e80 | 442 | switch(state) { |
EvB | 13:acd120520e80 | 443 | case R_HORIZONTAL: |
EvB | 13:acd120520e80 | 444 | r_movehorizontal(); |
EvB | 13:acd120520e80 | 445 | break; |
EvB | 13:acd120520e80 | 446 | case R_VERTICAL: |
EvB | 13:acd120520e80 | 447 | r_movevertical(); |
EvB | 13:acd120520e80 | 448 | break; |
EvB | 13:acd120520e80 | 449 | case R_BASE: |
EvB | 13:acd120520e80 | 450 | r_movebase(); |
EvB | 13:acd120520e80 | 451 | break; |
EvB | 13:acd120520e80 | 452 | } |
EvB | 13:acd120520e80 | 453 | } |
EvB | 13:acd120520e80 | 454 | |
EvB | 13:acd120520e80 | 455 | /*if(emg1.normalized >=0.2 && emg2.normalized >= 0.2) // PIDcalculation should not happen. |
EvB | 13:acd120520e80 | 456 | { |
vera1 | 11:bda77916d2ea | 457 | go_PID = false; |
vera1 | 11:bda77916d2ea | 458 | } |
vera1 | 11:bda77916d2ea | 459 | else{go_PID = true;}*/ |
EvB | 13:acd120520e80 | 460 | |
EvB | 13:acd120520e80 | 461 | |
vera1 | 8:9edf32e021a5 | 462 | } |
vera1 | 8:9edf32e021a5 | 463 | |
MMartens | 1:f3fe6d2b7639 | 464 | int main() |
EvB | 13:acd120520e80 | 465 | { |
EvB | 13:acd120520e80 | 466 | pc.baud(9600); |
EvB | 13:acd120520e80 | 467 | go_EMG = true; // Setting ticker variables |
vera1 | 8:9edf32e021a5 | 468 | go_calibration = true; // Setting the timeout variable |
vera1 | 11:bda77916d2ea | 469 | go_PID = true; |
vera1 | 11:bda77916d2ea | 470 | go_switch = false; |
EvB | 13:acd120520e80 | 471 | go_move = true; |
MMartens | 1:f3fe6d2b7639 | 472 | speed1.period(PwmPeriod); |
MMartens | 4:75f6e4845194 | 473 | speed2.period(PwmPeriod); |
EvB | 13:acd120520e80 | 474 | |
vera1 | 8:9edf32e021a5 | 475 | calibrationgo.attach(&calibrationGO, 5.0); // Attach calibration timeout to calibration function |
vera1 | 8:9edf32e021a5 | 476 | mainticker.attach(&calibrationEMG, 0.001f); // Attach ticker to the calibration function |
EvB | 13:acd120520e80 | 477 | wait(5.0f); |
EvB | 13:acd120520e80 | 478 | mainticker.attach(&maintickerfunction,0.001f); |
EvB | 13:acd120520e80 | 479 | |
MMartens | 1:f3fe6d2b7639 | 480 | while(true) { |
EvB | 13:acd120520e80 | 481 | |
vera1 | 11:bda77916d2ea | 482 | ledstatedef = 1; |
vera1 | 11:bda77916d2ea | 483 | if(emg1.normalized >= 0.7 && emg2.normalized >= 0.7) { |
vera1 | 11:bda77916d2ea | 484 | ledstateswitch = 1; |
vera1 | 11:bda77916d2ea | 485 | ledstatedef = 0; |
vera1 | 11:bda77916d2ea | 486 | go_switch = true; |
EvB | 13:acd120520e80 | 487 | go_move = false; |
EvB | 13:acd120520e80 | 488 | |
vera1 | 11:bda77916d2ea | 489 | } |
EvB | 13:acd120520e80 | 490 | |
MMartens | 3:e888f52a46bc | 491 | |
vera1 | 11:bda77916d2ea | 492 | |
EvB | 13:acd120520e80 | 493 | if(count == 100) { |
MMartens | 3:e888f52a46bc | 494 | count = 0; |
vera1 | 11:bda77916d2ea | 495 | pc.printf("emg1 = %f, emg2 = %f\r\n", emg1.normalized, emg2.normalized); |
vera1 | 11:bda77916d2ea | 496 | //pc.printf("Angle = %f, pidTerm = %f ,PID_scaled = %f, Error = %f, setpoint = %f\r\n", angle, pidTerm ,pidTerm_scaled, error1, setpoint); |
vera1 | 11:bda77916d2ea | 497 | //pc.printf("Angle 2 = %f, pidTerm 2 = %f ,PID_scaled 2 = %f, Error 2 = %f, setpoint 2 = %f\r\n", angle2, pidTerm2 ,pidTerm_scaled2, error2,setpoint2); |
MMartens | 3:e888f52a46bc | 498 | } |
EvB | 13:acd120520e80 | 499 | |
EvB | 13:acd120520e80 | 500 | |
EvB | 13:acd120520e80 | 501 | wait(0.001f); |
vera1 | 6:fc46581fe3e0 | 502 | } |
MMartens | 1:f3fe6d2b7639 | 503 | |
MMartens | 0:9167ae5d9927 | 504 | } |
MMartens | 0:9167ae5d9927 | 505 | |
MMartens | 0:9167ae5d9927 | 506 |