如何在 MCSDK 5.x 中增加絕對位置編碼器

前言
當前MC SDK5.x中支持的關於編碼器(Encoder)為增量編碼器,即有A,B,Z信號的編碼器,主要為光編碼器;在市場中有些應用(比如無人機雲台,伺服,醫療)已經在廣泛使用磁編碼器,輸出的是絕對位置,而想取得位置信息,或者通過取樣絕對位置傳感的PWM脈寬,或者需要通過通訊方式進行獲取,比如SPI,I2C,UART等等;當前MC SDK5.x還未對這個部分直接支持,需要通過修改程序實現絕對位置編碼器的應用,本文使用STM32F303RE-Nucleo控制說明。

       

當導體通電後放入磁場中,由於磁場的作用導體上流動的電荷就會因為受到由磁場感應產生的洛倫茲力而發生流通路徑的偏移,這樣在垂直於電流方向上如果去測量的Y1,Y2點電壓,將產生電勢差,這個就是所說的霍爾效應;如果使用ADC對Y1,Y2點進行測量標定即可以反推磁場變化;



打開有絕對位置編碼器的電機可以看到轉子上有一個同步旋轉的磁石,同時有檢測晶片用於絕對角度輸出,絕對位置編碼器晶片輸出PWM波或者內部做通訊輸出,單片機可以讀取相關信息得到到當前轉子的角度。



1. 準備工作
為了方便調試,首先使用無傳感控制(Sensor-less)將電機閉環運行起來,如果電機合適,並且使用的是ST的電機Demo板,可以使用ST的Motor Profiler(30KHzPWM)進行無傳感電機參數以及轉動參數識別,可以很快將電機無傳感轉 動起來;
如果使用客戶自製板子,則按照ST的操作說明,使用MCWorkbench將電機閉環無傳感轉動起來,電機閉環轉動過程可以確保硬體軟體的完備性;注意這邊生成的CubeMx工程文件*.ioc文件,後面我們添加程序會使用到;
為了便於調試可增加兩路DAC,比如使用STM32F303則直接使用兩路輸出的DAC,如果該晶片上沒有DAC模塊,可 以使用TIMER+RC濾波電路模擬輸出DAC;下圖為使用DAC配置,需要配置為Userdefined DAC1/2。


絕對編碼器晶片角度信息讀取

絕對編碼器的輸出可以為PWM波形輸出,也可以為通訊埠輸出,比如UART,SPI,I2C等等,本文以SPI輸出以及PWM輸出為例做說明
 

2. 角度以及速度標定

2.1 電角度標定
 
因為我們讀取的角度為機械角度,在控制過程中我們用到的是電角度,因此還要做一下變換,將機械角度數據變為電角度數據;使用公式為:



在程序中需要量化為Q16格式後得到電角度範圍[−180°~180°];即[-32768~32767]

2.2 速度計算


3. 編碼器SPI輸出模式

3.1 CubeMx配置

打開MCWorkbench生成的*.ioc文件,配置SPI模塊,這邊我們使用SPI3接收,配置參數需要參考編碼器晶片的說明,這 邊以AS5048A為例,如下配置,配置PB10作為片選信號CS輸出




3.2 重新生成代碼

3.3 編寫SPI讀取代碼

根據編碼器晶片的數據手冊編寫SPI讀取代碼,調試代碼以便讀取到角度信息,因為是外設配置,本文對此部分不做具體說 明;可以參考spi_pwm_encoder.c文件,得到角度信息後進行機械角度轉變為電角度的計算;
#define ENCODER_SPI_MAX 16384 
#define POLES 11
/*
* Calculate electrical angle based on motor, data in Q16 format
* 16384 stand for 360degree(65536)*motor poles
*/
SPI_EIAngle = (int16_t)((65536*SPI_Angle_Digital*POLES)/ENCODER_SPI_MAX)%65536;​
SPI_Angle_Digital為通過SPI讀取的電角度數字量,ENCODER_SPI_MAX為最大數字量輸出,比如14-bit精度的輸出,這個數據為16384。

3.4 創建絕對值編碼器的結構體

