電機驅動是很常見的應用,在很多系統中我們都會碰到需要改變電機的速度以實現相應的控制功能,這就涉及到電機速度曲線規划的問題。在這篇中我們就來簡單討論一下電機的梯形曲線規划的問題。
1、基本原理
梯形速度曲線控制算法是工業控制領域應用最為廣泛的加減速控制策略之一。所謂梯形速度曲線將整個運動過程分為勻加速、勻速和勻減速三個階段,在變速過程中加速度保持不變。
從變速過程中加速度保持不變這特點來說,其加減速過程其實是一個線性過程。我們可以采用一個線性函數來描述它。
這一線性函數,具體到我們的加減速過程中就是速度與時間的函數關系,函數結果就是我們某一時刻的速度,變量就是時間,斜率就是加速度,初始速度就是截距,具體如下:
這一函數表達的是連續的,但實際使用中我們需要離散化處理,我們必定以一定的時間間隔來處理速度的增加問題。這樣實際的速度變化就不可能是連續的,而是階梯狀的,具體如下:
為了速度的變化盡量平緩,我們需要盡可能地讓時間間隔小一些,這其實是我們在考慮編寫程序時需要處理的一個參數。
2、設計與實現
我們已經簡單描述了S型速度規划曲線的數學原理及應用表達式。接下來我們來考慮怎么實現它。
考慮到在同一個驅動器中可能因為應用場景的需要存在多條的速度規划曲線。所以我們以基於對象的思路來考慮它,這樣我們在更換不同的曲線就只需要更換不同的曲線實力就可以了。所以我們先來分析一下曲線對象的屬性和操作。
鑒於前面的分析,我們認為作為一個調速曲線對象至少要記錄:開始調速時的初始速度、當前速度、目標速度、加速度、最大速度、最小速度、調速時間、調速時間跨度、曲線類型等,我們將這些記為對象的屬性。據此我們可以定義電機速度曲線的對象類型為:
/* 定義電機速度曲線對象 */
typedef struct CurveObject {
float startSpeed; //開始調速時的初始速度
float currentSpeed; //當前速度
float targetSpeed; //目標速度
float stepSpeed; //加速度
float speedMax; //最大速度
float speedMin; //最小速度
uint32_t aTimes; //調速時間
uint32_t maxTimes; //調速跨度
SpeedCurveType curveMode; //曲線類型
}CurveObjectType;
我們已經定義了一個速度曲線對象類型,接下來我們就來分析如何實現一個T型調速曲線。我們已經描述過,速度其實就是時間的函數,根據我們前面分析的速度時間的函數表達式,我們實現如下:
void (*pCalCurve[])(CurveObjectType *curve)={CalCurveNone,CalCurveTRAP,CalCurveSPTA};
/* 電機曲線加減速操作-------------------------------------------------------- */
void MotorVelocityCurve(CurveObjectType *curve)
{
float temp=0;
if(curve->targetSpeed>curve->speedMax)
{
curve->targetSpeed=curve->speedMax;
}
if(curve->targetSpeed<curve->speedMin)
{
curve->targetSpeed=curve->speedMin;
}
if((fabs(curve->currentSpeed-curve->startSpeed)<=curve->stepSpeed)&&(curve->maxTimes==0))
{
if(curve->startSpeed<curve->speedMin)
{
curve->startSpeed=curve->speedMin;
}
temp=fabs(curve->targetSpeed-curve->startSpeed);
temp=temp/curve->stepSpeed;
curve->maxTimes=(uint32_t)(temp)+1;
curve->aTimes=0;
}
if(curve->aTimes<curve->maxTimes)
{
pCalCurve[curve->curveMode](curve);
curve->aTimes++;
}
else
{
curve->currentSpeed=curve->targetSpeed;
curve->maxTimes=0;
curve->aTimes=0;
}
}
/*梯形曲線速度計算*/
static void CalCurveTRAP(CurveObjectType *trap)
{
float slope=0.0;
slope=(trap->targetSpeed-trap->startSpeed)/trap->maxTimes;
trap->currentSpeed=trap->startSpeed+slope*trap->aTimes;
if(trap->currentSpeed>trap->speedMax)
{
trap->currentSpeed=trap->speedMax;
}
if(trap->currentSpeed<trap->speedMin)
{
trap->currentSpeed=trap->speedMin;
}
}
在這個實現中,我們出於更普遍的實用性考慮,將各種曲線的相同操作集成在一起,然后將它們差異的部分通過曲線類型屬性以回調函數的方式集成。
3、應用與驗證
我們實現了T形電機速度規划曲線的基本設計與實現。接下來,我們就是用這一調速曲線來實現一個電機調速的實例。我們定義速度規划曲線時,是及與對象的思想來實現的,所以我們先聲明一條曲線對象實例。
CurveObjectType curve; //電機調速曲線
在聲明了這一曲線對象后,我們需要對其初始化賦值才能正確的使用。大多數的屬性直接根據應用對象的要求給予初始值就可以了。需要注意的是曲線類型這一屬性,這將決定使用什么樣的速度規划曲線。該屬性為SpeedCurveType枚舉,該枚舉定義如下:
/* 定義電機速度曲線類型枚舉 */
typedef enum SpeedCurve {
CURVE_NONE=0, //直啟
CURVE_TRAP=1, //梯形曲線
CURVE_SPTA=2 //S型曲線
}SpeedCurveType;
在這里我們需要將曲線類型初始化為T形速度規划曲線。具體操作如下:
curve.curveMode=CURVE_TRAP;
初始化完成之后就可以使用曲線對象來實現電機速度的調節了。使用也很簡單,只要按一定的時間周期調用我們前面實現的MotorVelocityCurve函數就可以實現整個調速過程。具體如下:
MotorVelocityCurve(&curve);
在每次調速開始之前都需要設置取下的開始速度和目標速度,這樣函數就會按照設定的起始速度和目標速度實現速度調整。
4、小結
我們實現了梯形加減速曲線,並使用其實現了具體的應用。總體來說,當我們將參數設置的合適時,所起到的效果也是非常明顯的。在我們的實際使用過程中,梯形曲線對大多數的應用基本都合適。不僅是在啟動和停車過程,在運行過程中如果速度設定發生改變,也會調用曲線實現加減速過程。
梯形速度曲線雖說實現簡單,在一般的應用場合也能有不錯的效果,但實際上還是有一定的問題。梯形速度曲線的加速度是一個常量,這就造成加速度的變化過程並不連續,在加減速階段和勻速運動階段的連接部分,加速度會發生突變,而這種突變可能會對控制目標產生沖擊,而有些應用場合這種沖擊是不允許的。