BLDC motor driver

Dependencies:   mbed-dev-f303 FastPWM3

Committer:
benkatz
Date:
Fri Mar 31 18:24:46 2017 +0000
Revision:
22:60276ba87ac6
Child:
23:2adf23ee0305
Encoder autocalibration for dc offset and harmonics

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 22:60276ba87ac6 6
benkatz 22:60276ba87ac6 7
benkatz 22:60276ba87ac6 8 void order_phases(PositionSensor *ps, GPIOStruct *gpio){
benkatz 22:60276ba87ac6 9 ///Checks phase order, to ensure that positive Q current produces
benkatz 22:60276ba87ac6 10 ///torque in the positive direction wrt the position sensor.
benkatz 22:60276ba87ac6 11
benkatz 22:60276ba87ac6 12 printf("\n\r Checking phase ordering\n\r");
benkatz 22:60276ba87ac6 13 float theta_ref = 0;
benkatz 22:60276ba87ac6 14 float theta_actual = 0;
benkatz 22:60276ba87ac6 15 float v_d = .2; //Put all volts on the D-Axis
benkatz 22:60276ba87ac6 16 float v_q = 0.0;
benkatz 22:60276ba87ac6 17 float v_u, v_v, v_w = 0;
benkatz 22:60276ba87ac6 18 float dtc_u, dtc_v, dtc_w = .5;
benkatz 22:60276ba87ac6 19 int sample_counter = 0;
benkatz 22:60276ba87ac6 20
benkatz 22:60276ba87ac6 21 ///Set voltage angle to zero, wait for rotor position to settle
benkatz 22:60276ba87ac6 22 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); //inverse dq0 transform on voltages
benkatz 22:60276ba87ac6 23 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); //space vector modulation
benkatz 22:60276ba87ac6 24 for(int i = 0; i<20000; i++){
benkatz 22:60276ba87ac6 25 TIM1->CCR3 = 0x708*(1.0f-dtc_u); // Set duty cycles
benkatz 22:60276ba87ac6 26 TIM1->CCR2 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 27 TIM1->CCR1 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 28 wait_us(100);
benkatz 22:60276ba87ac6 29 }
benkatz 22:60276ba87ac6 30 //ps->ZeroPosition();
benkatz 22:60276ba87ac6 31 ps->Sample();
benkatz 22:60276ba87ac6 32 float theta_start = ps->GetMechPosition(); //get initial rotor position
benkatz 22:60276ba87ac6 33
benkatz 22:60276ba87ac6 34 /// Rotate voltage angle
benkatz 22:60276ba87ac6 35 while(theta_ref < 4*PI){ //rotate for 2 electrical cycles
benkatz 22:60276ba87ac6 36 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); //inverse dq0 transform on voltages
benkatz 22:60276ba87ac6 37 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); //space vector modulation
benkatz 22:60276ba87ac6 38 wait_us(100);
benkatz 22:60276ba87ac6 39 TIM1->CCR3 = 0x708*(1.0f-dtc_u); //Set duty cycles
benkatz 22:60276ba87ac6 40 TIM1->CCR2 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 41 TIM1->CCR1 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 42 ps->Sample(); //sample position sensor
benkatz 22:60276ba87ac6 43 theta_actual = ps->GetMechPosition();
benkatz 22:60276ba87ac6 44 if(sample_counter > 200){
benkatz 22:60276ba87ac6 45 sample_counter = 0 ;
benkatz 22:60276ba87ac6 46 printf("%.4f %.4f\n\r", theta_ref/(NPP), theta_actual);
benkatz 22:60276ba87ac6 47 }
benkatz 22:60276ba87ac6 48 sample_counter++;
benkatz 22:60276ba87ac6 49 theta_ref += 0.001f;
benkatz 22:60276ba87ac6 50 }
benkatz 22:60276ba87ac6 51 float theta_end = ps->GetMechPosition();
benkatz 22:60276ba87ac6 52 int direction = (theta_end - theta_start)>0;
benkatz 22:60276ba87ac6 53 printf("Theta Start: %f Theta End: %f\n\r", theta_start, theta_end);
benkatz 22:60276ba87ac6 54 printf("Direction: %d\n\r", direction);
benkatz 22:60276ba87ac6 55 if(direction){printf("Phaseing correct\n\r");}
benkatz 22:60276ba87ac6 56 else if(!direction){printf("Phasing incorrect. Swapping phases V and W\n\r");}
benkatz 22:60276ba87ac6 57 gpio->phasing = direction;
benkatz 22:60276ba87ac6 58
benkatz 22:60276ba87ac6 59 }
benkatz 22:60276ba87ac6 60
benkatz 22:60276ba87ac6 61
benkatz 22:60276ba87ac6 62
benkatz 22:60276ba87ac6 63 void calibrate(PositionSensor *ps, GPIOStruct *gpio){
benkatz 22:60276ba87ac6 64 /// Measures the electrical angle offset of the position sensor
benkatz 22:60276ba87ac6 65 /// and (in the future) corrects nonlinearity due to position sensor eccentricity
benkatz 22:60276ba87ac6 66
benkatz 22:60276ba87ac6 67 printf("Starting calibration procedure\n\r");
benkatz 22:60276ba87ac6 68
benkatz 22:60276ba87ac6 69 const int n = 128*NPP; // number of positions to be sampled per mechanical rotation. Multiple of NPP for filtering reasons (see later)
benkatz 22:60276ba87ac6 70 const int n2 = 10; // increments between saved samples (for smoothing motion)
benkatz 22:60276ba87ac6 71 float delta = 2*PI*NPP/(n*n2); // change in angle between samples
benkatz 22:60276ba87ac6 72 float error_f[n] = {0}; // error vector rotating forwards
benkatz 22:60276ba87ac6 73 float error_b[n] = {0}; // error vector rotating backwards
benkatz 22:60276ba87ac6 74 int raw_f[n] = {0};
benkatz 22:60276ba87ac6 75 int raw_b[n] = {0};
benkatz 22:60276ba87ac6 76 float theta_ref = 0;
benkatz 22:60276ba87ac6 77 float theta_actual = 0;
benkatz 22:60276ba87ac6 78 float v_d = .2; // Put volts on the D-Axis
benkatz 22:60276ba87ac6 79 float v_q = 0.0;
benkatz 22:60276ba87ac6 80 float v_u, v_v, v_w = 0;
benkatz 22:60276ba87ac6 81 float dtc_u, dtc_v, dtc_w = .5;
benkatz 22:60276ba87ac6 82
benkatz 22:60276ba87ac6 83
benkatz 22:60276ba87ac6 84 ///Set voltage angle to zero, wait for rotor position to settle
benkatz 22:60276ba87ac6 85 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
benkatz 22:60276ba87ac6 86 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
benkatz 22:60276ba87ac6 87 for(int i = 0; i<40000; i++){
benkatz 22:60276ba87ac6 88 TIM1->CCR3 = 0x708*(1.0f-dtc_u); // Set duty cycles
benkatz 22:60276ba87ac6 89 if(gpio->phasing){
benkatz 22:60276ba87ac6 90 TIM1->CCR2 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 91 TIM1->CCR1 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 92 }
benkatz 22:60276ba87ac6 93 else{
benkatz 22:60276ba87ac6 94 TIM1->CCR1 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 95 TIM1->CCR2 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 96 }
benkatz 22:60276ba87ac6 97 wait_us(100);
benkatz 22:60276ba87ac6 98 }
benkatz 22:60276ba87ac6 99 ps->Sample();
benkatz 22:60276ba87ac6 100
benkatz 22:60276ba87ac6 101 for(int i = 0; i<n; i++){ // rotate forwards
benkatz 22:60276ba87ac6 102 for(int j = 0; j<n2; j++){
benkatz 22:60276ba87ac6 103 theta_ref += delta;
benkatz 22:60276ba87ac6 104 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
benkatz 22:60276ba87ac6 105 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
benkatz 22:60276ba87ac6 106 TIM1->CCR3 = 0x708*(1.0f-dtc_u);
benkatz 22:60276ba87ac6 107 if(gpio->phasing){
benkatz 22:60276ba87ac6 108 TIM1->CCR2 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 109 TIM1->CCR1 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 110 }
benkatz 22:60276ba87ac6 111 else{
benkatz 22:60276ba87ac6 112 TIM1->CCR1 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 113 TIM1->CCR2 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 114 }
benkatz 22:60276ba87ac6 115 wait_us(100);
benkatz 22:60276ba87ac6 116 ps->Sample();
benkatz 22:60276ba87ac6 117 }
benkatz 22:60276ba87ac6 118 ps->Sample();
benkatz 22:60276ba87ac6 119 theta_actual = ps->GetMechPosition();
benkatz 22:60276ba87ac6 120 error_f[i] = theta_ref/NPP - theta_actual;
benkatz 22:60276ba87ac6 121 raw_f[i] = ps->GetRawPosition();
benkatz 22:60276ba87ac6 122 printf("%.4f %.4f %d\n\r", theta_ref/(NPP), theta_actual, raw_f[i]);
benkatz 22:60276ba87ac6 123 //theta_ref += delta;
benkatz 22:60276ba87ac6 124 }
benkatz 22:60276ba87ac6 125 for(int i = 0; i<n; i++){ // rotate backwards
benkatz 22:60276ba87ac6 126 for(int j = 0; j<n2; j++){
benkatz 22:60276ba87ac6 127 theta_ref -= delta;
benkatz 22:60276ba87ac6 128 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
benkatz 22:60276ba87ac6 129 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
benkatz 22:60276ba87ac6 130 TIM1->CCR3 = 0x708*(1.0f-dtc_u);
benkatz 22:60276ba87ac6 131 if(gpio->phasing){
benkatz 22:60276ba87ac6 132 TIM1->CCR2 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 133 TIM1->CCR1 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 134 }
benkatz 22:60276ba87ac6 135 else{
benkatz 22:60276ba87ac6 136 TIM1->CCR1 = 0x708*(1.0f-dtc_v);
benkatz 22:60276ba87ac6 137 TIM1->CCR2 = 0x708*(1.0f-dtc_w);
benkatz 22:60276ba87ac6 138 }
benkatz 22:60276ba87ac6 139 wait_us(100);
benkatz 22:60276ba87ac6 140 ps->Sample();
benkatz 22:60276ba87ac6 141 }
benkatz 22:60276ba87ac6 142 ps->Sample(); // sample position sensor
benkatz 22:60276ba87ac6 143 theta_actual = ps->GetMechPosition(); // get mechanical position
benkatz 22:60276ba87ac6 144 error_b[i] = theta_ref/NPP - theta_actual;
benkatz 22:60276ba87ac6 145 raw_b[i] = ps->GetRawPosition();
benkatz 22:60276ba87ac6 146 printf("%.4f %.4f %d\n\r", theta_ref/(NPP), theta_actual, raw_b[i]);
benkatz 22:60276ba87ac6 147 //theta_ref -= delta;
benkatz 22:60276ba87ac6 148 }
benkatz 22:60276ba87ac6 149
benkatz 22:60276ba87ac6 150 float offset = 0;
benkatz 22:60276ba87ac6 151 for(int i = 0; i<n; i++){
benkatz 22:60276ba87ac6 152 offset += (error_f[i] + error_b[n-1-i])/(2.0f*n); // calclate average position sensor offset
benkatz 22:60276ba87ac6 153 }
benkatz 22:60276ba87ac6 154 offset = fmod(offset*NPP, 2*PI); // convert mechanical angle to electrical angle
benkatz 22:60276ba87ac6 155 printf("Encoder Electrical Offset (rad) %f\n\r", offset);
benkatz 22:60276ba87ac6 156
benkatz 22:60276ba87ac6 157 ps->SetElecOffset(offset); // Set position sensor offset
benkatz 22:60276ba87ac6 158
benkatz 22:60276ba87ac6 159 /// Perform filtering to linearize position sensor eccentricity
benkatz 22:60276ba87ac6 160 /// FIR n-sample average, where n = number of samples in one electrical cycle
benkatz 22:60276ba87ac6 161 /// This filter has zero gain at electrical frequency and all integer multiples
benkatz 22:60276ba87ac6 162 /// So cogging should also be completely filtered out.
benkatz 22:60276ba87ac6 163
benkatz 22:60276ba87ac6 164 float error[n] = {0};
benkatz 22:60276ba87ac6 165 int window = 128;
benkatz 22:60276ba87ac6 166 float error_filt[n] = {0};
benkatz 22:60276ba87ac6 167 float mean = 0;
benkatz 22:60276ba87ac6 168 for (int i = 0; i<n; i++){ //Average the forward and back directions
benkatz 22:60276ba87ac6 169 error[i] = 0.5f*(error_f[i] + error_b[n-i-1]);
benkatz 22:60276ba87ac6 170 }
benkatz 22:60276ba87ac6 171 for (int i = 0; i<n; i++){
benkatz 22:60276ba87ac6 172 for(int j = 0; j<window; j++){
benkatz 22:60276ba87ac6 173 int ind = -window/2 + j + i; // Indexes from -window/2 to + window/2
benkatz 22:60276ba87ac6 174 if(ind<0){
benkatz 22:60276ba87ac6 175 ind += n;} // Moving average wraps around
benkatz 22:60276ba87ac6 176 else if(ind > n-1) {
benkatz 22:60276ba87ac6 177 ind -= n;}
benkatz 22:60276ba87ac6 178 error_filt[i] += error[ind]/(float)window;
benkatz 22:60276ba87ac6 179 }
benkatz 22:60276ba87ac6 180 //printf("%.4f %4f %.4f %.4f\n\r", error[i], error_filt[i], error_f[i], error_b[i]);
benkatz 22:60276ba87ac6 181 mean += error_filt[i]/n;
benkatz 22:60276ba87ac6 182 }
benkatz 22:60276ba87ac6 183 int raw_offset = (raw_f[0] + raw_b[n-1])/2; //Insensitive to errors in this direction, so 2 points is plenty
benkatz 22:60276ba87ac6 184 const int n_lut = 128;
benkatz 22:60276ba87ac6 185 int lut[n_lut];
benkatz 22:60276ba87ac6 186 for (int i = 0; i<n_lut; i++){ // build lookup table
benkatz 22:60276ba87ac6 187 int ind = (raw_offset>>7) + i;
benkatz 22:60276ba87ac6 188 if(ind > (n_lut-1)){
benkatz 22:60276ba87ac6 189 ind -= n_lut;
benkatz 22:60276ba87ac6 190 }
benkatz 22:60276ba87ac6 191 lut[ind] = (int) ((error_filt[i*NPP] - mean)*(float)(ps->GetCPR())/(2.0f*PI));
benkatz 22:60276ba87ac6 192 printf("%d %d %d %d\n\r", raw_offset>>7, i, ind, lut[ind]);
benkatz 22:60276ba87ac6 193 }
benkatz 22:60276ba87ac6 194 ps->WriteLUT(lut); // write lookup table to position sensor object
benkatz 22:60276ba87ac6 195
benkatz 22:60276ba87ac6 196
benkatz 22:60276ba87ac6 197
benkatz 22:60276ba87ac6 198
benkatz 22:60276ba87ac6 199
benkatz 22:60276ba87ac6 200
benkatz 22:60276ba87ac6 201 }