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