Operation Mode State Machine plus homing for StateMachinePTR
Dependencies: MODSERIAL QEI biquadFilter mbed
Fork of Controller by
OperationMode.cpp@12:cae29e41ac2e, 2018-10-31 (annotated)
- Committer:
- Roooos
- Date:
- Wed Oct 31 21:21:13 2018 +0000
- Revision:
- 12:cae29e41ac2e
- Parent:
- 11:dcc416dbe3ea
- Child:
- 13:9125d359619c
met OPSET;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Roooos | 10:93957c339972 | 1 | #include "mbed.h" |
Roooos | 10:93957c339972 | 2 | #include "math.h" |
Roooos | 10:93957c339972 | 3 | #include "MODSERIAL.h" |
Roooos | 10:93957c339972 | 4 | #include "QEI.h" |
Roooos | 10:93957c339972 | 5 | #include "BiQuad.h" |
Roooos | 10:93957c339972 | 6 | |
Roooos | 10:93957c339972 | 7 | //Tickers |
Roooos | 10:93957c339972 | 8 | Ticker TickerMeasureAndControl; |
Roooos | 10:93957c339972 | 9 | Timer TimerLoop; |
Roooos | 10:93957c339972 | 10 | //Communication |
Roooos | 10:93957c339972 | 11 | MODSERIAL pc(USBTX,USBRX); |
Roooos | 10:93957c339972 | 12 | QEI Encoder(D10,D11,NC,32); |
Roooos | 10:93957c339972 | 13 | QEI Encoder2(D12,D13,NC,32); |
Roooos | 10:93957c339972 | 14 | //Global pin variables |
Roooos | 10:93957c339972 | 15 | PwmOut PwmPin(D5); |
Roooos | 10:93957c339972 | 16 | PwmOut PwmPin2(D6); |
Roooos | 10:93957c339972 | 17 | DigitalOut DirectionPin(D4); |
Roooos | 10:93957c339972 | 18 | DigitalOut DirectionPin2(D7); |
Roooos | 10:93957c339972 | 19 | DigitalIn BUT1(D8); |
Roooos | 10:93957c339972 | 20 | DigitalIn BUT2(D9); |
Roooos | 10:93957c339972 | 21 | DigitalIn button_sw2(SW2); |
Roooos | 10:93957c339972 | 22 | DigitalIn button_sw3(SW3); |
Roooos | 10:93957c339972 | 23 | |
Roooos | 10:93957c339972 | 24 | DigitalOut LedGreen(LED_GREEN); |
Roooos | 10:93957c339972 | 25 | DigitalOut LedRed(LED_RED); |
Roooos | 10:93957c339972 | 26 | DigitalOut LedBlue(LED_BLUE); |
Roooos | 10:93957c339972 | 27 | |
Roooos | 10:93957c339972 | 28 | double PositionRef=0; |
Roooos | 10:93957c339972 | 29 | double PositionRef2=0; |
Roooos | 10:93957c339972 | 30 | |
Roooos | 10:93957c339972 | 31 | |
Roooos | 10:93957c339972 | 32 | //Define substates Operation Mode |
Roooos | 10:93957c339972 | 33 | |
Roooos | 11:dcc416dbe3ea | 34 | enum States {OPWait, OPSet, OPState1, OPState2, OPState3, OPState4, OPHoming}; |
Roooos | 10:93957c339972 | 35 | States CurrentOperationState; |
Roooos | 10:93957c339972 | 36 | |
Roooos | 10:93957c339972 | 37 | void OperationStateMachine() |
Roooos | 10:93957c339972 | 38 | { |
Roooos | 10:93957c339972 | 39 | |
Roooos | 11:dcc416dbe3ea | 40 | |
Roooos | 10:93957c339972 | 41 | switch (CurrentOperationState) { |
Roooos | 10:93957c339972 | 42 | case OPWait: |
Roooos | 10:93957c339972 | 43 | LedRed = 0; //red |
Roooos | 11:dcc416dbe3ea | 44 | LedGreen = 1; |
Roooos | 11:dcc416dbe3ea | 45 | LedBlue = 1; |
Roooos | 12:cae29e41ac2e | 46 | if (BUT1 == false) { |
Roooos | 12:cae29e41ac2e | 47 | CurrentOperationState = OPState1; |
Roooos | 12:cae29e41ac2e | 48 | TimerLoop.reset(); |
Roooos | 12:cae29e41ac2e | 49 | } |
Roooos | 12:cae29e41ac2e | 50 | if (button_sw3 == false) { |
Roooos | 11:dcc416dbe3ea | 51 | CurrentOperationState = OPSet; |
Roooos | 12:cae29e41ac2e | 52 | TimreLoop.reset(); |
Roooos | 11:dcc416dbe3ea | 53 | } |
Roooos | 11:dcc416dbe3ea | 54 | break; |
Roooos | 11:dcc416dbe3ea | 55 | |
Roooos | 11:dcc416dbe3ea | 56 | case OPSet: |
Roooos | 11:dcc416dbe3ea | 57 | LedRed = 1; //turqoise |
Roooos | 11:dcc416dbe3ea | 58 | LedGreen = 0; |
Roooos | 11:dcc416dbe3ea | 59 | LedBlue = 0; |
Roooos | 11:dcc416dbe3ea | 60 | if (PositionRef2 > -0.853*(6.380)) { |
Roooos | 11:dcc416dbe3ea | 61 | PositionRef2 -= 0.0005*(6.380); |
Roooos | 11:dcc416dbe3ea | 62 | } |
Roooos | 11:dcc416dbe3ea | 63 | if (PositionRef2 < -0.853*(6.380) && TimerLoop > 2) { |
Roooos | 10:93957c339972 | 64 | CurrentOperationState = OPState1; |
Roooos | 10:93957c339972 | 65 | TimerLoop.reset(); |
Roooos | 10:93957c339972 | 66 | } |
Roooos | 10:93957c339972 | 67 | break; |
Roooos | 11:dcc416dbe3ea | 68 | |
Roooos | 10:93957c339972 | 69 | case OPState1: |
Roooos | 11:dcc416dbe3ea | 70 | LedRed = 0; //yellow |
Roooos | 11:dcc416dbe3ea | 71 | LedGreen = 0; |
Roooos | 11:dcc416dbe3ea | 72 | LedBlue = 1; |
Roooos | 11:dcc416dbe3ea | 73 | if (PositionRef < 0.48*(6.380)) { //counts/8400 *2 because encoder X2 -> X4 |
Roooos | 10:93957c339972 | 74 | PositionRef += 0.0005*(6.380); |
Roooos | 10:93957c339972 | 75 | } |
Roooos | 11:dcc416dbe3ea | 76 | if ((PositionRef > 0.48*(6.380)) && (TimerLoop >= 4.0)) { |
Roooos | 10:93957c339972 | 77 | CurrentOperationState = OPState2; |
Roooos | 10:93957c339972 | 78 | TimerLoop.reset(); |
Roooos | 10:93957c339972 | 79 | } |
Roooos | 10:93957c339972 | 80 | break; |
Roooos | 11:dcc416dbe3ea | 81 | |
Roooos | 10:93957c339972 | 82 | case OPState2: |
Roooos | 11:dcc416dbe3ea | 83 | LedRed = 0; //white |
Roooos | 11:dcc416dbe3ea | 84 | LedGreen = 0; |
Roooos | 11:dcc416dbe3ea | 85 | LedBlue = 0; |
Roooos | 11:dcc416dbe3ea | 86 | if (PositionRef2 > -0.40*(6.380)) { |
Roooos | 10:93957c339972 | 87 | PositionRef2 -= 0.0005*(6.380); |
Roooos | 10:93957c339972 | 88 | } |
Roooos | 11:dcc416dbe3ea | 89 | if ((PositionRef2 < -0.40*(6.380)) && (TimerLoop >= 4.0)) { |
Roooos | 10:93957c339972 | 90 | CurrentOperationState = OPState3; |
Roooos | 10:93957c339972 | 91 | TimerLoop.reset(); |
Roooos | 10:93957c339972 | 92 | } |
Roooos | 10:93957c339972 | 93 | break; |
Roooos | 11:dcc416dbe3ea | 94 | |
Roooos | 10:93957c339972 | 95 | case OPState3: |
Roooos | 11:dcc416dbe3ea | 96 | LedRed = 0; //pink |
Roooos | 11:dcc416dbe3ea | 97 | LedGreen = 1; |
Roooos | 11:dcc416dbe3ea | 98 | LedBlue = 0; |
Roooos | 11:dcc416dbe3ea | 99 | if (PositionRef > -0.15*(6.380)) { |
Roooos | 10:93957c339972 | 100 | PositionRef -= 0.0005*(6.380); |
Roooos | 10:93957c339972 | 101 | } |
Roooos | 11:dcc416dbe3ea | 102 | if (PositionRef2 > -0.75*(6.380)) { |
Roooos | 11:dcc416dbe3ea | 103 | PositionRef2 -= 0.0002*(6.380); |
Roooos | 10:93957c339972 | 104 | } |
Roooos | 11:dcc416dbe3ea | 105 | if ((PositionRef < -0.15*(6.380)) && (PositionRef2 < -0.75*(6.380)) && (TimerLoop >= 4.0)) { |
Roooos | 10:93957c339972 | 106 | CurrentOperationState = OPState4; |
Roooos | 10:93957c339972 | 107 | TimerLoop.reset(); |
Roooos | 10:93957c339972 | 108 | } |
Roooos | 10:93957c339972 | 109 | break; |
Roooos | 11:dcc416dbe3ea | 110 | |
Roooos | 10:93957c339972 | 111 | case OPState4: |
Roooos | 11:dcc416dbe3ea | 112 | LedRed = 1; //blue |
Roooos | 11:dcc416dbe3ea | 113 | LedGreen = 1; |
Roooos | 11:dcc416dbe3ea | 114 | LedBlue = 0; |
Roooos | 11:dcc416dbe3ea | 115 | if (PositionRef2 > -1.4*(6.380)) { |
Roooos | 11:dcc416dbe3ea | 116 | PositionRef2 -= 0.005*(6.380); |
Roooos | 10:93957c339972 | 117 | } |
Roooos | 11:dcc416dbe3ea | 118 | if ((PositionRef2 < -1.4*(6.380)) && (TimerLoop > 4)) { |
Roooos | 11:dcc416dbe3ea | 119 | TimerLoop.reset(); |
Roooos | 10:93957c339972 | 120 | CurrentOperationState = OPHoming; |
Roooos | 10:93957c339972 | 121 | } |
Roooos | 10:93957c339972 | 122 | break; |
Roooos | 11:dcc416dbe3ea | 123 | |
Roooos | 10:93957c339972 | 124 | case OPHoming: |
Roooos | 10:93957c339972 | 125 | LedGreen = 0; //Green |
Roooos | 10:93957c339972 | 126 | LedBlue = 1; |
Roooos | 10:93957c339972 | 127 | LedRed = 1; |
Roooos | 11:dcc416dbe3ea | 128 | if (PositionRef < 0) { |
Roooos | 11:dcc416dbe3ea | 129 | PositionRef += 0.003*(6.380); |
Roooos | 11:dcc416dbe3ea | 130 | } |
Roooos | 11:dcc416dbe3ea | 131 | if (PositionRef2 < 0) { |
Roooos | 11:dcc416dbe3ea | 132 | PositionRef2 += 0.001*(6.380); |
Roooos | 11:dcc416dbe3ea | 133 | } |
Roooos | 11:dcc416dbe3ea | 134 | if ((PositionRef > 0) && (PositionRef2 > 0) && (TimerLoop > 4)) { |
Roooos | 11:dcc416dbe3ea | 135 | CurrentOperationState = OPWait; |
Roooos | 11:dcc416dbe3ea | 136 | } |
Roooos | 10:93957c339972 | 137 | break; |
Roooos | 10:93957c339972 | 138 | } |
Roooos | 10:93957c339972 | 139 | } |
Roooos | 10:93957c339972 | 140 | |
Roooos | 10:93957c339972 | 141 | |
Roooos | 10:93957c339972 | 142 | |
Roooos | 10:93957c339972 | 143 | |
Roooos | 10:93957c339972 | 144 | //----------------------------------------------------------------------------- |
Roooos | 10:93957c339972 | 145 | //The double-functions |
Roooos | 10:93957c339972 | 146 | |
Roooos | 10:93957c339972 | 147 | |
Roooos | 10:93957c339972 | 148 | |
Roooos | 10:93957c339972 | 149 | |
Roooos | 10:93957c339972 | 150 | // actual position of the motor 1 |
Roooos | 10:93957c339972 | 151 | double GetActualPosition() |
Roooos | 10:93957c339972 | 152 | { |
Roooos | 10:93957c339972 | 153 | //This function determines the actual position of the motor |
Roooos | 10:93957c339972 | 154 | //The count:radians relation is 8400:2pi |
Roooos | 10:93957c339972 | 155 | double EncoderCounts = Encoder.getPulses(); //number of counts |
Roooos | 10:93957c339972 | 156 | double PositionMotor = EncoderCounts/8400*(2*6.283); // in rad (6.283 = 2pi), 2* is for compensating X4 --> X2 encoding |
Roooos | 10:93957c339972 | 157 | |
Roooos | 10:93957c339972 | 158 | return PositionMotor; |
Roooos | 10:93957c339972 | 159 | } |
Roooos | 10:93957c339972 | 160 | |
Roooos | 10:93957c339972 | 161 | double GetActualPosition2() //motor 2 |
Roooos | 10:93957c339972 | 162 | { |
Roooos | 10:93957c339972 | 163 | double Encoder2Counts = Encoder2.getPulses(); //number of counts |
Roooos | 10:93957c339972 | 164 | double PositionMotor2 = Encoder2Counts/8400*(2*6.283); // in rad (6.283 = 2pi), 2* is for compensating X4 --> X2 encoding |
Roooos | 10:93957c339972 | 165 | |
Roooos | 10:93957c339972 | 166 | return PositionMotor2; |
Roooos | 10:93957c339972 | 167 | } |
Roooos | 10:93957c339972 | 168 | |
Roooos | 10:93957c339972 | 169 | ///The controller |
Roooos | 10:93957c339972 | 170 | double PID_Controller(double Error) |
Roooos | 10:93957c339972 | 171 | { |
Roooos | 10:93957c339972 | 172 | //Arm drive parameters |
Roooos | 10:93957c339972 | 173 | double Ts = 0.002; //Sampling time 100 Hz |
Roooos | 10:93957c339972 | 174 | double Kp = 19.8; // proportional gain |
Roooos | 10:93957c339972 | 175 | double Ki = 3.98; //Intergral gain |
Roooos | 10:93957c339972 | 176 | double Kd = 1.96; //Differential gain. |
Roooos | 10:93957c339972 | 177 | |
Roooos | 10:93957c339972 | 178 | static double ErrorIntegral = 0; |
Roooos | 10:93957c339972 | 179 | static double ErrorPrevious = Error; |
Roooos | 10:93957c339972 | 180 | static BiQuad LowPassFilter(0.0640, 0.1279, 0.0640, -1.1683, 0.4241); |
Roooos | 10:93957c339972 | 181 | |
Roooos | 10:93957c339972 | 182 | //Proportional part: |
Roooos | 10:93957c339972 | 183 | double u_k = Kp * Error; |
Roooos | 10:93957c339972 | 184 | |
Roooos | 10:93957c339972 | 185 | //Integral part: |
Roooos | 10:93957c339972 | 186 | ErrorIntegral = ErrorIntegral + Error*Ts; |
Roooos | 10:93957c339972 | 187 | double u_i = Ki * ErrorIntegral; |
Roooos | 10:93957c339972 | 188 | |
Roooos | 10:93957c339972 | 189 | //Derivative part: |
Roooos | 10:93957c339972 | 190 | double ErrorDerivative = (Error - ErrorPrevious)/Ts; |
Roooos | 10:93957c339972 | 191 | double FilteredErrorDerivative = LowPassFilter.step(ErrorDerivative); |
Roooos | 10:93957c339972 | 192 | double u_d = Kd * FilteredErrorDerivative; |
Roooos | 10:93957c339972 | 193 | ErrorPrevious = Error; |
Roooos | 10:93957c339972 | 194 | |
Roooos | 10:93957c339972 | 195 | // sum of parts and return it |
Roooos | 10:93957c339972 | 196 | return u_k + u_i + u_d; //This will become the MotorValue |
Roooos | 10:93957c339972 | 197 | } |
Roooos | 10:93957c339972 | 198 | |
Roooos | 10:93957c339972 | 199 | double PID_Controller2(double Error) |
Roooos | 10:93957c339972 | 200 | { |
Roooos | 10:93957c339972 | 201 | //Belt drive parameters |
Roooos | 10:93957c339972 | 202 | double Ts = 0.002; //Sampling time 100 Hz |
Roooos | 10:93957c339972 | 203 | double Kp = 11.1; // proportional gain |
Roooos | 10:93957c339972 | 204 | double Ki = 2.24; //Integral gain |
Roooos | 10:93957c339972 | 205 | double Kd = 1.1; //Differential gain |
Roooos | 10:93957c339972 | 206 | |
Roooos | 10:93957c339972 | 207 | static double ErrorIntegral = 0; |
Roooos | 10:93957c339972 | 208 | static double ErrorPrevious = Error; |
Roooos | 10:93957c339972 | 209 | static BiQuad LowPassFilter(0.0640, 0.1279, 0.0640, -1.1683, 0.4241); |
Roooos | 10:93957c339972 | 210 | |
Roooos | 10:93957c339972 | 211 | //Proportional part: |
Roooos | 10:93957c339972 | 212 | double u_k = Kp * Error; |
Roooos | 10:93957c339972 | 213 | |
Roooos | 10:93957c339972 | 214 | //Integral part: |
Roooos | 10:93957c339972 | 215 | ErrorIntegral = ErrorIntegral + Error*Ts; |
Roooos | 10:93957c339972 | 216 | double u_i = Ki * ErrorIntegral; |
Roooos | 10:93957c339972 | 217 | |
Roooos | 10:93957c339972 | 218 | //Derivative part: |
Roooos | 10:93957c339972 | 219 | double ErrorDerivative = (Error - ErrorPrevious)/Ts; |
Roooos | 10:93957c339972 | 220 | double FilteredErrorDerivative = LowPassFilter.step(ErrorDerivative); |
Roooos | 10:93957c339972 | 221 | double u_d = Kd * FilteredErrorDerivative; |
Roooos | 10:93957c339972 | 222 | ErrorPrevious = Error; |
Roooos | 10:93957c339972 | 223 | |
Roooos | 10:93957c339972 | 224 | // sum of parts and return it |
Roooos | 10:93957c339972 | 225 | return u_k + u_i + u_d; //This will become the MotorValue |
Roooos | 10:93957c339972 | 226 | } |
Roooos | 10:93957c339972 | 227 | |
Roooos | 10:93957c339972 | 228 | //Ticker function set motorvalues |
Roooos | 10:93957c339972 | 229 | void SetMotor(double MotorValue, double MotorValue2) |
Roooos | 10:93957c339972 | 230 | { |
Roooos | 10:93957c339972 | 231 | if (MotorValue >=0) { |
Roooos | 10:93957c339972 | 232 | DirectionPin = 1; |
Roooos | 10:93957c339972 | 233 | } else { |
Roooos | 10:93957c339972 | 234 | DirectionPin = 0; |
Roooos | 10:93957c339972 | 235 | } |
Roooos | 10:93957c339972 | 236 | |
Roooos | 10:93957c339972 | 237 | if (fabs(MotorValue)>1) { // if error more than 1 radian, full duty cycle |
Roooos | 10:93957c339972 | 238 | PwmPin = 1; |
Roooos | 10:93957c339972 | 239 | } else { |
Roooos | 10:93957c339972 | 240 | PwmPin = fabs(MotorValue); |
Roooos | 10:93957c339972 | 241 | } |
Roooos | 10:93957c339972 | 242 | |
Roooos | 10:93957c339972 | 243 | if (MotorValue2 >=0) { |
Roooos | 10:93957c339972 | 244 | DirectionPin2 = 1; |
Roooos | 10:93957c339972 | 245 | } else { |
Roooos | 10:93957c339972 | 246 | DirectionPin2 = 0; |
Roooos | 10:93957c339972 | 247 | } |
Roooos | 10:93957c339972 | 248 | |
Roooos | 10:93957c339972 | 249 | if (fabs(MotorValue2)>1) { // if error more than 1 radian, full duty cycle |
Roooos | 10:93957c339972 | 250 | PwmPin2 = 1; |
Roooos | 10:93957c339972 | 251 | } else { |
Roooos | 10:93957c339972 | 252 | PwmPin2 = fabs(MotorValue2); |
Roooos | 10:93957c339972 | 253 | } |
Roooos | 10:93957c339972 | 254 | } |
Roooos | 10:93957c339972 | 255 | |
Roooos | 10:93957c339972 | 256 | // ---------------------------------------------------------------------------- |
Roooos | 10:93957c339972 | 257 | //Ticker function |
Roooos | 10:93957c339972 | 258 | void MeasureAndControl(void) |
Roooos | 10:93957c339972 | 259 | { |
Roooos | 11:dcc416dbe3ea | 260 | |
Roooos | 10:93957c339972 | 261 | //double PositionRef = GetReferencePosition(); |
Roooos | 10:93957c339972 | 262 | //double PositionRef2 = GetReferencePosition2(); |
Roooos | 11:dcc416dbe3ea | 263 | |
Roooos | 10:93957c339972 | 264 | OperationStateMachine(); |
Roooos | 10:93957c339972 | 265 | double PositionMotor = GetActualPosition(); |
Roooos | 10:93957c339972 | 266 | double PositionMotor2 = GetActualPosition2(); |
Roooos | 10:93957c339972 | 267 | double MotorValue = PID_Controller(PositionRef - PositionMotor); // input is error |
Roooos | 10:93957c339972 | 268 | double MotorValue2 = PID_Controller2(PositionRef2 - PositionMotor2); |
Roooos | 10:93957c339972 | 269 | SetMotor(MotorValue, MotorValue2); |
Roooos | 10:93957c339972 | 270 | } |
Roooos | 10:93957c339972 | 271 | |
Roooos | 10:93957c339972 | 272 | |
Roooos | 10:93957c339972 | 273 | |
Roooos | 10:93957c339972 | 274 | //----------------------------------------------------------------------------- |
Roooos | 10:93957c339972 | 275 | int main() |
Roooos | 10:93957c339972 | 276 | { |
Roooos | 10:93957c339972 | 277 | LedGreen = 1; |
Roooos | 10:93957c339972 | 278 | LedRed = 1; |
Roooos | 10:93957c339972 | 279 | LedBlue = 1; |
Roooos | 10:93957c339972 | 280 | pc.baud(115200); |
Roooos | 10:93957c339972 | 281 | pc.printf("Hello World\n\r"); |
Roooos | 10:93957c339972 | 282 | TimerLoop.start(); |
Roooos | 10:93957c339972 | 283 | CurrentOperationState = OPWait; |
Roooos | 10:93957c339972 | 284 | PwmPin.period_us(60); // 16.66667 kHz (default period is too slow!) |
Roooos | 10:93957c339972 | 285 | TickerMeasureAndControl.attach(&MeasureAndControl,0.002); //500 Hz |
Roooos | 10:93957c339972 | 286 | while (true) { |
Roooos | 10:93957c339972 | 287 | } |
Roooos | 10:93957c339972 | 288 | } |