jake tang 2023-10-09 17:24 采纳率: 25%
浏览 53
已结题

编码器线性插值和永磁同步电机开环强拖校准如何保证强拖角度准确的问题

在对离轴绝对值编码器进行线性插值来解决线性度不足的问题时,发现插值后角度数据出现如下图的波浪。

img

可以看出插值还是有一定效果 忽略波浪的确是直了(理解万岁!) 这里有个疑问 这个波浪感觉是开环强拖的采样点间隔不准 线性插值按理说直接就是一条直线过去了 不应该是这种波浪 采样点按理说我开环强拖角度时 延时给够他就会逼进到那个点吗 但是我增加延时好像并没有啥变化

贴出我的校准函数


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个点有变好一点。调整强拖方法都没明显变化,有个比较显眼的地方就是波浪形波动跟速度有关,电机速度越大波浪的幅值越大频率越小,速度越小就相反。我用其他方式来拖动电机,因为电机公装的问题没法用其他电机来拖动,用了个电动手枪转来拖高低速没啥明显区别,并且没有波浪线扰动,图我放下图。补偿后的曲线有点不直,不知道是不是电动手枪转速度不均匀的导致的还是算法的问题,我个人偏向于前者。希望得到大家的帮助,谢谢!!

img

  • 写回答

23条回答 默认 最新

  • bug菌¹ Java领域优质创作者 2023-10-09 17:48
    关注
    获得2.00元问题酬金

    该回答引用ChatGPT,希望对题主有所帮助,如有帮助,还望采纳。


    问题描述:

    在进行离轴绝对值编码器线性插值来解决线性度不足的问题时,出现插值后角度数据出现波浪的情况。根据预期,线性插值应当得到一条直线,为什么会出现波浪?同时,在进行永磁同步电机开环强拖校准时,增加延时并没有改善强拖角度的准确性,为什么?

    解决方案:

    离轴绝对值编码器线性插值

    线性插值得到的结果受到采样点间隔的影响。如果采样点间隔不均匀,那么线性插值得到的结果就会出现波浪。此时,需要根据实际情况来选取采样点间隔,使其尽可能均匀。

    永磁同步电机开环强拖校准

    强拖角度的准确性也受到采样点间隔的影响。如果采样点间隔不均匀,那么强拖角度就会出现较大的误差。此时,也需要根据实际情况来选取采样点间隔,使其尽可能均匀。

    另外,增加延时并不能改善强拖角度的准确性。这是因为,延时只能影响采样点之间的时间间隔,而不能改变采样点的实际位置。如果采样点的实际位置不准确,那么增加延时也无济于事。因此,需要通过其他手段来保证采样点的位置准确。比如,可以通过调整电机参数或者校准编码器来达到这一目的。

    评论

报告相同问题?

问题事件

  • 系统已结题 10月17日
  • 修改了问题 10月12日
  • 创建了问题 10月9日

悬赏问题

  • ¥30 arduino vector defined in discarded section `.text' of wiring.c.o (symbol from plugin)
  • ¥20 关于#c++#的问题:(2)运算二叉树·表达式一般由一个运算符和两个操作数组成:(相关搜索:二叉树遍历)
  • ¥20 如何训练大模型在复杂因素组成的系统中求得最优解
  • ¥15 关于#r语言#的问题:在进行倾向性评分匹配时,使用“match it"包提示”错误于eval(family$initialize): y值必需满足0 <= y <= 1“请问在进行PSM时
  • ¥45 求17位带符号原码乘法器verilog代码
  • ¥20 PySide6扩展QLable实现Word一样的图片裁剪框
  • ¥15 matlab数据降噪处理,提高数据的可信度,确保峰值信号的不损失?
  • ¥15 怎么看我在bios每次修改的日志
  • ¥15 python+mysql图书管理系统
  • ¥15 Questasim Error: (vcom-13)