創建結構體,包含SpeednPosFdbk_Handle_t的通用組件,並且定義私有成員變量,用於絕對位置編碼器的控制以及參量計算,在abs_encoder_pos_fdbk.c中進行初始化動作
/**   
* @brief Abs encoder component parameters definition
*/
typedef struc​
{
SpeednPosFdbk_Handle_t _Super;
int16_t Encoder_EIAngle; /* Encoder final electrical angle */
int16_t Encoder_MecAngle; /* Encoder final mechanical angle */

int16_t Encoder_AngleD_Pre; /* Encoder previous digital angle */
int16_t Encoder_AngleD_Now; /* Encoder present/now digital angle */
int16_t Encoder_Speed_RPM; /* Speed uint in RPM */
int16_t Encoder_Average_Speed_RPM; /* Average speed unit in RPM*/

bool SensorIsReliable;
uint8_t mode;

int32_t Circle_Counter; /* Count the circle for motro run */
bool Middle_Flag; /* Middle flag, 1--arrived pass middle*/

} Abs_Encoder_Handle_t;
3.5 絕對值編碼器函數編寫
參照encoder_speed_pos_fdbk.c文件編寫對應的絕對值編碼器的代碼,接口函數對應起來,這樣可以有效的集成擴展, 分別定義:
1)    初始化函數Abs_Encoder_Init
2)    清除函數Abs_Encoder_Clear
3)    絕對值編碼器讀取電角度函數Abs_Encoder_GetElAngle
4)    讀取機械角度函數Abs_Encoder_GetMecAngle
5)    得到電機平均機械速度函數  Abs_Encoder_GetAvrgMecSpeed01Hz
6)    計算電機平均機械速度函數  Abs_Encoder_CalcAvrgMecSpeed01Hz

3.6 添加絕對位置編碼器代碼

3.6.1 絕對位置編碼器速度計算

參照2.2公式進行速度計算

