天天看點

步進電機S型曲線加減速算法與實作

一年前做過的S型曲線加減速算法,再次做的時候竟然犯錯,在此總結記錄一下,友善以後查閱,同時希望幫助初學者提供簡單的參考資料(注:本項目采用的帶細分的驅動器,MCU的OC比較輸出子產品産生50%的PWM方波)。

S型曲線的的方程

步進電機S型曲線加減速算法與實作

,在[-5,5]的圖形如下圖所示:

步進電機S型曲線加減速算法與實作

如要将此曲線應用在步進電機的加、減速過程中,需要将方程在XY坐标系進行平移,同時對曲線進行拉升變化:

步進電機S型曲線加減速算法與實作

其中的A分量在y方向進行平移,B分量在y方向進行拉伸,ax+b分量在x方向進行平移和拉伸。

項目中加速過程:從5600Hz加速到64000Hz,采用4細分。輸出比較子產品所用的定時器驅動頻率為10M,采用1000個點進行加速處理。最終根據項目的需要,在加速過程中采用的曲線方程為:

步進電機S型曲線加減速算法與實作

其中的Fcurrent為length(1000)個點中的單個頻率值。Fmin起始頻率為5600; Fmax為最大頻率64000;  -flexible*(i - num)/num是對S型曲線進行拉伸變化,其中flexible代表S曲線區間(越大代表壓縮的最厲害,中間(x坐标0點周圍)加速度越大;越小越接近勻加速。理想的S曲線的取值為4-6),i是在循環計算過程中的索引,從0開始,num為 length/2 大小(這樣可以使得S曲線對稱)。在項目中i的區間[0,1000), num=1000/2=500。這些參數均可以修改。提供的計算接口如下。

對應的計算接口code:

void CalculateSModelLine(float fre[],  unsigned short period[],   float  len,  float fre_max,  float fre_min, float flexible)

{

    int i=0;

    float deno ;

    float melo ;

    float delt = fre_max-fre_min;

    for(; i<len; i++)

    {

        melo = flexible * (i-len/2) / (len/2);

        deno = 1.0 / (1 + expf(-melo));   //expf is a library function of exponential(e) 

        fre[i] = delt * deno + fre_min;

        period[i] = (unsigned short)(10000000.0 / fre[i]);    // 10000000 is the timer driver frequency

    }

    return ;

}

// start move motor

void StartPWM()

{

    DriverMotorFlag = TRUE;

    Index = 0;

    MOTOR_EN_DISABLE = ENABLE;

    OpenOC4(OC_ON | OC_TIMER_MODE16 | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

    // map rc13 to oc4 output

    RPC13R = 11;

    // 50 percent duty

    OC4RS = OC_PERIOD_MIN / 2;

    OpenTimer3(T3_ON | T3_PS_1_8, OC_PERIOD_MIN);

    INTSetVectorPriority(INT_TIMER_3_VECTOR, INT_PRIORITY_LEVEL_6);

    INTSetVectorSubPriority(INT_TIMER_3_VECTOR, INT_SUB_PRIORITY_LEVEL_1);

    EnableIntT3;

}

//stop motor, hereis no deceleration 

void StopPWM()

{

    DriverMotorFlag = FALSE;

    Index = 0;

    MOTOR_EN_DISABLE = DISENABLE;

    OpenOC4(OC_OFF | OC_TIMER_MODE16 | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

    // map rc13 to oc4 output

    RPC13R = 0;

    PORTCbits.RC13 = 0;

    CloseTimer3();

    DisableIntT3;

}

//change the timer Period value in the correspond timer rather than the other place, Or the motor will be stalled occasionally.

// 剛開始我在另外的一個定時器中斷中每隔1ms改變 應用在OC子產品的timer3 的Period值,結構偶發的造成電機在加速過程中堵轉。其實應該是在timer3的中斷中修改。

static unsigned short CountForAcc = 0;

void __ISR(_TIMER_3_VECTOR, ipl6) Timer3OutHandler(void)

{

    // clear the interrupt flag, or the interrupt will not occur again.

    mT3ClearIntFlag();

    if(CountForAcc++ > 2)    // here can adjust the totally time of acceleration

    {

        CountForAcc = 0;

        //if(DriverMotorFlag == TRUE && PR3 > OC_PERIOD_MAX + SPEED_STEP)

        if(DriverMotorFlag == TRUE && Index < ACC_TIMES)

        {

            PR3 = Period[Index++];

            OC4RS = PR3 / 2;

        }

    }

}

通過CalculateSModelLine接口得到如下不同的幾條加速曲線:

黃色:CalculateSModelLine(Freq, Period, 1000, 56000, 16000, 4);

橙色:CalculateSModelLine(Freq, Period, 1000, 64000, 500, 8);

藍色:CalculateSModelLine(Freq, Period, 1000, 64000, 500, 15);

灰色:CalculateSModelLine(Freq, Period, 1000, 40000, 500, 5);

步進電機S型曲線加減速算法與實作

最後可以估算加速過程的時間和角位移,以橙色曲線為例:CalculateSModelLine(Freq, Period, 1000, 64000, 500, 8)為例(假設在中斷中沒有  if(CountForAcc++ > 2)  條件限制):

時間:Period第一個點的值為10000000/500 = 20000,最後也點的值 10000000/64000=156,平均值為10000左右,timer中斷的平均時間Tn=10000/10000000=1ms, 1000個點,總時間為1s,當然,起始頻率大加速時間就越短,比如Fmin=16000Hz,Fmax=64000,則40ms左右即可完成加速過程。

角位移:1.8(單步) * 1000(步數) / 4(細分)= 450°

上述為加速過程,減速同樣的道理,隻要将方程改為: 

步進電機S型曲線加減速算法與實作

可以得到減速曲線如下所示:

步進電機S型曲線加減速算法與實作

以上為實際的項目資料,歡迎各位指正。

繼續閱讀