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: mbed-dev-f303 FastPWM3
calibration.cpp
00001 /// Calibration procedures for determining position sensor offset, 00002 /// phase ordering, and position sensor linearization 00003 /// 00004 00005 #include "calibration.h" 00006 #include "foc.h" 00007 #include "PreferenceWriter.h" 00008 #include "user_config.h" 00009 #include "motor_config.h" 00010 #include "current_controller_config.h" 00011 00012 extern Serial pc; 00013 00014 void order_phases(PositionSensor *ps, GPIOStruct *gpio, ControllerStruct *controller, PreferenceWriter *prefs){ 00015 00016 ///Checks phase order, to ensure that positive Q current produces 00017 ///torque in the positive direction wrt the position sensor. 00018 pc.printf("\n\r Checking phase ordering\n\r"); 00019 float theta_ref = 0; 00020 float theta_actual = 0; 00021 float v_d = .15f; //Put all volts on the D-Axis 00022 float v_q = 0.0f; 00023 float v_u, v_v, v_w = 0; 00024 float dtc_u, dtc_v, dtc_w = .5f; 00025 int sample_counter = 0; 00026 00027 ///Set voltage angle to zero, wait for rotor position to settle 00028 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); //inverse dq0 transform on voltages 00029 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); //space vector modulation 00030 for(int i = 0; i<20000; i++){ 00031 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); // Set duty cycles 00032 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v); 00033 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w); 00034 wait_us(100); 00035 } 00036 //ps->ZeroPosition(); 00037 ps->Sample(DT); 00038 wait_us(1000); 00039 //float theta_start = ps->GetMechPositionFixed(); //get initial rotor position 00040 float theta_start; 00041 controller->i_b = I_SCALE*(float)(controller->adc2_raw - controller->adc2_offset); //Calculate phase currents from ADC readings 00042 controller->i_c = I_SCALE*(float)(controller->adc1_raw - controller->adc1_offset); 00043 controller->i_a = -controller->i_b - controller->i_c; 00044 dq0(controller->theta_elec, controller->i_a, controller->i_b, controller->i_c, &controller->i_d, &controller->i_q); //dq0 transform on currents 00045 float current = sqrt(pow(controller->i_d, 2) + pow(controller->i_q, 2)); 00046 pc.printf("\n\rCurrent\n\r"); 00047 pc.printf("%f %f %f\n\r\n\r", controller->i_d, controller->i_q, current); 00048 /// Rotate voltage angle 00049 while(theta_ref < 4*PI){ //rotate for 2 electrical cycles 00050 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); //inverse dq0 transform on voltages 00051 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); //space vector modulation 00052 wait_us(100); 00053 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); //Set duty cycles 00054 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v); 00055 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w); 00056 ps->Sample(DT); //sample position sensor 00057 theta_actual = ps->GetMechPositionFixed(); 00058 if(theta_ref==0){theta_start = theta_actual;} 00059 if(sample_counter > 200){ 00060 sample_counter = 0 ; 00061 pc.printf("%.4f %.4f\n\r", theta_ref/(NPP), theta_actual); 00062 } 00063 sample_counter++; 00064 theta_ref += 0.001f; 00065 } 00066 float theta_end = ps->GetMechPositionFixed(); 00067 int direction = (theta_end - theta_start)>0; 00068 pc.printf("Theta Start: %f Theta End: %f\n\r", theta_start, theta_end); 00069 pc.printf("Direction: %d\n\r", direction); 00070 if(direction){pc.printf("Phasing correct\n\r");} 00071 else if(!direction){pc.printf("Phasing incorrect. Swapping phases V and W\n\r");} 00072 PHASE_ORDER = direction; 00073 } 00074 00075 00076 void calibrate(PositionSensor *ps, GPIOStruct *gpio, ControllerStruct *controller, PreferenceWriter *prefs){ 00077 /// Measures the electrical angle offset of the position sensor 00078 /// and (in the future) corrects nonlinearity due to position sensor eccentricity 00079 pc.printf("Starting calibration procedure\n\r"); 00080 00081 const int n = 128*NPP; // number of positions to be sampled per mechanical rotation. Multiple of NPP for filtering reasons (see later) 00082 const int n2 = 50; // increments between saved samples (for smoothing motion) 00083 float delta = 2*PI*NPP/(n*n2); // change in angle between samples 00084 float error_f[n] = {0}; // error vector rotating forwards 00085 float error_b[n] = {0}; // error vector rotating backwards 00086 const int n_lut = 128; 00087 int lut[n_lut]= {0}; // clear any old lookup table before starting. 00088 ps->WriteLUT(lut); 00089 int raw_f[n] = {0}; 00090 int raw_b[n] = {0}; 00091 float theta_ref = 0; 00092 float theta_actual = 0; 00093 float v_d = .15f; // Put volts on the D-Axis 00094 float v_q = 0.0f; 00095 float v_u, v_v, v_w = 0; 00096 float dtc_u, dtc_v, dtc_w = .5f; 00097 00098 00099 ///Set voltage angle to zero, wait for rotor position to settle 00100 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages 00101 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation 00102 for(int i = 0; i<40000; i++){ 00103 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); // Set duty cycles 00104 if(PHASE_ORDER){ 00105 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v); 00106 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w); 00107 } 00108 else{ 00109 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_v); 00110 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_w); 00111 } 00112 wait_us(100); 00113 } 00114 ps->Sample(DT); 00115 controller->i_b = I_SCALE*(float)(controller->adc2_raw - controller->adc2_offset); //Calculate phase currents from ADC readings 00116 controller->i_c = I_SCALE*(float)(controller->adc1_raw - controller->adc1_offset); 00117 controller->i_a = -controller->i_b - controller->i_c; 00118 dq0(controller->theta_elec, controller->i_a, controller->i_b, controller->i_c, &controller->i_d, &controller->i_q); //dq0 transform on currents 00119 float current = sqrt(pow(controller->i_d, 2) + pow(controller->i_q, 2)); 00120 pc.printf(" Current Angle : Rotor Angle : Raw Encoder \n\r\n\r"); 00121 for(int i = 0; i<n; i++){ // rotate forwards 00122 for(int j = 0; j<n2; j++){ 00123 theta_ref += delta; 00124 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages 00125 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation 00126 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); 00127 if(PHASE_ORDER){ // Check phase ordering 00128 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v); // Set duty cycles 00129 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w); 00130 } 00131 else{ 00132 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_v); 00133 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_w); 00134 } 00135 wait_us(100); 00136 ps->Sample(DT); 00137 } 00138 ps->Sample(DT); 00139 theta_actual = ps->GetMechPositionFixed(); 00140 error_f[i] = theta_ref/NPP - theta_actual; 00141 raw_f[i] = ps->GetRawPosition(); 00142 pc.printf("%.4f %.4f %d\n\r", theta_ref/(NPP), theta_actual, raw_f[i]); 00143 //theta_ref += delta; 00144 } 00145 00146 for(int i = 0; i<n; i++){ // rotate backwards 00147 for(int j = 0; j<n2; j++){ 00148 theta_ref -= delta; 00149 abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages 00150 svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation 00151 TIM1->CCR3 = (PWM_ARR>>1)*(1.0f-dtc_u); 00152 if(PHASE_ORDER){ 00153 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_v); 00154 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_w); 00155 } 00156 else{ 00157 TIM1->CCR1 = (PWM_ARR>>1)*(1.0f-dtc_v); 00158 TIM1->CCR2 = (PWM_ARR>>1)*(1.0f-dtc_w); 00159 } 00160 wait_us(100); 00161 ps->Sample(DT); 00162 } 00163 ps->Sample(DT); // sample position sensor 00164 theta_actual = ps->GetMechPositionFixed(); // get mechanical position 00165 error_b[i] = theta_ref/NPP - theta_actual; 00166 raw_b[i] = ps->GetRawPosition(); 00167 pc.printf("%.4f %.4f %d\n\r", theta_ref/(NPP), theta_actual, raw_b[i]); 00168 //theta_ref -= delta; 00169 } 00170 00171 float offset = 0; 00172 for(int i = 0; i<n; i++){ 00173 offset += (error_f[i] + error_b[n-1-i])/(2.0f*n); // calclate average position sensor offset 00174 } 00175 offset = fmod(offset*NPP, 2*PI); // convert mechanical angle to electrical angle 00176 00177 00178 ps->SetElecOffset(offset); // Set position sensor offset 00179 __float_reg[0] = offset; 00180 E_OFFSET = offset; 00181 00182 /// Perform filtering to linearize position sensor eccentricity 00183 /// FIR n-sample average, where n = number of samples in one electrical cycle 00184 /// This filter has zero gain at electrical frequency and all integer multiples 00185 /// So cogging effects should be completely filtered out. 00186 00187 float error[n] = {0}; 00188 const int window = 128; 00189 float error_filt[n] = {0}; 00190 float cogging_current[window] = {0}; 00191 float mean = 0; 00192 for (int i = 0; i<n; i++){ //Average the forward and back directions 00193 error[i] = 0.5f*(error_f[i] + error_b[n-i-1]); 00194 } 00195 for (int i = 0; i<n; i++){ 00196 for(int j = 0; j<window; j++){ 00197 int ind = -window/2 + j + i; // Indexes from -window/2 to + window/2 00198 if(ind<0){ 00199 ind += n;} // Moving average wraps around 00200 else if(ind > n-1) { 00201 ind -= n;} 00202 error_filt[i] += error[ind]/(float)window; 00203 } 00204 if(i<window){ 00205 cogging_current[i] = current*sinf((error[i] - error_filt[i])*NPP); 00206 } 00207 //printf("%.4f %4f %.4f %.4f\n\r", error[i], error_filt[i], error_f[i], error_b[i]); 00208 mean += error_filt[i]/n; 00209 } 00210 int raw_offset = (raw_f[0] + raw_b[n-1])/2; //Insensitive to errors in this direction, so 2 points is plenty 00211 00212 00213 pc.printf("\n\r Encoder non-linearity compensation table\n\r"); 00214 pc.printf(" Sample Number : Lookup Index : Lookup Value : Cogging Current Lookup\n\r\n\r"); 00215 for (int i = 0; i<n_lut; i++){ // build lookup table 00216 int ind = (raw_offset>>7) + i; 00217 if(ind > (n_lut-1)){ 00218 ind -= n_lut; 00219 } 00220 lut[ind] = (int) ((error_filt[i*NPP] - mean)*(float)(ps->GetCPR())/(2.0f*PI)); 00221 pc.printf("%d %d %d %f\n\r", i, ind, lut[ind], cogging_current[i]); 00222 wait(.001); 00223 } 00224 00225 ps->WriteLUT(lut); // write lookup table to position sensor object 00226 //memcpy(controller->cogging, cogging_current, sizeof(controller->cogging)); //compensation doesn't actually work yet.... 00227 memcpy(&ENCODER_LUT, lut, sizeof(lut)); // copy the lookup table to the flash array 00228 pc.printf("\n\rEncoder Electrical Offset (rad) %f\n\r", offset); 00229 00230 if (!prefs->ready()) prefs->open(); 00231 prefs->flush(); // write offset and lookup table to flash 00232 prefs->close(); 00233 00234 00235 }
Generated on Wed Jul 13 2022 15:44:18 by
1.7.2