在对离轴绝对值编码器进行线性插值来解决线性度不足的问题时,发现插值后角度数据出现如下图的波浪。
可以看出插值还是有一定效果 忽略波浪的确是直了(理解万岁!) 这里有个疑问 这个波浪感觉是开环强拖的采样点间隔不准 线性插值按理说直接就是一条直线过去了 不应该是这种波浪 采样点按理说我开环强拖角度时 延时给够他就会逼进到那个点吗 但是我增加延时好像并没有啥变化
贴出我的校准函数
void calibrate(EncoderStruct *encoder, ControllerStruct *controller){
/// Measures the electrical angle offset of the position sensor
/// and (in the future) corrects nonlinearity due to position sensor eccentricity
printf("Starting calibration procedure\n\r");
float * error_f;
float * error_b;
int * lut;
int * raw_f;
int * raw_b;
const int n = 256; // number of positions to be sampled per mechanical rotation. Multiple of NPP for filtering reasons (see later)
const int n2 = 20*NPP; // increments between saved samples (for smoothing motion)
float delta = 2*PI*NPP/(n*n2); // change in angle between samples
error_f = (float *)malloc(sizeof(float)*n); // error vector rotating forwards
error_b = (float *)malloc(sizeof(float)*n); // error vector rotating backwards
if(NULL == error_f || NULL == error_b)return;
const int n_lut = 256;
lut = (int *)malloc(sizeof(int)*n_lut); // clear any old lookup table before starting.
if(NULL == lut)return;
memset(error_f, 0, sizeof(float)*n);
memset(error_b, 0, sizeof(float)*n);
memset(lut, 0, sizeof(float)*n_lut);
memcpy(encoder->offset_lut, lut, sizeof(encoder->offset_lut));
raw_f = (int *)malloc(sizeof(int)*n);
raw_b = (int *)malloc(sizeof(int)*n);
if(NULL == raw_f || NULL == raw_b)return;
memset(raw_f, 0, sizeof(int)*n);
memset(raw_b, 0, sizeof(int)*n);
float theta_ref = 0;
float theta_actual = 0;
float v_d = V_CAL; // Put volts on the D-Axis
float v_q = 0.0f;
float v_u, v_v, v_w = 0;
float dtc_u, dtc_v, dtc_w = .5f;
///Set voltage angle to zero, wait for rotor position to settle
abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
for(int i = 0; i<40000; i++){
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_U, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_u));
if(PHASE_ORDER){
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_V, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_v));
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_W, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_w));
}
else{
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_V, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_w));
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_W, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_v));
}
HAL_Delay_us(100);
}
ps_sample(encoder, DT);
controller->i_a = I_SCALE*(float)(controller->adc1_raw - controller->adc1_offset); //Calculate phase currents from ADC readings
controller->i_b = I_SCALE*(float)(controller->adc2_raw - controller->adc2_offset);
controller->i_c = -controller->i_a - controller->i_b;
dq0(controller->theta_elec, controller->i_a, controller->i_b, controller->i_c, &controller->i_d, &controller->i_q); //dq0 transform on currents
float current = sqrt(pow(controller->i_d, 2) + pow(controller->i_q, 2));
printf(" Current Angle : Rotor Angle : Raw Encoder \n\r\n\r");
int count = 0;
for(int i = 0; i<n; i++){ // rotate forwards
for(int j = 0; j<n2; j++){
theta_ref += delta;
abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_U, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_u));
if(PHASE_ORDER){
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_V, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_v));
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_W, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_w));
}
else{
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_V, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_w));
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_W, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_v));
}
HAL_Delay_us(150);
}
for(int i=0; i<5; i++){
ps_sample(encoder, DT); // sample position sensor
count += encoder->raw;
}
theta_actual = encoder->angle_multiturn[0] + M_OFFSET;
error_f[i] = theta_ref/NPP - theta_actual;
raw_f[i] = count/5;//encoder->raw;
count = 0;
printf("%d %.4f\t %.4f\t %d\r\n", i, theta_ref/(NPP), theta_actual, raw_f[i]);
}
HAL_Delay_us(150);
for(int i=0; i<5; i++){
ps_sample(encoder, DT); // sample position sensor
count += encoder->raw;
} // sample position sensor
theta_actual = encoder->angle_multiturn[0] + M_OFFSET; // get mechanical position
error_b[0] = theta_ref/NPP - theta_actual;
raw_b[0] = count/5;//encoder->raw;
count = 0;
printf("%d %.4f\t %.4f\t %d\r\n", 0, theta_ref/NPP, theta_actual, raw_b[0]);
HAL_Delay_us(150);
for(int i = 1; i<n; i++){ // rotate backwards
for(int j = 0; j<n2; j++){
theta_ref -= delta;
abc(theta_ref, v_d, v_q, &v_u, &v_v, &v_w); // inverse dq0 transform on voltages
svm(1.0, v_u, v_v, v_w, &dtc_u, &dtc_v, &dtc_w); // space vector modulation
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_U, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_u));
if(PHASE_ORDER){
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_V, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_v));
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_W, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_w));
}
else{
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_V, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_w));
__HAL_TIM_SET_COMPARE(&TIM_PWM, TIM_CH_W, ((TIM_PWM.Instance->ARR)>>1)*(1.0f-dtc_v));
}
HAL_Delay_us(150);
}
for(int i=0; i<5; i++){
ps_sample(encoder, DT); // sample position sensor
count += encoder->raw;
}
theta_actual = encoder->angle_multiturn[0] + M_OFFSET; // get mechanical position
error_b[i] = theta_ref/NPP - theta_actual;
raw_b[i] = count/5;//encoder->raw;
count =0;
printf("%d %.4f\t %.4f\t %d\r\n", i, theta_ref/(NPP), theta_actual, raw_b[i]);
}
float offset = 0;
for(int i = 0; i<n; i++){
offset += (error_f[i] + error_b[n-1-i])/(2.0f*n); // calclate average position sensor offset
}
offset = fmod(offset*NPP, 2*PI); // convert mechanical angle to electrical angle
E_OFFSET = offset;
printf("\n\rEncoder Electrical Offset (rad) %f\r\n", offset);
for (int i = 0; i<n; i++){ //Average the forward and back directions
lut[i] = 0.5f*(raw_f[i] + raw_b[n-i-1]);
printf(" %d %d \r\n", i, lut[i]);
}
printf("sample is end \r\n");
for(int i=0; i<n-1; i++){
for(int j=0; j<n-i-1; j++){
if(lut[j]>lut[j+1]){
int temp =lut[j];
lut[j] = lut[j+1];
lut[j+1] = temp;
}
}
}
ps_sample(encoder, DT);
int raw_now = encoder->raw;
for(int i = 0; i<n; i++){
if(raw_now > lut[i]){
line_index.off1 = i;
line_index.off2 = (line_index.off1+1)%256;
}
printf(" %d %d \r\n", i,lut[i]);
}
memcpy(encoder->offset_lut, lut, sizeof(encoder->offset_lut)); // write lookup table to position sensor object
memcpy(&ENCODER_LUT, lut, sizeof(encoder->offset_lut)); // copy the lookup table to the flash array
if (!preference_writer_ready(prefs)){ preference_writer_open(&prefs);}
preference_writer_flush(&prefs);
preference_writer_close(&prefs);
free(error_f); //gotta free up that ram
free(error_b);
free(lut);
free(raw_f);
free(raw_b);
}
10/12补充
经过两天调试,怀疑过采样不准不均匀等问题,然后对采样数据进行滤波调整采样点数,已经对强拖方式进行调整得到以下结论。原256个点增加到320个点没明显变换,减少到128个点有变好一点。调整强拖方法都没明显变化,有个比较显眼的地方就是波浪形波动跟速度有关,电机速度越大波浪的幅值越大频率越小,速度越小就相反。我用其他方式来拖动电机,因为电机公装的问题没法用其他电机来拖动,用了个电动手枪转来拖高低速没啥明显区别,并且没有波浪线扰动,图我放下图。补偿后的曲线有点不直,不知道是不是电动手枪转速度不均匀的导致的还是算法的问题,我个人偏向于前者。希望得到大家的帮助,谢谢!!