/* Speed_RPM = Deta(angle)*60*f/65536 */ 
pHandle->Encoder_Speed_RPM = (int16_t)((int32_t)(pHandle-
>Encoder_AngleD_Now - pHandle->Encoder_AngleD_Pre * 60 * SPEED_LOOP_FREQUENCY_HZ/65536);​
3.6.2 添加編碼器初始化代碼
在mc_task.c文件的MCboot()函數中增加初始化代碼
Abs_Encoder_Init(&Abs_Encoder_M1); // Initial absolute encoder sensor 
Abs_Encoder_M1.mode = SENSOR_SPI;​

3.6.3 角度以及速度的代碼添加

中頻任務TSK_MediumFrequencyTaskM1中加入絕對編碼器的角度以及速度計算函數

Abs_Encoder_CalcAvrgMecSpeed01Hz(&Abs_Encoder_M1, &wAux );​

3.7 判斷絕對位置編碼器角度準確性
使用DAC對角度進行判讀,在mc_task.c中TSK_HighFrequencyTask()函數中增加UserDAC數據更新,一個DAC輸出無 傳感觀測器輸出的電角度,另外一路輸出絕對值編碼器計算出的電角度。
/* DAC output*/ 
extern UI_Handle_t * pDAC;
static int16_t temp1;
static int16_t temp2;

temp1 = FOCVars[M1].hElAngle;
temp2 = Abs_Encoder_M1.Encoder_EIAngle;

DAC_SetUserChannelValue(pDAC, DAC_USER1, temp1);
DAC_SetUserChannelValue(pDAC, DAC_USER2, temp2);​
程序修改完成後編譯下載,讓電機工作在無傳感閉環模式,示波器連接DAC兩路輸出。
如果出現下面波形,則需要交換其中任意兩條電機線,或者在程序中加入負號即可;

下面的圖為正確的DAC輸出波形,可以看到黃色為無傳感器觀測器輸出電角度,藍色為計算得到的絕對位置編碼器輸出計算結果,兩者基本重合,如果出現吻合度非常差,波形錯開很多情況下,有兩種措施,要麼和電機廠商溝通做準確的零點校準, 要麼自行增加角度補償。


3.8 絕對位置角度閉環程序修改
3.8.1 修改電角度賦值
修改mc_task.c中TSK_MediumFrequencyTaskM1()函數,由無傳感方式獲得電角度改為絕對位置編碼器的轉換完成的電角度,並且返回對應的速度值;
#if defined(ABS_ENCODER_MODE) 
Abs_Encoder_CalcAvrgMecSpeed01Hz(&Abs_Encoder_M1, &wAux );
IsSpeedReliable = 1;
#else
Abs_Encoder_CalcAvrgMecSpeed01Hz(&Abs_Encoder_M1, &wAux );
IsSpeedReliable = STO_PLL_CalcAvrgMecSpeedUnit( &STO_PLL_M1, &wAux );
#endif​

3.8.2 屏蔽無傳感電角度計算

修改 mc_task.c 中 TSK_HighFrequencyTask() 函數,只保留

MC_FOC_DURATION這個判斷,其他都可以屏蔽掉。

hFOCreturn = FOC_CurrController(M1); 
if(hFOCreturn == MC_FOC_DURATION)
{
STM_FaultProcessing(&STM[M1], MC_FOC_DURATION, 0);
}​


3.8.3 修改速度傳感器為絕對編碼傳感器
 

修改 mc_task.c 中 TSK_MediumFrequencyTaskM1()函數,傳感器設定修改為絕對編碼器
case CLEAR:   
FOCVars[M1].bDriveInput = INTERNAL;
STC_SetSpeedSensor( pSTC[M1], &Abs_Encoder_M1._Super );

if ( STM_NextState( &STM[M1], START ) == true )
{
FOC_Clear( M1 );

R3_2_SwitchOnPWM( pwmcHandle[M1] );
}
break;​


3.8.4 修改狀態跳轉

因為開始就直接是閉環運行,因此需要修改mc_task.c中
TSK_MediumFrequencyTaskM1()函數,狀態START下,只需要一條跳轉語句,其他刪除或者屏蔽掉
case START:      
STM_NextState( &STM[M1], START_RUN );
break ;​

同樣在狀態START_RUN下,也只需要一條跳轉語句。

case START_RUN:     
STM_NextState( &STM[M1], RUN );
break ;​

3.9 絕對編碼器力矩閉環運行電機
以上修改完成後,重新編譯下載後就可以直接運行電機了,電機需要工作在力矩模式,如果使用GUI進行控制,則切換到Torque模式,同時設定Iqref數據,500這個數據計算來自於電機最大支持電流數字量(比如5000)的10%,可以逐漸增加這個數據,直到電機能夠運轉起來。

如果程序控制電機運行則可以寫為下面代碼
MC_ProgramTorqueRampMotor1(500,1000); 
MC_StartMotor1();​

3.10  絕對編碼器速度閉環運行電機

速度輸出已經在上面的中頻任務中計算得到,可以在無傳感模式下對編碼器速度輸出做調試,看輸出速度是否和無傳感匹配,如果匹配後可以轉入絕對編碼器的速度閉環控制


如果程序控制電機運行則可以寫為下面代碼
MC_ProgramSpeedRampMotor1 (600/6,1000); // 600RPM 
MC_StartMotor1();​

3.11 使用絕對編碼器做位置環
3.11.1 框架說明

以表貼電機為例,一般的FOC電機控制是兩環控制,速度環+電流環的控制方式,速度環為外環,電流環為內環,Idref = 0(d軸電流參考為0)的控制為常見控制;參考速度環輸出參考轉矩後供後端電流環路;

 

如果增加位置環最簡單和直接的方式即為將速度環換為位置環,即變為位置環+電流環的方式:



 
3.11.2  計算說明
為了方便控制,以及考慮精度問題,角度單位為rad*10000,比如電機轉動10圈,也就是10圈後的位置,則該位置的設定角度為:
           
             θset=10∗2?∗10000≈628320
 

位置環採用的是線性係數乘以係數直接輸出到速度的參考:

 

             ????=??∗(??−??)

 

             ??−位置環係數

             ?? −設定的位置

             ??−當前的位置

 

當前位置的角度數字量計算如下:

 

             ??=???∗2∗??∗10000+??

 

            ??? –絕對值編碼器轉過的整圈數

            ??−當前的機械角度的數字量

            ?? −取值3.1416

 

3.11.3 位置控制改進

在三環控制中,不可避免的會涉及到加速度的計算,正常控制過程為:加速、勻速、減速、定位過程。

那麼會涉及到加速度以及定位階段的控制,這邊我們可以按照加速度與速度差成反比,而定位階段可以直接設定速度為0,但是實際使用過程中我們會發現直接直接的速度模式在定位階段力量有限。
方法一:PID 需要特別設定,更能夠定位到給定位置;
方法二:拋開速度環,直接力矩控制;


3.11.4 增加以下變量或函數用於位置環控制

    1) 位置環PID 結構體PID_Handle_t PIDAngleHandle_M1
    2) 位置控制的結構體Position_Handle_t
    3) 位置角度誤差Position_GetErrorAngle
    4) 位置環速度參考輸出計算Position_CalcSpeedReferrence
    5) 位置環力矩參考輸出計算Position_CalcTorqueReferrence

3.11.5 增加位置控制程序

在mc_task.c的中頻任務函數TSK_MediumFrequencyTaskM1中增加位置環差值數據計算,根據差值計算,當差值在閾值之上的話進行速度控制,在RUN下調用下面函數:
/* Get error position/Angle, unit in rad*10000 */ 
Position_GetErrorAngle(&Abs_Encoder_M1,Target_Angle);
……
Position_CalcSpeedReferrence()​

如果差值縮小到一定範圍內,則進行力矩控制,在函數FOC_CalcCurrRef中進行調用。

