Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: QEI mbed-rtos mbed
main.cpp@10:d14c702c1992, 2013-12-04 (annotated)
- Committer:
- jaoramos
- Date:
- Wed Dec 04 04:11:41 2013 +0000
- Revision:
- 10:d14c702c1992
- Parent:
- 9:4ff9849fc8f6
- Child:
- 11:7e19e51b325d
Swing-up OK, LQR OK, transition not working
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jaoramos | 0:9f2b0ea63eac | 1 | #include "mbed.h" |
jaoramos | 0:9f2b0ea63eac | 2 | #include "rtos.h" |
jaoramos | 0:9f2b0ea63eac | 3 | #include "QEI.h" |
jaoramos | 2:011e6115c77a | 4 | #include <fstream> |
jaoramos | 2:011e6115c77a | 5 | #include <iomanip> |
jaoramos | 8:57c2b7c94ce8 | 6 | #include "stdlib.h" |
jaoramos | 1:5c05e0d08e61 | 7 | |
jaoramos | 4:8fcaff7801b0 | 8 | #define MOTOR_PPR 300 |
jaoramos | 1:5c05e0d08e61 | 9 | #define ENCODER_PPR 1024 |
jaoramos | 1:5c05e0d08e61 | 10 | |
jaoramos | 6:16da0de99a8c | 11 | #define ENC_QUADRATURE_TYPE 4 |
jaoramos | 6:16da0de99a8c | 12 | #define MOT_QUADRATURE_TYPE 2 |
jaoramos | 1:5c05e0d08e61 | 13 | #define OUR_PI 3.141592653589793 |
jaoramos | 5:d41998e421ed | 14 | #define DATA_COLS 7 |
jaoramos | 5:d41998e421ed | 15 | #define BUFFER_SIZE 4200 |
jaoramos | 1:5c05e0d08e61 | 16 | #define MAX_VOLTAGE 3.3 |
jaoramos | 1:5c05e0d08e61 | 17 | #define VOLTS_PER_AMP 0.14 |
jaoramos | 7:59613b7a1631 | 18 | #define PROGRAM_RUNTIME 15.0 |
jaoramos | 0:9f2b0ea63eac | 19 | |
jaoramos | 0:9f2b0ea63eac | 20 | Serial pc(USBTX, USBRX); |
jaoramos | 0:9f2b0ea63eac | 21 | |
jaoramos | 6:16da0de99a8c | 22 | QEI encoder(p29, p30, NC, ENCODER_PPR, QEI::X4_ENCODING); |
jaoramos | 1:5c05e0d08e61 | 23 | QEI motor(p25, p26, NC, MOTOR_PPR); |
jaoramos | 0:9f2b0ea63eac | 24 | Timer T; |
jaoramos | 0:9f2b0ea63eac | 25 | |
jaoramos | 1:5c05e0d08e61 | 26 | //Curent Measurement |
jaoramos | 1:5c05e0d08e61 | 27 | AnalogIn aIn(p16); //pin 15 set as analog input. Pins 15-20 can be used as analog inputs. |
jaoramos | 1:5c05e0d08e61 | 28 | |
jaoramos | 2:011e6115c77a | 29 | //Motor direction and PWM |
jaoramos | 2:011e6115c77a | 30 | DigitalOut dOut1(p5); |
jaoramos | 2:011e6115c77a | 31 | DigitalOut dOut2(p7); |
jaoramos | 2:011e6115c77a | 32 | PwmOut pwmOut(p21); |
jaoramos | 1:5c05e0d08e61 | 33 | |
jaoramos | 0:9f2b0ea63eac | 34 | // open a file for data logger |
jaoramos | 0:9f2b0ea63eac | 35 | LocalFileSystem local("local"); |
jaoramos | 8:57c2b7c94ce8 | 36 | float theta1, theta2, dtheta1, dtheta2, dtheta2MvFil; |
jaoramos | 1:5c05e0d08e61 | 37 | float mCurrent = 0.0; |
jaoramos | 5:d41998e421ed | 38 | float inputVoltage = 0.0; |
jaoramos | 1:5c05e0d08e61 | 39 | //int pulses0 = 0; |
jaoramos | 1:5c05e0d08e61 | 40 | //int deltaPulses; |
jaoramos | 0:9f2b0ea63eac | 41 | float t0 = 0.0; |
jaoramos | 1:5c05e0d08e61 | 42 | float t = 0.0, dt; |
jaoramos | 5:d41998e421ed | 43 | |
jaoramos | 5:d41998e421ed | 44 | //Controller gains - Full-state Feedback |
jaoramos | 5:d41998e421ed | 45 | //float k1 = -0.0316, k2 = 9.7076, k3 = -0.4095, k4 = 1.2340, k5 = 0.0410; |
jaoramos | 5:d41998e421ed | 46 | float k1 = -0.3162, k2 = 18.278, k3 = -0.8964, k4 = 2.4441, k5 = 0.1843; |
jaoramos | 1:5c05e0d08e61 | 47 | |
jaoramos | 6:16da0de99a8c | 48 | float encoder_conv = 2*OUR_PI/(float(ENCODER_PPR)*float(ENC_QUADRATURE_TYPE)); |
jaoramos | 6:16da0de99a8c | 49 | float motor_conv = 2*OUR_PI/(float(MOTOR_PPR)*float(MOT_QUADRATURE_TYPE)); |
jaoramos | 1:5c05e0d08e61 | 50 | |
jaoramos | 0:9f2b0ea63eac | 51 | float* buffer; |
jaoramos | 2:011e6115c77a | 52 | float lambda1 = 30, lambda2 = 30, lambda3 = 15; |
jaoramos | 0:9f2b0ea63eac | 53 | int index; |
jaoramos | 4:8fcaff7801b0 | 54 | int pulsesPend, pulsesMot; |
jaoramos | 10:d14c702c1992 | 55 | bool flag = 1; |
jaoramos | 0:9f2b0ea63eac | 56 | |
jaoramos | 0:9f2b0ea63eac | 57 | void saving(void const *args) { |
jaoramos | 0:9f2b0ea63eac | 58 | index = 0; |
jaoramos | 10:d14c702c1992 | 59 | while ((index < BUFFER_SIZE)&&(flag == 1)) { |
jaoramos | 1:5c05e0d08e61 | 60 | buffer[index] = theta1; |
jaoramos | 1:5c05e0d08e61 | 61 | buffer[index+1] = theta2; |
jaoramos | 1:5c05e0d08e61 | 62 | buffer[index+2] = dtheta1; |
jaoramos | 1:5c05e0d08e61 | 63 | buffer[index+3] = dtheta2; |
jaoramos | 1:5c05e0d08e61 | 64 | buffer[index+4] = mCurrent; |
jaoramos | 5:d41998e421ed | 65 | buffer[index+5] = inputVoltage; |
jaoramos | 5:d41998e421ed | 66 | buffer[index+6] = t; |
jaoramos | 4:8fcaff7801b0 | 67 | index = index + DATA_COLS; |
jaoramos | 1:5c05e0d08e61 | 68 | Thread::wait(20); |
jaoramos | 0:9f2b0ea63eac | 69 | } |
jaoramos | 0:9f2b0ea63eac | 70 | } |
jaoramos | 0:9f2b0ea63eac | 71 | |
jaoramos | 8:57c2b7c94ce8 | 72 | float c2, |
jaoramos | 8:57c2b7c94ce8 | 73 | g = 9.8, |
jaoramos | 8:57c2b7c94ce8 | 74 | m2 = 0.0391 + 0.0259, |
jaoramos | 8:57c2b7c94ce8 | 75 | L1 = (51+44.55)*0.001, |
jaoramos | 8:57c2b7c94ce8 | 76 | l1 = -0.03478, |
jaoramos | 8:57c2b7c94ce8 | 77 | L2 = 0.2983, |
jaoramos | 8:57c2b7c94ce8 | 78 | l2 = 0.05847, |
jaoramos | 8:57c2b7c94ce8 | 79 | I2x = 0.000534, |
jaoramos | 8:57c2b7c94ce8 | 80 | I2y = 0.000841, |
jaoramos | 8:57c2b7c94ce8 | 81 | I2z = 0.00031, |
jaoramos | 8:57c2b7c94ce8 | 82 | Ixz2 = -0.00024; |
jaoramos | 9:4ff9849fc8f6 | 83 | |
jaoramos | 8:57c2b7c94ce8 | 84 | float currentEnergy; |
jaoramos | 8:57c2b7c94ce8 | 85 | |
jaoramos | 8:57c2b7c94ce8 | 86 | float calcEnergy(void) |
jaoramos | 8:57c2b7c94ce8 | 87 | { |
jaoramos | 8:57c2b7c94ce8 | 88 | c2 = cos(theta2); |
jaoramos | 10:d14c702c1992 | 89 | //return (I2x*dtheta2*dtheta2)/2.0 + (I2y*dtheta1*dtheta1)/2.0 + (L1*L1*dtheta1*dtheta1*m2)/2.0 + (dtheta1*dtheta1*l2*l2*m2)/2.0 + (dtheta2*dtheta2*l2*l2*m2)/2.0 |
jaoramos | 10:d14c702c1992 | 90 | //- (I2y*dtheta1*dtheta1*c2*c2)/2.0 + (I2z*dtheta1*dtheta1*c2*c2)/2.0 + Ixz2*dtheta1*dtheta2*c2 + g*l2*m2*c2 - (dtheta1*dtheta1*l2*l2*m2*c2*c2)/2.0 |
jaoramos | 10:d14c702c1992 | 91 | //- L1*dtheta1*dtheta2*l2*m2*c2; |
jaoramos | 10:d14c702c1992 | 92 | return (I2x*dtheta2*dtheta2)/2.0 + g*l2*m2*c2; |
jaoramos | 8:57c2b7c94ce8 | 93 | } |
jaoramos | 8:57c2b7c94ce8 | 94 | |
jaoramos | 3:967aee5fed5b | 95 | void setVoltage(float inputVoltage) |
jaoramos | 3:967aee5fed5b | 96 | { |
jaoramos | 3:967aee5fed5b | 97 | if(inputVoltage<0.0) { |
jaoramos | 3:967aee5fed5b | 98 | inputVoltage = -inputVoltage; |
jaoramos | 3:967aee5fed5b | 99 | dOut1=0; |
jaoramos | 3:967aee5fed5b | 100 | dOut2=1; |
jaoramos | 3:967aee5fed5b | 101 | } else { |
jaoramos | 3:967aee5fed5b | 102 | dOut1=1; |
jaoramos | 3:967aee5fed5b | 103 | dOut2=0; |
jaoramos | 3:967aee5fed5b | 104 | } |
jaoramos | 3:967aee5fed5b | 105 | float dutyCycle = inputVoltage/MAX_VOLTAGE; |
jaoramos | 3:967aee5fed5b | 106 | dutyCycle = (dutyCycle > 1.0)? 1.0 : dutyCycle; |
jaoramos | 3:967aee5fed5b | 107 | pwmOut.write(dutyCycle); |
jaoramos | 3:967aee5fed5b | 108 | } |
jaoramos | 8:57c2b7c94ce8 | 109 | // |
jaoramos | 8:57c2b7c94ce8 | 110 | //#define MOVING_AVERAGE_SIZE 10 |
jaoramos | 8:57c2b7c94ce8 | 111 | // |
jaoramos | 8:57c2b7c94ce8 | 112 | //float movingAverage(float unfiltered) |
jaoramos | 8:57c2b7c94ce8 | 113 | //{ |
jaoramos | 8:57c2b7c94ce8 | 114 | // static std::deque<float> movAvgBuffer; // empty deque of floats |
jaoramos | 8:57c2b7c94ce8 | 115 | // static float sum = 0.0; |
jaoramos | 8:57c2b7c94ce8 | 116 | // |
jaoramos | 8:57c2b7c94ce8 | 117 | // movAvgBuffer.push_front(unfiltered); |
jaoramos | 8:57c2b7c94ce8 | 118 | // sum += unfiltered; |
jaoramos | 8:57c2b7c94ce8 | 119 | // |
jaoramos | 8:57c2b7c94ce8 | 120 | // if( movAvgBuffer.size() <= MOVING_AVERAGE_SIZE) |
jaoramos | 8:57c2b7c94ce8 | 121 | // { |
jaoramos | 8:57c2b7c94ce8 | 122 | // return (sum/float(movAvgBuffer.size())); |
jaoramos | 8:57c2b7c94ce8 | 123 | // } |
jaoramos | 8:57c2b7c94ce8 | 124 | // else |
jaoramos | 8:57c2b7c94ce8 | 125 | // { |
jaoramos | 8:57c2b7c94ce8 | 126 | // sum -= movAvgBuffer.back(); |
jaoramos | 8:57c2b7c94ce8 | 127 | // movAvgBuffer.pop_back(); |
jaoramos | 8:57c2b7c94ce8 | 128 | // |
jaoramos | 8:57c2b7c94ce8 | 129 | // return (sum/float(MOVING_AVERAGE_SIZE)); |
jaoramos | 8:57c2b7c94ce8 | 130 | // } |
jaoramos | 8:57c2b7c94ce8 | 131 | //} |
jaoramos | 3:967aee5fed5b | 132 | |
jaoramos | 0:9f2b0ea63eac | 133 | void computing(void const *args) { |
jaoramos | 9:4ff9849fc8f6 | 134 | float z1=0.0, z2=0.0, dz1 = 0.0, dz2 = 0.0, z3 = 0.0, dz3 = 0.0; |
jaoramos | 9:4ff9849fc8f6 | 135 | bool firstTime = true; |
jaoramos | 4:8fcaff7801b0 | 136 | |
jaoramos | 7:59613b7a1631 | 137 | while (true ) { |
jaoramos | 0:9f2b0ea63eac | 138 | t = T.read(); |
jaoramos | 1:5c05e0d08e61 | 139 | |
jaoramos | 8:57c2b7c94ce8 | 140 | |
jaoramos | 2:011e6115c77a | 141 | //read current |
jaoramos | 1:5c05e0d08e61 | 142 | mCurrent = aIn.read()*MAX_VOLTAGE/VOLTS_PER_AMP; |
jaoramos | 3:967aee5fed5b | 143 | if(dOut1 == 0) |
jaoramos | 3:967aee5fed5b | 144 | mCurrent = -mCurrent; |
jaoramos | 1:5c05e0d08e61 | 145 | pulsesPend = -encoder.getPulses(); |
jaoramos | 1:5c05e0d08e61 | 146 | pulsesMot = motor.getPulses(); |
jaoramos | 1:5c05e0d08e61 | 147 | |
jaoramos | 1:5c05e0d08e61 | 148 | dt = t - t0; //time difference |
jaoramos | 4:8fcaff7801b0 | 149 | theta2 = float(pulsesPend)*encoder_conv + OUR_PI; |
jaoramos | 1:5c05e0d08e61 | 150 | theta1 = float(pulsesMot)*motor_conv; |
jaoramos | 9:4ff9849fc8f6 | 151 | if(firstTime) |
jaoramos | 9:4ff9849fc8f6 | 152 | { |
jaoramos | 9:4ff9849fc8f6 | 153 | // z1 and z2 are in the beginning the same as the angle so that dtheta1 and dtheta2 are zero |
jaoramos | 9:4ff9849fc8f6 | 154 | z1 = theta1; |
jaoramos | 10:d14c702c1992 | 155 | z2 = 1.001*theta2; |
jaoramos | 9:4ff9849fc8f6 | 156 | firstTime = false; |
jaoramos | 9:4ff9849fc8f6 | 157 | } |
jaoramos | 1:5c05e0d08e61 | 158 | //calculate dtheta1 |
jaoramos | 2:011e6115c77a | 159 | dz1 = - lambda1 * z1 + lambda1 * theta1; |
jaoramos | 1:5c05e0d08e61 | 160 | z1 = z1 + dz1 * dt; |
jaoramos | 1:5c05e0d08e61 | 161 | dtheta1 = dz1; |
jaoramos | 0:9f2b0ea63eac | 162 | |
jaoramos | 1:5c05e0d08e61 | 163 | //calculate dtheta2 |
jaoramos | 2:011e6115c77a | 164 | dz2 = - lambda2 * z2 + lambda2 * theta2; |
jaoramos | 1:5c05e0d08e61 | 165 | z2 = z2 + dz2 * dt; |
jaoramos | 1:5c05e0d08e61 | 166 | dtheta2 = dz2; |
jaoramos | 2:011e6115c77a | 167 | |
jaoramos | 8:57c2b7c94ce8 | 168 | //dtheta2MvFil = movingAverage(dtheta2); |
jaoramos | 8:57c2b7c94ce8 | 169 | |
jaoramos | 2:011e6115c77a | 170 | //filter current |
jaoramos | 2:011e6115c77a | 171 | dz3 = -lambda3 * z3 + lambda3 * mCurrent; |
jaoramos | 2:011e6115c77a | 172 | z3 = z3 + dz3 * dt; |
jaoramos | 2:011e6115c77a | 173 | mCurrent = z3; |
jaoramos | 2:011e6115c77a | 174 | |
jaoramos | 10:d14c702c1992 | 175 | //set pwm |
jaoramos | 10:d14c702c1992 | 176 | if (cos(theta2) < 0.96) { |
jaoramos | 9:4ff9849fc8f6 | 177 | flag = 1; |
jaoramos | 8:57c2b7c94ce8 | 178 | currentEnergy = calcEnergy(); |
jaoramos | 10:d14c702c1992 | 179 | inputVoltage = -2.3*dtheta2*(0.0372 - currentEnergy); |
jaoramos | 8:57c2b7c94ce8 | 180 | |
jaoramos | 8:57c2b7c94ce8 | 181 | } else { |
jaoramos | 8:57c2b7c94ce8 | 182 | flag = 1; |
jaoramos | 10:d14c702c1992 | 183 | inputVoltage = -(k1*theta1 + k2*theta2 + k3*dtheta1 + k4*dtheta2 + k5*mCurrent); |
jaoramos | 8:57c2b7c94ce8 | 184 | } |
jaoramos | 9:4ff9849fc8f6 | 185 | |
jaoramos | 8:57c2b7c94ce8 | 186 | setVoltage(inputVoltage); |
jaoramos | 8:57c2b7c94ce8 | 187 | |
jaoramos | 0:9f2b0ea63eac | 188 | t0 = t; |
jaoramos | 0:9f2b0ea63eac | 189 | Thread::wait(1); |
jaoramos | 0:9f2b0ea63eac | 190 | } |
jaoramos | 0:9f2b0ea63eac | 191 | } |
jaoramos | 0:9f2b0ea63eac | 192 | |
jaoramos | 0:9f2b0ea63eac | 193 | void saveToFile () |
jaoramos | 0:9f2b0ea63eac | 194 | { |
jaoramos | 0:9f2b0ea63eac | 195 | FILE *fp = fopen("/local/data.csv", "w"); |
jaoramos | 0:9f2b0ea63eac | 196 | if (!fp) { |
jaoramos | 0:9f2b0ea63eac | 197 | fprintf(stderr, "File could not be openend \n\r"); |
jaoramos | 0:9f2b0ea63eac | 198 | exit(1); |
jaoramos | 0:9f2b0ea63eac | 199 | } |
jaoramos | 0:9f2b0ea63eac | 200 | |
jaoramos | 0:9f2b0ea63eac | 201 | wait(2.0); |
jaoramos | 0:9f2b0ea63eac | 202 | |
jaoramos | 5:d41998e421ed | 203 | for (int i=0; i < index; i = i + DATA_COLS) |
jaoramos | 1:5c05e0d08e61 | 204 | { |
jaoramos | 5:d41998e421ed | 205 | for (int j = 0; j < DATA_COLS; j++) |
jaoramos | 1:5c05e0d08e61 | 206 | { |
jaoramos | 1:5c05e0d08e61 | 207 | fprintf(fp,"%f,", buffer[i+j]); |
jaoramos | 1:5c05e0d08e61 | 208 | } |
jaoramos | 1:5c05e0d08e61 | 209 | fprintf(fp,"\n"); |
jaoramos | 0:9f2b0ea63eac | 210 | } |
jaoramos | 0:9f2b0ea63eac | 211 | pc.printf("closing file\n\r"); |
jaoramos | 0:9f2b0ea63eac | 212 | fclose(fp); |
jaoramos | 0:9f2b0ea63eac | 213 | wait(2.0);; |
jaoramos | 0:9f2b0ea63eac | 214 | } |
jaoramos | 0:9f2b0ea63eac | 215 | |
jaoramos | 0:9f2b0ea63eac | 216 | int main() { |
jaoramos | 0:9f2b0ea63eac | 217 | //allocate memory for the buffer |
jaoramos | 1:5c05e0d08e61 | 218 | pc.printf("creating buffer!\r\n"); |
jaoramos | 5:d41998e421ed | 219 | buffer = new float[BUFFER_SIZE]; |
jaoramos | 1:5c05e0d08e61 | 220 | pc.printf("done creating buffer!\r\n"); |
jaoramos | 0:9f2b0ea63eac | 221 | T.start(); |
jaoramos | 5:d41998e421ed | 222 | pwmOut.period(0.0001); |
jaoramos | 0:9f2b0ea63eac | 223 | |
jaoramos | 9:4ff9849fc8f6 | 224 | Thread::wait(2000); |
jaoramos | 9:4ff9849fc8f6 | 225 | |
jaoramos | 5:d41998e421ed | 226 | Thread thrd2(computing,NULL,osPriorityRealtime); |
jaoramos | 5:d41998e421ed | 227 | pc.printf("started computing thread!\r\n"); |
jaoramos | 5:d41998e421ed | 228 | Thread thrd3(saving,NULL,osPriorityNormal); |
jaoramos | 5:d41998e421ed | 229 | pc.printf("started saving thread!\r\n"); |
jaoramos | 5:d41998e421ed | 230 | |
jaoramos | 2:011e6115c77a | 231 | |
jaoramos | 0:9f2b0ea63eac | 232 | pc.printf("Start!\r\n"); |
jaoramos | 0:9f2b0ea63eac | 233 | pc.printf("Time: %f\r\n", t); |
jaoramos | 8:57c2b7c94ce8 | 234 | |
jaoramos | 7:59613b7a1631 | 235 | while (t < PROGRAM_RUNTIME) |
jaoramos | 0:9f2b0ea63eac | 236 | { |
jaoramos | 9:4ff9849fc8f6 | 237 | //pc.printf("at time: %f energy: %f\n",t, currentEnergy); |
jaoramos | 8:57c2b7c94ce8 | 238 | |
jaoramos | 8:57c2b7c94ce8 | 239 | Thread::wait(200); |
jaoramos | 0:9f2b0ea63eac | 240 | } |
jaoramos | 2:011e6115c77a | 241 | pc.printf("Done at Index: %d\r\n",index); |
jaoramos | 2:011e6115c77a | 242 | pwmOut.write(0.0); |
jaoramos | 0:9f2b0ea63eac | 243 | thrd2.terminate(); |
jaoramos | 0:9f2b0ea63eac | 244 | thrd3.terminate(); |
jaoramos | 0:9f2b0ea63eac | 245 | saveToFile(); |
jaoramos | 0:9f2b0ea63eac | 246 | } |