Mini Cheetah Actuator Branch Superseded by: https://github.com/bgkatz/motorcontrol

Dependencies:   mbed-dev-f303 FastPWM3

Superseded by: https://github.com/bgkatz/motorcontrol

Committer:
benkatz
Date:
Sun Jul 21 21:42:49 2019 +0000
Revision:
52:8e74c22ed89f
Parent:
47:e1196a851f76
testing gb-54;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
benkatz 22:60276ba87ac6 1 /// Calibration procedures for determining position sensor offset,
benkatz 22:60276ba87ac6 2 /// phase ordering, and position sensor linearization
benkatz 22:60276ba87ac6 3 ///
benkatz 22:60276ba87ac6 4
benkatz 22:60276ba87ac6 5 #include "calibration.h"
benkatz 23:2adf23ee0305 6 #include "foc.h"
benkatz 23:2adf23ee0305 7 #include "PreferenceWriter.h"
benkatz 23:2adf23ee0305 8 #include "user_config.h"
benkatz 44:8040fa2fcb0d 9 #include "motor_config.h"
benkatz 44:8040fa2fcb0d 10 #include "current_controller_config.h"
benkatz 22:60276ba87ac6 11
benkatz 23:2adf23ee0305 12 void order_phases(PositionSensor *ps, GPIOStruct *gpio, ControllerStruct *controller, PreferenceWriter *prefs){
benkatz 28:8c7e29f719c5 13
benkatz 22:60276ba87ac6 14 ///Checks phase order, to ensure that positive Q current produces
benkatz 22:60276ba87ac6 15 ///torque in the positive direction wrt the position sensor.
benkatz 22:60276ba87ac6 16 printf("\n\r Checking phase ordering\n\r");
benkatz 22:60276ba87ac6 17 float theta_ref = 0;
benkatz 22:60276ba87ac6 18 float theta_actual = 0;
benkatz 47:e1196a851f76 19 float v_d = V_CAL; //Put all volts on the D-Axis
benkatz 44:8040fa2fcb0d 20 float v_q = 0.0f;
benkatz 22:60276ba87ac6 21 float v_u, v_v, v_w = 0;
benkatz 44:8040fa2fcb0d 22 float dtc_u, dtc_v, dtc_w = .5f;
benkatz 22:60276ba87ac6 23 int sample_counter = 0;
benkatz 22:60276ba87ac6 24
benkatz 22:60276ba87ac6 25 ///Set voltage angle to zero, wait for rotor position to settle
benkatz 25:f5741040c4bb 26 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); //inverse dq0 transform on voltages
benkatz 25:f5741040c4bb 27 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); //space vector modulation
benkatz 22:60276ba87ac6 28 for(int i = 0; i<20000; i++){
benkatz 27:501fee691e0e 29 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); // Set duty cycles
benkatz 27:501fee691e0e 30 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 31 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 32 wait_us(100);
benkatz 22:60276ba87ac6 33 }
benkatz 22:60276ba87ac6 34 //ps->ZeroPosition();
benkatz 47:e1196a851f76 35 ps->Sample(DT);
benkatz 23:2adf23ee0305 36 wait_us(1000);
benkatz 38:67e4e1453a4b 37 //float theta_start = ps->GetMechPositionFixed(); //get initial rotor position
benkatz 26:2b865c00d7e9 38 float theta_start;
benkatz 23:2adf23ee0305 39 controller->i_b = I_SCALE*(float)(controller->adc2_raw - controller->adc2_offset); //Calculate phase currents from ADC readings
benkatz 23:2adf23ee0305 40 controller->i_c = I_SCALE*(float)(controller->adc1_raw - controller->adc1_offset);
benkatz 23:2adf23ee0305 41 controller->i_a = -controller->i_b - controller->i_c;
benkatz 23:2adf23ee0305 42 dq0(controller->theta_elec, controller->i_a, controller->i_b, controller->i_c, &controller->i_d, &controller->i_q); //dq0 transform on currents
benkatz 23:2adf23ee0305 43 float current = sqrt(pow(controller->i_d, 2) + pow(controller->i_q, 2));
benkatz 23:2adf23ee0305 44 printf("\n\rCurrent\n\r");
benkatz 23:2adf23ee0305 45 printf("%f %f %f\n\r\n\r", controller->i_d, controller->i_q, current);
benkatz 22:60276ba87ac6 46 /// Rotate voltage angle
benkatz 25:f5741040c4bb 47 while(theta_ref < 4*PI){ //rotate for 2 electrical cycles
benkatz 25:f5741040c4bb 48 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); //inverse dq0 transform on voltages
benkatz 25:f5741040c4bb 49 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); //space vector modulation
benkatz 22:60276ba87ac6 50 wait_us(100);
benkatz 27:501fee691e0e 51 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); //Set duty cycles
benkatz 27:501fee691e0e 52 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 53 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 47:e1196a851f76 54 ps->Sample(DT); //sample position sensor
benkatz 38:67e4e1453a4b 55 theta_actual = ps->GetMechPositionFixed();
benkatz 26:2b865c00d7e9 56 if(theta_ref==0){theta_start = theta_actual;}
benkatz 22:60276ba87ac6 57 if(sample_counter > 200){
benkatz 22:60276ba87ac6 58 sample_counter = 0 ;
benkatz 22:60276ba87ac6 59 printf("%.4f %.4f\n\r", theta_ref/(NPP), theta_actual);
benkatz 22:60276ba87ac6 60 }
benkatz 22:60276ba87ac6 61 sample_counter++;
benkatz 52:8e74c22ed89f 62 theta_ref += 0.0005f;
benkatz 22:60276ba87ac6 63 }
benkatz 38:67e4e1453a4b 64 float theta_end = ps->GetMechPositionFixed();
benkatz 22:60276ba87ac6 65 int direction = (theta_end - theta_start)>0;
benkatz 52:8e74c22ed89f 66 float ratio = abs(4.0f*PI/(theta_end-theta_start));
benkatz 52:8e74c22ed89f 67 int pole_pairs = (int) roundf(ratio);
benkatz 22:60276ba87ac6 68 printf("Theta Start: %f Theta End: %f\n\r", theta_start, theta_end);
benkatz 22:60276ba87ac6 69 printf("Direction: %d\n\r", direction);
benkatz 23:2adf23ee0305 70 if(direction){printf("Phasing correct\n\r");}
benkatz 22:60276ba87ac6 71 else if(!direction){printf("Phasing incorrect. Swapping phases V and W\n\r");}
benkatz 52:8e74c22ed89f 72 printf("Pole Pairs: %d\n\r", pole_pairs);
benkatz 52:8e74c22ed89f 73 NPP = pole_pairs;
benkatz 23:2adf23ee0305 74 PHASE_ORDER = direction;
benkatz 22:60276ba87ac6 75 }
benkatz 22:60276ba87ac6 76
benkatz 22:60276ba87ac6 77
benkatz 23:2adf23ee0305 78 void calibrate(PositionSensor *ps, GPIOStruct *gpio, ControllerStruct *controller, PreferenceWriter *prefs){
benkatz 22:60276ba87ac6 79 /// Measures the electrical angle offset of the position sensor
benkatz 22:60276ba87ac6 80 /// and (in the future) corrects nonlinearity due to position sensor eccentricity
benkatz 22:60276ba87ac6 81 printf("Starting calibration procedure\n\r");
benkatz 46:2d4b1dafcfe3 82 float * error_f;
benkatz 46:2d4b1dafcfe3 83 float * error_b;
benkatz 46:2d4b1dafcfe3 84 int * lut;
benkatz 46:2d4b1dafcfe3 85 int * raw_f;
benkatz 46:2d4b1dafcfe3 86 int * raw_b;
benkatz 46:2d4b1dafcfe3 87 float * error;
benkatz 46:2d4b1dafcfe3 88 float * error_filt;
benkatz 22:60276ba87ac6 89
benkatz 25:f5741040c4bb 90 const int n = 128*NPP; // number of positions to be sampled per mechanical rotation. Multiple of NPP for filtering reasons (see later)
benkatz 47:e1196a851f76 91 const int n2 = 40; // increments between saved samples (for smoothing motion)
benkatz 25:f5741040c4bb 92 float delta = 2*PI*NPP/(n*n2); // change in angle between samples
benkatz 46:2d4b1dafcfe3 93 error_f = new float[n](); // error vector rotating forwards
benkatz 46:2d4b1dafcfe3 94 error_b = new float[n](); // error vector rotating backwards
benkatz 28:8c7e29f719c5 95 const int n_lut = 128;
benkatz 46:2d4b1dafcfe3 96 lut = new int[n_lut](); // clear any old lookup table before starting.
benkatz 46:2d4b1dafcfe3 97
benkatz 46:2d4b1dafcfe3 98 error = new float[n]();
benkatz 46:2d4b1dafcfe3 99 const int window = 128;
benkatz 46:2d4b1dafcfe3 100 error_filt = new float[n]();
benkatz 46:2d4b1dafcfe3 101 float cogging_current[window] = {0};
benkatz 46:2d4b1dafcfe3 102
benkatz 28:8c7e29f719c5 103 ps->WriteLUT(lut);
benkatz 46:2d4b1dafcfe3 104 raw_f = new int[n]();
benkatz 46:2d4b1dafcfe3 105 raw_b = new int[n]();
benkatz 22:60276ba87ac6 106 float theta_ref = 0;
benkatz 22:60276ba87ac6 107 float theta_actual = 0;
benkatz 47:e1196a851f76 108 float v_d = V_CAL; // Put volts on the D-Axis
benkatz 44:8040fa2fcb0d 109 float v_q = 0.0f;
benkatz 22:60276ba87ac6 110 float v_u, v_v, v_w = 0;
benkatz 44:8040fa2fcb0d 111 float dtc_u, dtc_v, dtc_w = .5f;
benkatz 22:60276ba87ac6 112
benkatz 22:60276ba87ac6 113
benkatz 22:60276ba87ac6 114 ///Set voltage angle to zero, wait for rotor position to settle
benkatz 25:f5741040c4bb 115 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
benkatz 25:f5741040c4bb 116 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
benkatz 22:60276ba87ac6 117 for(int i = 0; i<40000; i++){
benkatz 27:501fee691e0e 118 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); // Set duty cycles
benkatz 24:58c2d7571207 119 if(PHASE_ORDER){
benkatz 27:501fee691e0e 120 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 121 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 122 }
benkatz 22:60276ba87ac6 123 else{
benkatz 27:501fee691e0e 124 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 125 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 126 }
benkatz 22:60276ba87ac6 127 wait_us(100);
benkatz 22:60276ba87ac6 128 }
benkatz 47:e1196a851f76 129 ps->Sample(DT);
benkatz 23:2adf23ee0305 130 controller->i_b = I_SCALE*(float)(controller->adc2_raw - controller->adc2_offset); //Calculate phase currents from ADC readings
benkatz 23:2adf23ee0305 131 controller->i_c = I_SCALE*(float)(controller->adc1_raw - controller->adc1_offset);
benkatz 23:2adf23ee0305 132 controller->i_a = -controller->i_b - controller->i_c;
benkatz 23:2adf23ee0305 133 dq0(controller->theta_elec, controller->i_a, controller->i_b, controller->i_c, &controller->i_d, &controller->i_q); //dq0 transform on currents
benkatz 23:2adf23ee0305 134 float current = sqrt(pow(controller->i_d, 2) + pow(controller->i_q, 2));
benkatz 26:2b865c00d7e9 135 printf(" Current Angle : Rotor Angle : Raw Encoder \n\r\n\r");
benkatz 25:f5741040c4bb 136 for(int i = 0; i<n; i++){ // rotate forwards
benkatz 22:60276ba87ac6 137 for(int j = 0; j<n2; j++){
benkatz 22:60276ba87ac6 138 theta_ref += delta;
benkatz 25:f5741040c4bb 139 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
benkatz 25:f5741040c4bb 140 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
benkatz 27:501fee691e0e 141 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u);
benkatz 25:f5741040c4bb 142 if(PHASE_ORDER){ // Check phase ordering
benkatz 27:501fee691e0e 143 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v); // Set duty cycles
benkatz 27:501fee691e0e 144 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 145 }
benkatz 22:60276ba87ac6 146 else{
benkatz 27:501fee691e0e 147 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 148 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 149 }
benkatz 52:8e74c22ed89f 150 wait_us(200);
benkatz 47:e1196a851f76 151 ps->Sample(DT);
benkatz 22:60276ba87ac6 152 }
benkatz 47:e1196a851f76 153 ps->Sample(DT);
benkatz 38:67e4e1453a4b 154 theta_actual = ps->GetMechPositionFixed();
benkatz 22:60276ba87ac6 155 error_f[i] = theta_ref/NPP - theta_actual;
benkatz 22:60276ba87ac6 156 raw_f[i] = ps->GetRawPosition();
benkatz 22:60276ba87ac6 157 printf("%.4f %.4f %d\n\r", theta_ref/(NPP), theta_actual, raw_f[i]);
benkatz 22:60276ba87ac6 158 //theta_ref += delta;
benkatz 22:60276ba87ac6 159 }
benkatz 26:2b865c00d7e9 160
benkatz 25:f5741040c4bb 161 for(int i = 0; i<n; i++){ // rotate backwards
benkatz 22:60276ba87ac6 162 for(int j = 0; j<n2; j++){
benkatz 22:60276ba87ac6 163 theta_ref -= delta;
benkatz 25:f5741040c4bb 164 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
benkatz 25:f5741040c4bb 165 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
benkatz 27:501fee691e0e 166 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u);
benkatz 24:58c2d7571207 167 if(PHASE_ORDER){
benkatz 27:501fee691e0e 168 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 169 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 170 }
benkatz 22:60276ba87ac6 171 else{
benkatz 27:501fee691e0e 172 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_v);
benkatz 27:501fee691e0e 173 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 174 }
benkatz 52:8e74c22ed89f 175 wait_us(200);
benkatz 47:e1196a851f76 176 ps->Sample(DT);
benkatz 22:60276ba87ac6 177 }
benkatz 47:e1196a851f76 178 ps->Sample(DT); // sample position sensor
benkatz 38:67e4e1453a4b 179 theta_actual = ps->GetMechPositionFixed(); // get mechanical position
benkatz 22:60276ba87ac6 180 error_b[i] = theta_ref/NPP - theta_actual;
benkatz 22:60276ba87ac6 181 raw_b[i] = ps->GetRawPosition();
benkatz 22:60276ba87ac6 182 printf("%.4f %.4f %d\n\r", theta_ref/(NPP), theta_actual, raw_b[i]);
benkatz 22:60276ba87ac6 183 //theta_ref -= delta;
benkatz 22:60276ba87ac6 184 }
benkatz 22:60276ba87ac6 185
benkatz 22:60276ba87ac6 186 float offset = 0;
benkatz 22:60276ba87ac6 187 for(int i = 0; i<n; i++){
benkatz 25:f5741040c4bb 188 offset += (error_f[i] + error_b[n-1-i])/(2.0f*n); // calclate average position sensor offset
benkatz 22:60276ba87ac6 189 }
benkatz 25:f5741040c4bb 190 offset = fmod(offset*NPP, 2*PI); // convert mechanical angle to electrical angle
benkatz 23:2adf23ee0305 191
benkatz 22:60276ba87ac6 192
benkatz 25:f5741040c4bb 193 ps->SetElecOffset(offset); // Set position sensor offset
benkatz 23:2adf23ee0305 194 __float_reg[0] = offset;
benkatz 23:2adf23ee0305 195 E_OFFSET = offset;
benkatz 22:60276ba87ac6 196
benkatz 22:60276ba87ac6 197 /// Perform filtering to linearize position sensor eccentricity
benkatz 22:60276ba87ac6 198 /// FIR n-sample average, where n = number of samples in one electrical cycle
benkatz 22:60276ba87ac6 199 /// This filter has zero gain at electrical frequency and all integer multiples
benkatz 25:f5741040c4bb 200 /// So cogging effects should be completely filtered out.
benkatz 22:60276ba87ac6 201
benkatz 46:2d4b1dafcfe3 202
benkatz 22:60276ba87ac6 203 float mean = 0;
benkatz 25:f5741040c4bb 204 for (int i = 0; i<n; i++){ //Average the forward and back directions
benkatz 22:60276ba87ac6 205 error[i] = 0.5f*(error_f[i] + error_b[n-i-1]);
benkatz 22:60276ba87ac6 206 }
benkatz 22:60276ba87ac6 207 for (int i = 0; i<n; i++){
benkatz 22:60276ba87ac6 208 for(int j = 0; j<window; j++){
benkatz 25:f5741040c4bb 209 int ind = -window/2 + j + i; // Indexes from -window/2 to + window/2
benkatz 22:60276ba87ac6 210 if(ind<0){
benkatz 25:f5741040c4bb 211 ind += n;} // Moving average wraps around
benkatz 22:60276ba87ac6 212 else if(ind > n-1) {
benkatz 22:60276ba87ac6 213 ind -= n;}
benkatz 22:60276ba87ac6 214 error_filt[i] += error[ind]/(float)window;
benkatz 22:60276ba87ac6 215 }
benkatz 23:2adf23ee0305 216 if(i<window){
benkatz 23:2adf23ee0305 217 cogging_current[i] = current*sinf((error[i] - error_filt[i])*NPP);
benkatz 23:2adf23ee0305 218 }
benkatz 22:60276ba87ac6 219 //printf("%.4f %4f %.4f %.4f\n\r", error[i], error_filt[i], error_f[i], error_b[i]);
benkatz 22:60276ba87ac6 220 mean += error_filt[i]/n;
benkatz 22:60276ba87ac6 221 }
benkatz 25:f5741040c4bb 222 int raw_offset = (raw_f[0] + raw_b[n-1])/2; //Insensitive to errors in this direction, so 2 points is plenty
benkatz 28:8c7e29f719c5 223
benkatz 28:8c7e29f719c5 224
benkatz 23:2adf23ee0305 225 printf("\n\r Encoder non-linearity compensation table\n\r");
benkatz 46:2d4b1dafcfe3 226 printf(" Sample Number : Lookup Index : Lookup Value\n\r\n\r");
benkatz 25:f5741040c4bb 227 for (int i = 0; i<n_lut; i++){ // build lookup table
benkatz 22:60276ba87ac6 228 int ind = (raw_offset>>7) + i;
benkatz 22:60276ba87ac6 229 if(ind > (n_lut-1)){
benkatz 22:60276ba87ac6 230 ind -= n_lut;
benkatz 22:60276ba87ac6 231 }
benkatz 22:60276ba87ac6 232 lut[ind] = (int) ((error_filt[i*NPP] - mean)*(float)(ps->GetCPR())/(2.0f*PI));
benkatz 46:2d4b1dafcfe3 233 printf("%d %d %d \n\r", i, ind, lut[ind]);
benkatz 26:2b865c00d7e9 234 wait(.001);
benkatz 22:60276ba87ac6 235 }
benkatz 23:2adf23ee0305 236
benkatz 25:f5741040c4bb 237 ps->WriteLUT(lut); // write lookup table to position sensor object
benkatz 23:2adf23ee0305 238 //memcpy(controller->cogging, cogging_current, sizeof(controller->cogging)); //compensation doesn't actually work yet....
benkatz 25:f5741040c4bb 239 memcpy(&ENCODER_LUT, lut, sizeof(lut)); // copy the lookup table to the flash array
benkatz 23:2adf23ee0305 240 printf("\n\rEncoder Electrical Offset (rad) %f\n\r", offset);
benkatz 22:60276ba87ac6 241
benkatz 23:2adf23ee0305 242 if (!prefs->ready()) prefs->open();
benkatz 25:f5741040c4bb 243 prefs->flush(); // write offset and lookup table to flash
benkatz 25:f5741040c4bb 244 prefs->close();
benkatz 46:2d4b1dafcfe3 245
benkatz 46:2d4b1dafcfe3 246 delete[] error_f; //gotta free up that ram
benkatz 46:2d4b1dafcfe3 247 delete[] error_b;
benkatz 46:2d4b1dafcfe3 248 delete[] lut;
benkatz 46:2d4b1dafcfe3 249 delete[] raw_f;
benkatz 46:2d4b1dafcfe3 250 delete[] raw_b;
benkatz 23:2adf23ee0305 251
benkatz 22:60276ba87ac6 252 }