__weak void FOC_CalcCurrRef(uint8_t bMotor) 
{
if(FOCVars[bMotor].bDriveInput == INTERNAL)
{
#if defined(POSITION_CONTROL)
/* If in position torque mode, Iqref come from Angle PID*/
if(Position_M1.Mode_Flag == P_TORQUE_MODE)
{
FOCVars[bMotor].hTeref = Position_CalcTorqueReferrence();
FOCVars[bMotor].Iqdref.q = FOCVars[bMotor].hTeref;
}
else
#endif
{
FOCVars[bMotor].hTeref = STC_CalcTorqueReference(pSTC[bMotor]);
FOCVars[bMotor].Iqdref.q = FOCVars[bMotor].hTeref;
}
}
}​


3.11.6 實際運行效果

位置偏差較大時,電機加速到最大速度,偏差小時將進入力矩控制模式,直到目標位置,在目標位置直接力矩鎖定。

設定位置角度值在0<- ->15708000(電機轉動250圈) 實際速度與參考速度曲線。

3.12 測試說明

spi_pwm_encoder.h中提供了測試宏定義

    A無傳感運行,用於測試絕對值編碼器,如下宏定義

//#define ABS_ENCODER_MODE 
//#define POSITION_CONTROL
#define ENCODER_SPI_MODE
//#define ENCODER_PWM_MODE​

    B,絕對值編碼器,SPI輸出模式的閉環運行

#define ABS_ENCODER_MODE 
//#define POSITION_CONTROL
#define ENCODER_SPI_MODE
//#define ENCODER_PWM_MODE​

     C,加入位置環後的三環運行

#define ABS_ENCODER_MODE 
#define POSITION_CONTROL
#define ENCODER_SPI_MODE
//#define ENCODER_PWM_MODE​

4.  編碼器PWM輸出模式

一般編碼器的PWM都是以固定頻率輸出,占空比代表角度,Duty的範圍為0—T,也就是0—360度(機械角度);

4.1 CubeMx配置

編碼器的PWM輸出可以直接使用ST晶片的TIMER PWM捕獲功能獲取PWM波的頻率(用於計算電角度)和占空比(機械角度信息);這邊我們使用TIM2;打開MC workbench生成的*.ioc文件,修改TIM2為PWM捕獲輸入:


將TIM2捕獲輸入通道1配置為Rising Edge,通道2為間接捕獲輸入(實際是TIM2_CH1的內部輸出),配置為Falling Edge,同時我們看到PA15(TIM2_CH1)已經被配置;通道1為頻率捕獲,通道2為占空比捕獲;


使能TIM2中斷

編輯中斷優先級

因為TIM2中斷不能妨礙電機運行,因此需要修改中斷優先級為搶占等級為3



4.2 重新生成代碼



在生成代碼的main.c中增加通道使能代碼,TIM2(32-bit)工作在72MHz,如果默認編碼器1K PWM,CCR1計數數值為 72MHz/1KHz = 72000
/* In PWM mode, use Tim2 PWM capture mode to get frequency and duty cycle, 
* CCR1 value is the frequency of PWM, can be used as calibration value.
* CCR2 value is for digital angle
* In this demo, TIM2 work under 72MHz
*/
HAL_TIM_Base_Start(&htim2);
HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);​


4.3 編寫電角度轉換讀取代碼

void PWM_Encoder_EIangle(uint32_t data) 
{
PWM_Angle_Digital = data;
if(PWM_Angle_Digital > ENCODER_PWM_MAX)
PWM_Angle_Digital = ENCODER_PWM_MAX;
PWM_EIAngle = (int16_t)((65536*PWM_Angle_Digital*POLES)/ENCODER_PWM_MAX)%65536;
}​

在TIM2的中斷服務中讀取CCR2寄存器內容,為防止誤動作,這邊CCR1數據標定為ENCODER_PWM_MAX,可以仿真條件下讀取這個數據,如果編碼器準確1KHz PWM輸出這個數據為72000,如果為其他數據可以進行對應修改;

#define ENCODER_PWM_MAX 67039 //72000 

void TIM2_IRQHandler(void)
{
PWM_Encoder_EIangle(TIM2->CCR2);
Encoder_EIAngle = PWM_EIAngle;
Encoder_MecAngle = (int16_t)(PWM_Angle_Digital*65536/ENCODER_PWM_MAX);
} ​

4.4 判斷絕對位置編碼器角度準確性

    同3.7所描述

 

4.5 絕對位置角度閉環程序修改

    同3.8,3.9,3.10的描述

 

4.6使用絕對編碼器做位置環

   參照 3.11 中的具體操作

技術文檔

類型標題檔案
軟件SPI_ENCODER

★博文內容參考自 網站,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

參考來源

false: https://c.51diantang.com/coursedetail?id=98decd6ebbb44beaab1b2e30b82136ed&column_id=2ab86a9228814c09a9621d3a970b21ac

評論