New reference frame: y=0 is now at table height.
Dependencies: HIDScope MODSERIAL QEI biquadFilter mbed
Fork of prog_forwardkin_feedback_copy by
main.cpp@44:43f200e04903, 2016-11-05 (annotated)
- Committer:
- GerhardBerman
- Date:
- Sat Nov 05 16:00:26 2016 +0000
- Revision:
- 44:43f200e04903
- Parent:
- 43:2b2e0bff0b39
Final version as used in demo, script is fully cleaned up.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
GerhardBerman | 0:43160ef59f9f | 1 | #include "mbed.h" |
GerhardBerman | 0:43160ef59f9f | 2 | #include <math.h> |
GerhardBerman | 0:43160ef59f9f | 3 | #include "MODSERIAL.h" |
GerhardBerman | 0:43160ef59f9f | 4 | #include "QEI.h" |
GerhardBerman | 0:43160ef59f9f | 5 | #include "HIDScope.h" |
GerhardBerman | 0:43160ef59f9f | 6 | #include "BiQuad.h" |
GerhardBerman | 0:43160ef59f9f | 7 | |
GerhardBerman | 17:91d20d362e72 | 8 | /* |
GerhardBerman | 17:91d20d362e72 | 9 | THINGS TO CONSIDER |
GerhardBerman | 44:43f200e04903 | 10 | - Motor action of motor 1 is inverted because it is mounted |
GerhardBerman | 17:91d20d362e72 | 11 | opposite to motor 2 in the tower. Check if the clockwise directions of the |
GerhardBerman | 17:91d20d362e72 | 12 | motors correspond to the positive q1, q2-directions (both counterclockwise) |
GerhardBerman | 17:91d20d362e72 | 13 | in the original IK-sketch. |
GerhardBerman | 44:43f200e04903 | 14 | - Arms should be placed manually into reference position before resetting board. |
GerhardBerman | 17:91d20d362e72 | 15 | */ |
GerhardBerman | 17:91d20d362e72 | 16 | |
GerhardBerman | 0:43160ef59f9f | 17 | //set pins |
GerhardBerman | 44:43f200e04903 | 18 | DigitalIn encoder1A (D13); //Channel A from Encoder 1 |
GerhardBerman | 44:43f200e04903 | 19 | DigitalIn encoder1B (D12); //Channel B from Encoder 1 |
GerhardBerman | 44:43f200e04903 | 20 | DigitalIn encoder2A (D11); //Channel A from Encoder 2 |
GerhardBerman | 44:43f200e04903 | 21 | DigitalIn encoder2B (D10); //Channel B from Encoder 2 |
GerhardBerman | 44:43f200e04903 | 22 | AnalogIn emg0( A0 ); |
GerhardBerman | 44:43f200e04903 | 23 | AnalogIn emg1( A1 ); |
GerhardBerman | 44:43f200e04903 | 24 | DigitalIn button1(D3); |
GerhardBerman | 44:43f200e04903 | 25 | DigitalIn button2(D9); |
GerhardBerman | 44:43f200e04903 | 26 | |
GerhardBerman | 0:43160ef59f9f | 27 | DigitalOut motor1DirectionPin(D7); |
GerhardBerman | 0:43160ef59f9f | 28 | PwmOut motor1MagnitudePin(D6); |
GerhardBerman | 7:2f74dfd1d411 | 29 | DigitalOut motor2DirectionPin(D4); |
GerhardBerman | 7:2f74dfd1d411 | 30 | PwmOut motor2MagnitudePin(D5); |
GerhardBerman | 41:68b170829965 | 31 | DigitalOut ledGrn(LED_GREEN); |
GerhardBerman | 41:68b170829965 | 32 | DigitalOut ledRed(LED_RED); |
GerhardBerman | 41:68b170829965 | 33 | DigitalOut ledBlue(LED_BLUE); |
GerhardBerman | 33:b09608fa69e9 | 34 | |
GerhardBerman | 7:2f74dfd1d411 | 35 | //library settings |
GerhardBerman | 0:43160ef59f9f | 36 | Serial pc(USBTX,USBRX); |
GerhardBerman | 41:68b170829965 | 37 | HIDScope scope(6); |
GerhardBerman | 0:43160ef59f9f | 38 | |
GerhardBerman | 44:43f200e04903 | 39 | //go-Ticker settings |
GerhardBerman | 44:43f200e04903 | 40 | Ticker MeasureTicker; |
GerhardBerman | 44:43f200e04903 | 41 | volatile bool MeasureTicker_go=false; |
GerhardBerman | 44:43f200e04903 | 42 | void MeasureTicker_act(){MeasureTicker_go=true;}; // Activates go-flag |
GerhardBerman | 44:43f200e04903 | 43 | |
GerhardBerman | 44:43f200e04903 | 44 | //constant values |
GerhardBerman | 3:8caef4872b0c | 45 | const float PI = 3.141592653589793; |
GerhardBerman | 44:43f200e04903 | 46 | const int cw = 0; //values for cw and ccw are inverted! cw=0 and ccw=1 |
GerhardBerman | 3:8caef4872b0c | 47 | const int ccw = 1; |
GerhardBerman | 44:43f200e04903 | 48 | double threshold_l=0.09; //left arm EMG threshold |
GerhardBerman | 44:43f200e04903 | 49 | double threshold_r = 0.08; //right arm EMG threshold |
GerhardBerman | 44:43f200e04903 | 50 | float EMGgain = 1.0; |
GerhardBerman | 0:43160ef59f9f | 51 | |
GerhardBerman | 44:43f200e04903 | 52 | //set lengths |
GerhardBerman | 44:43f200e04903 | 53 | //float L0 = 0.232; //height of motor axes above table surface |
GerhardBerman | 44:43f200e04903 | 54 | float L1 = 0.45; //length of proximal arm |
GerhardBerman | 44:43f200e04903 | 55 | float L2 = 0.35; //length of distal arm |
GerhardBerman | 44:43f200e04903 | 56 | float TowerHeight = 0.232; //height of motor axes above table surface |
GerhardBerman | 44:43f200e04903 | 57 | float StampHeight = 0.056; // height of end effector |
GerhardBerman | 44:43f200e04903 | 58 | float y_stampup = 0.1; //height stamp while not stamping: 10cm above table surface |
GerhardBerman | 44:43f200e04903 | 59 | float y_stampdown = -0.04; //height stamp while stamping: at table surface |
GerhardBerman | 34:96bcbddc7d2d | 60 | |
GerhardBerman | 44:43f200e04903 | 61 | //float dy_stampdown = 2.0; //0.05; //5 cm movement downward to stamp |
GerhardBerman | 44:43f200e04903 | 62 | float MotorGain = 8.4; // rad/s for PWM, is max motor speed |
GerhardBerman | 44:43f200e04903 | 63 | float MotorMaxSpeed = 0.1; //define a maximum PWM speed for the motor |
GerhardBerman | 44:43f200e04903 | 64 | float t_sample = 0.002; //seconds |
GerhardBerman | 44:43f200e04903 | 65 | const float maxStampDistance = 0.7; |
GerhardBerman | 44:43f200e04903 | 66 | const float minStampDistance = 0.3; |
GerhardBerman | 44:43f200e04903 | 67 | float Kp = 4.0; //proportional controller constant |
GerhardBerman | 44:43f200e04903 | 68 | float Ki = 0.04; //integrative controller constant |
GerhardBerman | 44:43f200e04903 | 69 | float Kd = 0.02; //derivative controller constant |
GerhardBerman | 44:43f200e04903 | 70 | float N = 25; //PIDF filter constant |
GerhardBerman | 44:43f200e04903 | 71 | //(Higher N is faster derivative action but more sensitive to noise) |
GerhardBerman | 44:43f200e04903 | 72 | |
GerhardBerman | 44:43f200e04903 | 73 | //set initial conditions for inputs and positions |
GerhardBerman | 44:43f200e04903 | 74 | float biceps_l = 0, biceps_r = 0; |
GerhardBerman | 44:43f200e04903 | 75 | double envelopeL = 0, envelopeR = 0; |
GerhardBerman | 44:43f200e04903 | 76 | int T=0; //EMG 'switch' variable |
GerhardBerman | 44:43f200e04903 | 77 | float ReferencePosition_x = 0.35; //starting position for x reference position |
GerhardBerman | 44:43f200e04903 | 78 | float ReferencePosition_y = L1 + TowerHeight - StampHeight; //starting position for y reference position |
GerhardBerman | 44:43f200e04903 | 79 | float ReferencePosition_xnew = 0.35; |
GerhardBerman | 39:cc7754330c26 | 80 | float ReferencePosition_ynew = L1 + TowerHeight - StampHeight; |
GerhardBerman | 19:cba54636bd62 | 81 | float Position_x = 0.0; |
GerhardBerman | 19:cba54636bd62 | 82 | float Position_y = 0.0; |
GerhardBerman | 44:43f200e04903 | 83 | |
GerhardBerman | 44:43f200e04903 | 84 | //set initial conditions for angles, errors and motor values |
GerhardBerman | 44:43f200e04903 | 85 | float q1 = 0,q2 = PI/2; |
GerhardBerman | 44:43f200e04903 | 86 | float q1_ref = 0, q2_ref = 0; |
GerhardBerman | 44:43f200e04903 | 87 | float q1start = 0; |
GerhardBerman | 39:cc7754330c26 | 88 | float q12start = PI/2; |
GerhardBerman | 44:43f200e04903 | 89 | float q1Encoder = 0, q12Encoder = 0; |
GerhardBerman | 39:cc7754330c26 | 90 | float q12Out = 0; |
GerhardBerman | 19:cba54636bd62 | 91 | |
GerhardBerman | 44:43f200e04903 | 92 | float q1_error_prev = 0, q2_error_prev = 0; |
GerhardBerman | 44:43f200e04903 | 93 | float DerTotalError1 = 0, DerTotalError2 = 0; |
GerhardBerman | 44:43f200e04903 | 94 | float q1IntError = 0, q2IntError = 0; |
GerhardBerman | 44:43f200e04903 | 95 | float TotalError1_prev = 0, TotalError2_prev = 0; |
GerhardBerman | 44:43f200e04903 | 96 | float TotalError1= 0, TotalError2= 0; |
GerhardBerman | 44:43f200e04903 | 97 | //float TotalErrorMin= 0; |
GerhardBerman | 26:bb7e14f59ddd | 98 | |
GerhardBerman | 44:43f200e04903 | 99 | float motorValue1 = 0.0, motorValue2 = 0.0; |
GerhardBerman | 44:43f200e04903 | 100 | int counts1 = 0, counts2 = 0; |
GerhardBerman | 44:43f200e04903 | 101 | int counts1Prev = 0, counts2Prev = 0; |
GerhardBerman | 26:bb7e14f59ddd | 102 | |
GerhardBerman | 44:43f200e04903 | 103 | //set reference angle boundaries |
GerhardBerman | 44:43f200e04903 | 104 | float q1_refOutNew = 0, q2_refOutNew = 0; |
GerhardBerman | 44:43f200e04903 | 105 | float q1_refOutMin = 0; //Physical min angle 0.00 radians |
GerhardBerman | 44:43f200e04903 | 106 | float q1_refOutMax = 1.37; //Physical max angle 1.47 radians - 0.1 rad |
GerhardBerman | 44:43f200e04903 | 107 | float q2_refOutMin = 0.91; //Physical min angle 0.81 radians + 0.1 rad |
GerhardBerman | 44:43f200e04903 | 108 | float q2_refOutMax = 2.07; //Physical max angle 2.17 radians - 0.1 rad |
GerhardBerman | 0:43160ef59f9f | 109 | |
GerhardBerman | 44:43f200e04903 | 110 | //set BiQuad filters/filter chains |
GerhardBerman | 44:43f200e04903 | 111 | |
GerhardBerman | 44:43f200e04903 | 112 | BiQuad pidf; //PID Filter |
GerhardBerman | 40:9ecaab27acde | 113 | |
GerhardBerman | 44:43f200e04903 | 114 | BiQuadChain bcq1R; //Right EMG filter chain 1: notch filter+highpass |
GerhardBerman | 44:43f200e04903 | 115 | BiQuadChain bcq2R; //Right EMG filter chain 2: lowpass |
GerhardBerman | 44:43f200e04903 | 116 | BiQuad bq1R(9.9110e-01,-1.6036e+00,9.9110e-01,-1.6036e+00,9.8221e-01); // Notch filter wo=50; bw=wo/35 |
GerhardBerman | 44:43f200e04903 | 117 | BiQuad bq2R(9.1497e-01,-1.8299e+00,9.1497e-01,-1.8227e+00,8.3718e-01); // High pass Butterworth filter 2nd order, Fc=10; |
GerhardBerman | 44:43f200e04903 | 118 | BiQuad bq3R(1.3487e-03,2.6974e-03,1.3487e-03,-1.8935e+00,8.9886e-01); // Low pass Butterworth filter 2nd order, Fc = 8; |
GerhardBerman | 41:68b170829965 | 119 | |
GerhardBerman | 44:43f200e04903 | 120 | BiQuadChain bcq1L; //Left EMG filter chain 1: notch filter+highpass |
GerhardBerman | 44:43f200e04903 | 121 | BiQuadChain bcq2L; //Left EMG filter chain 2: lowpass |
GerhardBerman | 44:43f200e04903 | 122 | BiQuad bq1L(9.9110e-01,-1.6036e+00,9.9110e-01,-1.6036e+00,9.8221e-01); // Notch filter wo=50; bw=wo/35 |
GerhardBerman | 44:43f200e04903 | 123 | BiQuad bq2L(9.1497e-01,-1.8299e+00,9.1497e-01,-1.8227e+00,8.3718e-01); // High pass Butterworth filter 2nd order, Fc=10; |
GerhardBerman | 44:43f200e04903 | 124 | BiQuad bq3L(1.3487e-03,2.6974e-03,1.3487e-03,-1.8935e+00,8.9886e-01); // Low pass Butterworth filter 2nd order, Fc = 8; |
GerhardBerman | 44:43f200e04903 | 125 | // In the following: R is used for right arm EMG, L is used for left arm EMG |
GerhardBerman | 3:8caef4872b0c | 126 | |
GerhardBerman | 3:8caef4872b0c | 127 | //define encoder counts and degrees |
GerhardBerman | 44:43f200e04903 | 128 | QEI Encoder1(D12, D13, NC, 32); // turns on encoder |
GerhardBerman | 44:43f200e04903 | 129 | QEI Encoder2(D10, D11, NC, 32); // turns on encoder |
GerhardBerman | 44:43f200e04903 | 130 | const int counts_per_revolution = 4200; //counts per motor axis revolution |
GerhardBerman | 44:43f200e04903 | 131 | const int inverse_gear_ratio = 131; |
GerhardBerman | 44:43f200e04903 | 132 | const float resolution = counts_per_revolution/(2*PI/inverse_gear_ratio); //87567.0496892 counts per radian, encoder axis |
GerhardBerman | 14:725a608b6709 | 133 | |
GerhardBerman | 44:43f200e04903 | 134 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 135 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 3:8caef4872b0c | 136 | |
GerhardBerman | 41:68b170829965 | 137 | void FilteredSample(int &Tout, double &envelopeLout, double &envelopeRout) |
GerhardBerman | 41:68b170829965 | 138 | { |
GerhardBerman | 44:43f200e04903 | 139 | //This function reads EMG, filters it and generates a T-switch value which specifies the movement of the robot |
GerhardBerman | 44:43f200e04903 | 140 | |
GerhardBerman | 41:68b170829965 | 141 | double inLout = emg0.read(); |
GerhardBerman | 41:68b170829965 | 142 | double inRout = emg1.read(); |
GerhardBerman | 41:68b170829965 | 143 | |
GerhardBerman | 41:68b170829965 | 144 | double outRfilter1 = bcq1R.step(inRout); |
GerhardBerman | 41:68b170829965 | 145 | double outRrect= fabs(outRfilter1); |
GerhardBerman | 41:68b170829965 | 146 | envelopeRout = bcq2R.step(outRrect); |
GerhardBerman | 41:68b170829965 | 147 | |
GerhardBerman | 41:68b170829965 | 148 | double outLfilter1 = bcq1L.step(inLout); |
GerhardBerman | 41:68b170829965 | 149 | double outLrect = fabs(outLfilter1); |
GerhardBerman | 41:68b170829965 | 150 | envelopeLout = bcq2L.step(outLrect); |
GerhardBerman | 41:68b170829965 | 151 | |
GerhardBerman | 41:68b170829965 | 152 | double biceps_l = (double) envelopeLout * EMGgain; //emg0.read(); //velocity or reference position change, EMG with a gain |
GerhardBerman | 41:68b170829965 | 153 | double biceps_r = (double) envelopeRout * EMGgain; //emg1.read(); |
GerhardBerman | 41:68b170829965 | 154 | if (biceps_l > threshold_l && biceps_r > threshold_r){ |
GerhardBerman | 41:68b170829965 | 155 | //both arms activated: stamp moves down |
GerhardBerman | 41:68b170829965 | 156 | Tout = -2; |
GerhardBerman | 41:68b170829965 | 157 | } |
GerhardBerman | 41:68b170829965 | 158 | else if (biceps_l > threshold_l && biceps_r <= threshold_r){ |
GerhardBerman | 41:68b170829965 | 159 | //arm 1 activated, move left |
GerhardBerman | 41:68b170829965 | 160 | Tout = -1; |
GerhardBerman | 41:68b170829965 | 161 | } |
GerhardBerman | 41:68b170829965 | 162 | else if (biceps_l <= threshold_l && biceps_r > threshold_r){ |
GerhardBerman | 41:68b170829965 | 163 | //arm 1 activated, move right |
GerhardBerman | 41:68b170829965 | 164 | Tout = 1; |
GerhardBerman | 41:68b170829965 | 165 | } |
GerhardBerman | 41:68b170829965 | 166 | else{ |
GerhardBerman | 41:68b170829965 | 167 | //wait(0.2); |
GerhardBerman | 41:68b170829965 | 168 | Tout = 0; |
GerhardBerman | 44:43f200e04903 | 169 | } |
GerhardBerman | 41:68b170829965 | 170 | } |
GerhardBerman | 41:68b170829965 | 171 | |
GerhardBerman | 44:43f200e04903 | 172 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 173 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 174 | |
GerhardBerman | 44:43f200e04903 | 175 | void GetReferenceKinematics1(float &q1Out, float &q2Out, float &q1_refOut, float &q2_refOut) |
GerhardBerman | 44:43f200e04903 | 176 | { |
GerhardBerman | 44:43f200e04903 | 177 | //This function reads current position from encoder, calculates reference position from T-switch value, |
GerhardBerman | 44:43f200e04903 | 178 | //converts reference position to reference angles and checks boundaries |
GerhardBerman | 7:2f74dfd1d411 | 179 | |
GerhardBerman | 19:cba54636bd62 | 180 | //get joint positions q feedback from encoder |
GerhardBerman | 44:43f200e04903 | 181 | float Encoder1Position = counts1/resolution; //angular position of encoder in radians |
GerhardBerman | 44:43f200e04903 | 182 | float Encoder2Position = -1*counts2/resolution; //NEGATIVE due to opposite build up in tower |
GerhardBerman | 39:cc7754330c26 | 183 | |
GerhardBerman | 39:cc7754330c26 | 184 | q1Encoder = Encoder1Position*inverse_gear_ratio; |
GerhardBerman | 39:cc7754330c26 | 185 | q12Encoder = Encoder2Position*inverse_gear_ratio; |
GerhardBerman | 44:43f200e04903 | 186 | q1Out = q1start + q1Encoder; //angular position of motor axis in radians |
GerhardBerman | 44:43f200e04903 | 187 | q12Out = q12start + q12Encoder; //encoder 2 gives sum of q1 and q2! |
GerhardBerman | 39:cc7754330c26 | 188 | q2Out = q12Out - q1Out; |
GerhardBerman | 44:43f200e04903 | 189 | //float q1deg = q1Out*360/2/PI; //angle in degrees |
GerhardBerman | 44:43f200e04903 | 190 | //float q2deg = q2Out*360/2/PI; //angle in degrees |
GerhardBerman | 7:2f74dfd1d411 | 191 | |
GerhardBerman | 44:43f200e04903 | 192 | //get end effector position with trigonometry |
GerhardBerman | 19:cba54636bd62 | 193 | Position_x = (L1*sin(q1) + L2*sin(q1+q2)); |
GerhardBerman | 28:6d8c6fe79394 | 194 | Position_y = (L1*cos(q1) + L2*cos(q1+q2)) + TowerHeight - StampHeight; |
GerhardBerman | 29:caf3dd699617 | 195 | |
GerhardBerman | 44:43f200e04903 | 196 | //get reference position from EMG based T-switch values |
GerhardBerman | 41:68b170829965 | 197 | if (T == -2){ |
GerhardBerman | 44:43f200e04903 | 198 | //both EMGs active: stamp moves down |
GerhardBerman | 19:cba54636bd62 | 199 | ReferencePosition_xnew = ReferencePosition_x; |
GerhardBerman | 44:43f200e04903 | 200 | ReferencePosition_ynew = ReferencePosition_y - 0.015; |
GerhardBerman | 18:d2cfd07ae88a | 201 | } |
GerhardBerman | 41:68b170829965 | 202 | else if (T==-1){ |
GerhardBerman | 44:43f200e04903 | 203 | //left EMG active, move stamp left |
GerhardBerman | 44:43f200e04903 | 204 | ReferencePosition_xnew = ReferencePosition_x - 0.0009; |
GerhardBerman | 44:43f200e04903 | 205 | ReferencePosition_ynew = y_stampup; |
GerhardBerman | 8:935abf8ecc27 | 206 | } |
GerhardBerman | 41:68b170829965 | 207 | else if (T==1){ |
GerhardBerman | 44:43f200e04903 | 208 | //right EMG active, move stamp right |
GerhardBerman | 44:43f200e04903 | 209 | ReferencePosition_xnew = ReferencePosition_x + 0.0009; |
GerhardBerman | 44:43f200e04903 | 210 | ReferencePosition_ynew = y_stampup; |
GerhardBerman | 44:43f200e04903 | 211 | } |
GerhardBerman | 44:43f200e04903 | 212 | else{ //T==0 |
GerhardBerman | 44:43f200e04903 | 213 | //no EMG active, no x-movement, y-position restored to non-stamping position |
GerhardBerman | 44:43f200e04903 | 214 | ReferencePosition_ynew = y_stampup; |
GerhardBerman | 8:935abf8ecc27 | 215 | } |
GerhardBerman | 19:cba54636bd62 | 216 | |
GerhardBerman | 44:43f200e04903 | 217 | //check reference position boundaries |
GerhardBerman | 39:cc7754330c26 | 218 | if (ReferencePosition_xnew > maxStampDistance){ |
GerhardBerman | 44:43f200e04903 | 219 | //target too far to be reached |
GerhardBerman | 44:43f200e04903 | 220 | ReferencePosition_x = maxStampDistance; |
GerhardBerman | 39:cc7754330c26 | 221 | ReferencePosition_y = y_stampup; |
GerhardBerman | 44:43f200e04903 | 222 | //pc.printf("Target too far! \r\n"); |
GerhardBerman | 39:cc7754330c26 | 223 | } |
GerhardBerman | 39:cc7754330c26 | 224 | else if (ReferencePosition_xnew < minStampDistance){ |
GerhardBerman | 44:43f200e04903 | 225 | //target too close |
GerhardBerman | 44:43f200e04903 | 226 | ReferencePosition_x = minStampDistance; |
GerhardBerman | 39:cc7754330c26 | 227 | ReferencePosition_y = y_stampup; |
GerhardBerman | 44:43f200e04903 | 228 | //pc.printf("Target too close! \r\n"); |
GerhardBerman | 39:cc7754330c26 | 229 | } |
GerhardBerman | 41:68b170829965 | 230 | else if (ReferencePosition_ynew < y_stampdown){ |
GerhardBerman | 44:43f200e04903 | 231 | //target under table surface |
GerhardBerman | 44:43f200e04903 | 232 | ReferencePosition_x = ReferencePosition_xnew; |
GerhardBerman | 41:68b170829965 | 233 | ReferencePosition_y = y_stampdown; |
GerhardBerman | 44:43f200e04903 | 234 | //pc.printf("Target too low! \r\n"); |
GerhardBerman | 41:68b170829965 | 235 | } |
GerhardBerman | 39:cc7754330c26 | 236 | else { |
GerhardBerman | 44:43f200e04903 | 237 | //target within reach |
GerhardBerman | 39:cc7754330c26 | 238 | ReferencePosition_x = ReferencePosition_xnew; |
GerhardBerman | 39:cc7754330c26 | 239 | ReferencePosition_y = ReferencePosition_ynew; |
GerhardBerman | 39:cc7754330c26 | 240 | } |
GerhardBerman | 39:cc7754330c26 | 241 | |
GerhardBerman | 44:43f200e04903 | 242 | //calculate reference joint angles for the new reference position |
GerhardBerman | 28:6d8c6fe79394 | 243 | float PointPositionArm2_x = ReferencePosition_x; |
GerhardBerman | 28:6d8c6fe79394 | 244 | float PointPositionArm2_y = ReferencePosition_y - TowerHeight + StampHeight; |
GerhardBerman | 28:6d8c6fe79394 | 245 | float PointVectorArm2 = sqrt(pow(PointPositionArm2_x,2)+pow(PointPositionArm2_y,2)); |
GerhardBerman | 19:cba54636bd62 | 246 | |
GerhardBerman | 28:6d8c6fe79394 | 247 | float alpha = atan(PointPositionArm2_y/PointPositionArm2_x); |
GerhardBerman | 28:6d8c6fe79394 | 248 | float beta = acos((L2*L2-L1*L1-pow(PointVectorArm2,2))/(-2*L1*PointVectorArm2)); |
GerhardBerman | 19:cba54636bd62 | 249 | q1_refOutNew = PI/2 - (alpha+beta); |
GerhardBerman | 28:6d8c6fe79394 | 250 | q2_refOutNew = PI - asin(PointVectorArm2*sin(beta)/L2); |
GerhardBerman | 19:cba54636bd62 | 251 | |
GerhardBerman | 44:43f200e04903 | 252 | //check reference angle boundaries |
GerhardBerman | 39:cc7754330c26 | 253 | if (q1_refOutNew < q1_refOutMin){ |
GerhardBerman | 44:43f200e04903 | 254 | //new q1_ref too small |
GerhardBerman | 39:cc7754330c26 | 255 | q1_refOut = q1_refOutMin; |
GerhardBerman | 44:43f200e04903 | 256 | //pc.printf("\r\n Under q1 angle boundaries\r\n"); |
GerhardBerman | 39:cc7754330c26 | 257 | } |
GerhardBerman | 39:cc7754330c26 | 258 | else if (q1_refOutNew > q1_refOutMax){ |
GerhardBerman | 44:43f200e04903 | 259 | //new q1_ref too large |
GerhardBerman | 39:cc7754330c26 | 260 | q1_refOut = q1_refOutMax; |
GerhardBerman | 44:43f200e04903 | 261 | //pc.printf("\r\n Above q1 angle boundaries\r\n"); |
GerhardBerman | 19:cba54636bd62 | 262 | } |
GerhardBerman | 19:cba54636bd62 | 263 | else { |
GerhardBerman | 44:43f200e04903 | 264 | //new q1_ref within reach |
GerhardBerman | 39:cc7754330c26 | 265 | q1_refOut = q1_refOutNew; |
GerhardBerman | 19:cba54636bd62 | 266 | } |
GerhardBerman | 39:cc7754330c26 | 267 | |
GerhardBerman | 39:cc7754330c26 | 268 | if (q2_refOutNew < q2_refOutMin){ |
GerhardBerman | 44:43f200e04903 | 269 | //new q2_ref too small |
GerhardBerman | 39:cc7754330c26 | 270 | q2_refOut = q2_refOutMin; |
GerhardBerman | 39:cc7754330c26 | 271 | pc.printf("\r\n Under q2 angle boundaries"); |
GerhardBerman | 39:cc7754330c26 | 272 | } |
GerhardBerman | 39:cc7754330c26 | 273 | else if (q2_refOutNew > q2_refOutMax){ |
GerhardBerman | 44:43f200e04903 | 274 | //new q2_ref too large |
GerhardBerman | 39:cc7754330c26 | 275 | q2_refOut = q2_refOutMax; |
GerhardBerman | 39:cc7754330c26 | 276 | pc.printf("\r\n Above q2 angle boundaries"); |
GerhardBerman | 19:cba54636bd62 | 277 | } |
GerhardBerman | 19:cba54636bd62 | 278 | else { |
GerhardBerman | 44:43f200e04903 | 279 | //new q2_ref within reach |
GerhardBerman | 39:cc7754330c26 | 280 | q2_refOut = q2_refOutNew; |
GerhardBerman | 39:cc7754330c26 | 281 | } |
GerhardBerman | 41:68b170829965 | 282 | |
GerhardBerman | 41:68b170829965 | 283 | scope.set(0, ReferencePosition_xnew); |
GerhardBerman | 41:68b170829965 | 284 | scope.set(1, ReferencePosition_ynew); |
GerhardBerman | 41:68b170829965 | 285 | scope.set(2, envelopeL); |
GerhardBerman | 41:68b170829965 | 286 | scope.set(3, envelopeR); |
GerhardBerman | 41:68b170829965 | 287 | scope.set(4, T); |
GerhardBerman | 41:68b170829965 | 288 | scope.send(); |
GerhardBerman | 44:43f200e04903 | 289 | } |
GerhardBerman | 44:43f200e04903 | 290 | |
GerhardBerman | 44:43f200e04903 | 291 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 292 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 293 | |
GerhardBerman | 44:43f200e04903 | 294 | void FeedbackControl1(float q1_ref, float q2_ref, float q1, float q2, float &motorValue1Out, float &motorValue2Out) |
GerhardBerman | 44:43f200e04903 | 295 | { |
GerhardBerman | 44:43f200e04903 | 296 | //This function calculates the error between angles and refernce angles, and provides motor values via a PIDF controller |
GerhardBerman | 12:05e5964b69a4 | 297 | |
GerhardBerman | 44:43f200e04903 | 298 | //calculate error values |
GerhardBerman | 44:43f200e04903 | 299 | float q1_error = q1_ref - q1; // proportional angular error in radians |
GerhardBerman | 44:43f200e04903 | 300 | float q2_error = q2_ref - q2; // proportional angular error in radians |
GerhardBerman | 29:caf3dd699617 | 301 | |
GerhardBerman | 44:43f200e04903 | 302 | //PIDF total error output |
GerhardBerman | 40:9ecaab27acde | 303 | float TotalError1 = pidf.step(q1_error); |
GerhardBerman | 40:9ecaab27acde | 304 | float TotalError2 = pidf.step(q2_error); |
GerhardBerman | 40:9ecaab27acde | 305 | |
GerhardBerman | 44:43f200e04903 | 306 | //calculate motor values from the total errors |
GerhardBerman | 44:43f200e04903 | 307 | motorValue1Out = TotalError1/MotorGain; |
11i | 21:dd51d78c0732 | 308 | motorValue2Out = TotalError2/MotorGain; |
11i | 21:dd51d78c0732 | 309 | |
GerhardBerman | 44:43f200e04903 | 310 | //prepare for next ticker cycle |
GerhardBerman | 19:cba54636bd62 | 311 | q1_error_prev = q1_error; |
GerhardBerman | 19:cba54636bd62 | 312 | q2_error_prev = q2_error; |
GerhardBerman | 25:596255732b65 | 313 | TotalError1_prev = TotalError1; |
GerhardBerman | 33:b09608fa69e9 | 314 | TotalError2_prev = TotalError2; |
GerhardBerman | 3:8caef4872b0c | 315 | } |
GerhardBerman | 3:8caef4872b0c | 316 | |
GerhardBerman | 44:43f200e04903 | 317 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 318 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 319 | |
GerhardBerman | 9:e4c34f5665a0 | 320 | void SetMotor1(float motorValue1, float motorValue2) |
GerhardBerman | 3:8caef4872b0c | 321 | { |
GerhardBerman | 44:43f200e04903 | 322 | //This function sets the PWM and direction bits for the motors. |
GerhardBerman | 44:43f200e04903 | 323 | //motorValues outside range are truncated to within range. |
GerhardBerman | 44:43f200e04903 | 324 | |
GerhardBerman | 9:e4c34f5665a0 | 325 | //control motor 1 |
GerhardBerman | 44:43f200e04903 | 326 | if (motorValue1 >=0){ |
GerhardBerman | 44:43f200e04903 | 327 | //clockwise rotation |
GerhardBerman | 44:43f200e04903 | 328 | motor1DirectionPin=cw; |
GerhardBerman | 3:8caef4872b0c | 329 | } |
GerhardBerman | 44:43f200e04903 | 330 | else{ |
GerhardBerman | 44:43f200e04903 | 331 | //counterclockwise rotation |
GerhardBerman | 44:43f200e04903 | 332 | motor1DirectionPin=ccw; |
GerhardBerman | 3:8caef4872b0c | 333 | } |
GerhardBerman | 39:cc7754330c26 | 334 | if (fabs(motorValue1)>MotorMaxSpeed){ |
GerhardBerman | 44:43f200e04903 | 335 | motor1MagnitudePin = MotorMaxSpeed; //motor values truncated |
GerhardBerman | 29:caf3dd699617 | 336 | } |
GerhardBerman | 29:caf3dd699617 | 337 | else{ |
GerhardBerman | 44:43f200e04903 | 338 | motor1MagnitudePin = fabs(motorValue1); |
GerhardBerman | 29:caf3dd699617 | 339 | } |
GerhardBerman | 29:caf3dd699617 | 340 | |
GerhardBerman | 9:e4c34f5665a0 | 341 | //control motor 2 |
GerhardBerman | 44:43f200e04903 | 342 | if (motorValue2 >=0){ |
GerhardBerman | 44:43f200e04903 | 343 | //counterclockwise rotation due to inverse buildup in tower |
GerhardBerman | 44:43f200e04903 | 344 | motor2DirectionPin=cw; //action is ccw, due to faulty motor2DirectionPin (inverted) |
GerhardBerman | 7:2f74dfd1d411 | 345 | } |
GerhardBerman | 44:43f200e04903 | 346 | else{ |
GerhardBerman | 44:43f200e04903 | 347 | //clockwise rotation due to inverse buildup in tower |
GerhardBerman | 44:43f200e04903 | 348 | motor2DirectionPin=ccw; //action is cw, due to faulty motor2DirectionPin (inverted) |
GerhardBerman | 10:45473f650198 | 349 | //led1=0; |
GerhardBerman | 10:45473f650198 | 350 | //led2=1; |
GerhardBerman | 7:2f74dfd1d411 | 351 | } |
GerhardBerman | 39:cc7754330c26 | 352 | if (fabs(motorValue2)>MotorMaxSpeed){ |
GerhardBerman | 39:cc7754330c26 | 353 | motor2MagnitudePin = MotorMaxSpeed; |
GerhardBerman | 29:caf3dd699617 | 354 | } |
GerhardBerman | 29:caf3dd699617 | 355 | else{ |
GerhardBerman | 29:caf3dd699617 | 356 | motor2MagnitudePin = fabs(motorValue2); |
GerhardBerman | 29:caf3dd699617 | 357 | } |
GerhardBerman | 3:8caef4872b0c | 358 | } |
GerhardBerman | 3:8caef4872b0c | 359 | |
GerhardBerman | 44:43f200e04903 | 360 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 361 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 362 | |
GerhardBerman | 3:8caef4872b0c | 363 | void MeasureAndControl() |
GerhardBerman | 3:8caef4872b0c | 364 | { |
GerhardBerman | 44:43f200e04903 | 365 | // This function measures the EMG of both arms, calculates via inverse kinematics |
GerhardBerman | 44:43f200e04903 | 366 | // what the joint reference positions should be, and controls the motor with |
GerhardBerman | 44:43f200e04903 | 367 | // a Feedback controller. This is called from a Ticker. |
GerhardBerman | 41:68b170829965 | 368 | FilteredSample(T, envelopeL, envelopeR); |
GerhardBerman | 19:cba54636bd62 | 369 | GetReferenceKinematics1(q1, q2, q1_ref, q2_ref); |
GerhardBerman | 24:393da1cc1fa8 | 370 | FeedbackControl1( q1_ref, q2_ref, q1, q2, motorValue1, motorValue2); |
GerhardBerman | 9:e4c34f5665a0 | 371 | SetMotor1(motorValue1, motorValue2); |
GerhardBerman | 3:8caef4872b0c | 372 | } |
GerhardBerman | 3:8caef4872b0c | 373 | |
GerhardBerman | 44:43f200e04903 | 374 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 44:43f200e04903 | 375 | //-------------------------------------------------------------------------------------------------------------------------- |
GerhardBerman | 6:3c4f3f2ce54f | 376 | |
GerhardBerman | 0:43160ef59f9f | 377 | int main() |
GerhardBerman | 0:43160ef59f9f | 378 | { |
GerhardBerman | 44:43f200e04903 | 379 | //pc.baud(115200); |
GerhardBerman | 44:43f200e04903 | 380 | //pc.printf("Test putty IK"); |
GerhardBerman | 44:43f200e04903 | 381 | ledRed=1; |
GerhardBerman | 44:43f200e04903 | 382 | ledBlue=1; |
GerhardBerman | 44:43f200e04903 | 383 | ledRed=0; |
GerhardBerman | 41:68b170829965 | 384 | |
GerhardBerman | 44:43f200e04903 | 385 | bcq1R.add(&bq1R).add(&bq2R); //set BiQuad chains |
GerhardBerman | 44:43f200e04903 | 386 | bcq2R.add(&bq3R); |
GerhardBerman | 44:43f200e04903 | 387 | bcq1L.add(&bq1L).add(&bq2L); |
GerhardBerman | 44:43f200e04903 | 388 | bcq2L.add(&bq3L); |
GerhardBerman | 44:43f200e04903 | 389 | pidf.PIDF( Kp, Ki, Kd, N, t_sample ); //set PID filter |
GerhardBerman | 44:43f200e04903 | 390 | |
GerhardBerman | 44:43f200e04903 | 391 | //start up encoders |
GerhardBerman | 44:43f200e04903 | 392 | counts1 = Encoder1.getPulses(); //gives position of encoder in counts |
GerhardBerman | 44:43f200e04903 | 393 | counts2 = Encoder2.getPulses(); //gives position of encoder in counts |
GerhardBerman | 44:43f200e04903 | 394 | wait(20.0); //time to sart up HIDScope and EMG |
GerhardBerman | 44:43f200e04903 | 395 | MeasureTicker.attach(&MeasureTicker_act, 0.002); //initialize MeasureTicker, 500 Hz |
GerhardBerman | 44:43f200e04903 | 396 | |
GerhardBerman | 0:43160ef59f9f | 397 | while(1) |
GerhardBerman | 0:43160ef59f9f | 398 | { |
GerhardBerman | 3:8caef4872b0c | 399 | if (MeasureTicker_go){ |
GerhardBerman | 3:8caef4872b0c | 400 | MeasureTicker_go=false; |
GerhardBerman | 41:68b170829965 | 401 | ledGrn = 1; |
GerhardBerman | 41:68b170829965 | 402 | ledBlue = 0; |
GerhardBerman | 44:43f200e04903 | 403 | MeasureAndControl(); //execute whole MeasureAndControl function |
GerhardBerman | 44:43f200e04903 | 404 | counts1 = Encoder1.getPulses(); //get encoder counts again |
GerhardBerman | 44:43f200e04903 | 405 | counts2 = Encoder2.getPulses(); //get encoder counts again |
GerhardBerman | 41:68b170829965 | 406 | ledBlue = 1; |
GerhardBerman | 41:68b170829965 | 407 | ledGrn = 0; |
GerhardBerman | 3:8caef4872b0c | 408 | } |
GerhardBerman | 0:43160ef59f9f | 409 | } |
GerhardBerman | 0:43160ef59f9f | 410 | } |