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