摘要:有刷電機結構簡單開發久技術成熟響應速度快,起動扭矩大運行平穩,起制動效果好控制精度高使用成本低,維修方便而無刷電機由于無電刷,具有低干擾噪音低運轉順暢壽命長低維護成本等優點。電機控制方式力矩控制指定電機提供設置大小的力矩。
電機作為一種能將電能轉化為機械能的裝置,其在制造、醫療、運動控制等等許多地方都起著重要的作用。想學習了解機器人的小伙伴,從電機了解起走也是一條不錯(坎坷)的道路。
???其實電機對于我來說是接觸的比較多了的,記得小時候玩四驅車,就特意將“馬達”拆開來看過想搞懂原理,也多帶帶將電機拿出來制作了一些小的diy,后來到了高中在學到了電磁學,算是了解了基礎的原理了(在不停的刷題后),再后來到大學就是真正的使用了。第一次使用應該是在大一買的單片機,配了一個電機,有程序可以進行調速,但當時由于一些原因,沒有再去使用。又到了大三,學習了電機拖動,對電機的認識又深了一點,也做了一些關于電機的實驗。但是,令我難以忘記的是研究生開始調試電機的時候,真的是…一言難盡,之前也參考過許多大佬的博客,所以想把自己的這段難忘的經歷做個總結,也給有需要的朋友一個參考。
按電源種類分為:直流電機和交流電機。我們常見常用的電機大多是直流電機,相比前者,交流電機不需要換向器和電刷轉換電流方向,與直流電機相比它的結構更簡單,功率更大,在工業領域被廣泛應用
根據有無電刷分為:有刷電機和無刷電機。有刷電機結構簡單、開發久技術成熟、響應速度快,起動扭矩大、運行平穩,起制動效果好、控制精度高、使用成本低,維修方便;而無刷電機由于無電刷,具有低干擾、噪音低、運轉順暢、壽命長、低維護成本等優點。于是我接觸的以無刷電機為主。
根據有無反饋分為:步進電機和伺服電機。前者沒有反饋信號,位置精度不夠高,且轉速遠遠小于后者。在需要精確的控制,伺服電機更加常用。
| |
由于位置是速度的積分,所以三種控制方式的控制框圖是有要求的,下面是一種常見的控制結構圖,當然,如果只針對某一兩種控制模式,其控制方案將比這個更加簡易。
????為了方便用戶的使用,市面上許多電機都是針對上面的控制方式進行了封裝的,也就是我們常聽說的——控制器。控制器的控制方案有許多,針對不同的控制環也有不同的控制方案,例如:對于電流環,有FOC矢量控制,速度、位置環有PID。當然,也有其他的控制算法,但這里我們就使用常用的就行了?,F在我們也可以開始談談標題了。
????PID 是一種傳統且經典的控制算法,在工程中應用非常廣泛,相比其他高大上甚至只存在于 paper 上的算法, PID 是非常接地氣的。
????PID ,即:Proportional(比例)、Integral(積分)、Differential(微分)的縮寫。顧名思義,PID 控制算法是結合比例、積分和微分的融合怪,其規律可以描述為:
u ( t ) = K p ( e ( t ) + 1 T t ∫ 0 t e ( t ) d t + T d d e ( t ) d t u(t)=K_p(e(t)+/frac{1}{T_t}/int_0^t e(t)dt+T_d/frac{de(t)}{dt} u(t)=Kp?(e(t)+Tt?1?∫0t?e(t)dt+Td?dtde(t)?
????其中 K p K_p Kp? 是比例增益, T t T_t Tt? 是積分時間常數, T d T_d Td? 是微分時間常數, u ( t ) u(t) u(t) 是輸入信號, e ( t ) e(t) e(t) 是誤差。
????三個環節在控制中也分別起著不同的控制作用。
比例環節 P:比例環節與穩態誤差相關,比例環節越大,上升速度越快,且穩態誤差越小,但無論怎樣多大都會存在誤差,不能消除誤差,而且過大還會導致震蕩,反而不穩定
積分環節 I:積分環節則可以消除誤差,合適的積分環節可以很快的消除誤差,但是設置較大會產生超調,并且過大也會導致震蕩,從而不穩定
微分環節 D:微分環節具有預測作用,可以預測信號的變化方向,從而可以減小超調,提高響應速度,但過大會導致系統不穩定
matlab PID 的參考代碼如下(上面的圖是在下面代碼基礎上修改了一點,但是核心沒有變):
%% 說明% 被控系統: 1/(0.1s+1)% 控制器: PID%%clc,clearts=0.001; %采樣時間=0.001ssys=tf(1,[0.1,1]); %建立被控對象傳遞函數dsys=c2d(sys,ts,"z") % 離散化[num,den]=tfdata(dsys,"v"); % 得到差分方程系數 y(k) = -den[2]*y(k-1) + num[2]*u(k-1)e_last=0; %前一時刻的偏差 E_integ=0; %累積偏差u_last=0.0; %前一時刻的控制量y_last=0; %前一時刻的輸出% PID參數kp=1; ki=0;kd=0;u=zeros(1,10000); %設置仿真長度time=zeros(1,10000); %時刻點(設定10000個)for k=1:1:10000 time(k)=k*ts; %時間 r(k)=100; %期望值 y(k)=-1*den(2)*y_last + num(2)*u_last; %系統響應輸出序列 e(k)=r(k)-y(k); %誤差信號 u(k)=kp*e(k)+ki*E_integ+kd*(e(k)-e_last); %系統PID控制器輸出序列 E_integ=E_integ+e(k); %誤差的累加和 u_last=u(k); %前一個的控制器輸出值 y_last=y(k); %前一個的系統響應輸出值 e_last=e(k); %前一個誤差信號的值endp1=plot(time,r,"-.");xlim([0,1]);hold on; %指令信號的曲線(即期望輸入)p2=plot(time,y,"--");xlim([0,1]); %不含積分分離的PID曲線hold on;
????上面的 PID公示 是針對連續情況下的,而在生活中,我們常常使用的是離散型的變量,比如時間,于是我們需要將 PID 的公式進行離散化,根據離散化的方法不同,PID 控制的公式就有兩種,即位置式 PID 和增量式 PID,
????常見的調參方式是比較快樂的,直接在生產商寫好的驅動下進行參數的設置以及測試,找到合適的參數,更有的還有調參軟件,遍歷參數尋找合適的參數,從而省去人工調試的復雜環節。
????但這里想要分享的調參方法要多一點步驟,但是大體方向是不變的,這里以 Tmotor 的 AK10-9 與 大疆的 M2006 兩款無刷直流電機為例子進行介紹。
????Tmotor 的電機本來是有調參軟件的,但是最開始的時候由于資料不完善,加上他的控制環不符合我們的應用要求,所以我們需要進行簡單的修改。
Tmotor 的運動控制框圖如下,可以看到他的電流環采用 FOC 矢量控制,我們不能修改,另外兩個環,速度環和位置環,只有比例環節,不能達到無誤差的目標,所以我們需要在他的電流環上進行編寫封裝。
我們需要的控制環應該如下:
下面我們先編寫控制程序。
之前探討過離散 PID 有位置式 PID 算法和增量式 PID 算法,下面是根據其公式編寫的 PID 程序,在使用之前需要稍稍修改一下參數。
位置式 PID
********************位置式 PID***************************** 輸入參數:電機電流速度位置等反饋值fed ***********************************************************typedef struct PID{ float target; //目標參考值 float deadband; //定義電機死區 float err_now; //定義當前誤差 float err_last; //定義上一時刻誤差 float kp; //比例環節系數 float ki; //積分環節系數 float kd; //微分環節系數,這里已將時間常數包含進去 float Pout; //比例環節輸出 float Iout; //積分環節輸出 float Dout; //微分環節輸出 float IntegLimt; //設置積分限幅 float output; //輸出量 float OutputLimt;//輸出限幅}PID_PARM;//初始化PID參數的函數void PID_parm_Init(PID_PARM *PID_parm,float target,float kp,float ki,float kd,float IntegLimt,float OutputLimt){ PID_parm->target = target; PID_parm->err_now = 0; PID_parm->err_last = 0; PID_parm->kp = kp; PID_parm->ki = ki; PID_parm->kd = kd; PID_parm->Pout = 0; PID_parm->Iout = 0; PID_parm->Dout = 0; PID_parm->IntegLimt = IntegLimt; PID_parm->output = 0; PID_parm->OutputLimt = OutputLimt;}//計算PID的函數float PID_cal(PID_PARM *pid_parm,float feedback){ pid_parm->err_now = pid_parm->target - feedback; pid_parm->Pout = pid_parm->kp*pid_parm->err_now; pid_parm->Iout += pid_parm->ki*pid_parm->err_now; pid_parm->Dout = pid_parm->kd*(pid_parm->err_now-pid_parm->err_last); //積分限幅 if(pid_parm->Iout > pid_parm->IntegLimt) pid_parm->Iout = pid_parm->IntegLimt; else if(pid_parm->Iout < -pid_parm->IntegLimt) pid_parm->Iout = -pid_parm->IntegLimt; //輸出限幅 pid_parm->output = pid_parm->Pout + pid_parm->Iout + pid_parm->Dout; if(pid_parm->output > pid_parm->OutputLimt) pid_parm->output = pid_parm->OutputLimt; else if(pid_parm->output < -pid_parm->OutputLimt) pid_parm->output = -pid_parm->OutputLimt; //數據更新 pid_parm->err_last = pid_parm->err_now; return pid_parm->output;}float u; PID_PARM pid_parm;PID_parm_Init(&pid_parm,10,1,0.1,,0.5,50,100); //這里的參數隨機給的,具體參數需要調節u = PID_cal(&pid_parm,fed); //計算出來的下一次輸入
增量式 PID
********************增量式 PID***************************** 輸入參數:電機電流速度位置等反饋值fed ***********************************************************typedef struct PID{ float target; //目標參考值 float deadband; //定義電機死區 float err_now; //定義當前誤差 float err_last; //定義上一時刻誤差 float err_llast; //定義上上時刻誤差 float kp; //比例環節系數 float ki; //積分環節系數 float kd; //微分環節系數,這里已將時間常數包含進去 float Pout; //比例環節輸出 float Iout; //積分環節輸出 float Dout; //微分環節輸出 float output; //輸出增量 float output_last; //上一次輸出的增量 float OutputLimt; //輸出限幅}PID_PARM;//初始化PID參數的函數void PID_parm_Init(PID_PARM *PID_parm,float target,float kp,float ki,float kd,float OutputLimt){ PID_parm->target = target; PID_parm->err_now = 0; PID_parm->err_last = 0; PID_parm->err_llast = 0; PID_parm->kp = kp; PID_parm->ki = ki; PID_parm->kd = kd; PID_parm->Pout = 0; fPID_parm->Iout = 0; PID_parm->Dout = 0; PID_parm->output = 0; PID_parm->output_last = 0; PID_parm->OutputLimt = OutputLimt;}//計算PID的函數float PID_cal(PID_PARM *pid_parm,float feedback){ pid_parm->err_now = pid_parm->target - feedback; pid_parm->Pout = pid_parm->kp*(pid_parm->err_now - pid_parm->err_last); pid_parm->Iout = pid_parm->ki*pid_parm->err_now; pid_parm->Dout = pid_parm->kd*(pid_parm->err_now - 2*pid_parm->err_last + pid_parm->err_llast); //輸出限幅 pid_parm->output += pid_parm->Pout + pid_parm->Iout + pid_parm->Dout; if(pid_parm->output > pid_parm->OutputLimt) pid_parm->output = pid_parm->OutputLimt; else if(pid_parm->output < -pid_parm->OutputLimt) pid_parm->output = -pid_parm->OutputLimt; //數據更新 pid_parm->err_llast = pid_parm->err_last; pid_parm->err_last = pid_parm->err_now; pid_parm->output_last = pid_parm->output; return pid_parm->output;}float u; PID_PARM pid_parm;PID_parm_Init(&pid_parm,10,1,0.1,,0.5,100); //這里的參數隨機給的,具體參數需要調節u = PID_cal(&pid_parm,fed); //計算出來的下一次輸入
這里采用的 stm32 進行控制的,工程文件全部在下面:
key.h
#ifndef __KEY_H#define __KEY_H #include "sys.h" /*下面的方式是通過直接操作庫函數方式讀取IO*/#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) //PE4#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) //PE3 #define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) //PE2#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) //PA0#define KEY0_PRES 1#define KEY1_PRES 2#define KEY2_PRES 3#define WKUP_PRES 4void KEY_Init(void); //IO初始化u8 KEY_Scan(u8); //按鍵掃描函數 #endif
can.h
#ifndef __CAN_H#define __CAN_H #include "sys.h" void CAN1_Init(void);//CAN1初始化 u8 CAN1_Send_Msg(u8* msg); //發送數據 u8 CAN1_Receive_Msg(u8 *buf);#endif
pid.h
#ifndef __PID_H#define __PID_H #include "sys.h" #include "stdlib.h"typedef struct PID{ float target; //目標參考值 float deadband; //定義電機死區 float err_now; //定義當前誤差 float err_last; //定義上一時刻誤差 float err_llast; //定義上上時刻誤差 float kp; //比例環節系數 float ki; //積分環節系數 float kd; //微分環節系數,這里已將時間常數包含進去 float Pout; //比例環節輸出 float Iout; //積分環節輸出 float Dout; //微分環節輸出 float IntegLimt; //設置積分限幅 float output; //輸出量 float output_last; //上一次輸出的增量 float OutputLimt; //輸出限幅}PID_PARM;void PID_parm_Init(PID_PARM *PID_parm,float target,float deadband,float kp,float ki,float kd,float IntegLimt,float OutputLimt);float Pos_PID_cal(PID_PARM *pid_parm,float feedback);float Inc_PID_cal(PID_PARM *pid_parm,float feedback);void PID_init(PID_PARM *Spd_PID,PID_PARM *Pos_PID);#endif
motor.h
#ifndef __MOTOR_H#define __MOTOR_H #include "sys.h" #include "pid.h"#define pi 3.1415926#define P_MAX 12.5#define P_MIN -12.5#define V_MAX 46.57#define V_MIN -46.57#define KP_MAX 500#define KP_MIN 0#define KD_MAX 5#define KD_MIN 0#define T_MAX 54#define T_MIN -54extern u8 Tmotor_Mod_Buf[3][8];typedef enum{ Tmotor_Open = 0xfc, Tmotor_Close = 0xfd, Tmotor_SetZero = 0xfe,}Tmotor_Mod;typedef struct{ u8 id; // id int16_t speed_rps; // rad/s int16_t real_torque; // 反饋力矩 uint16_t angle; // 絕對角度}Tmotor_measure_t;extern Tmotor_measure_t TmotorData; // 保存Tmotor電機的狀態int float_to_uint(float x, float x_min, float x_max, int bits);float uint_to_float(int x_int, float x_min, float x_max, int bits);float limitf(float val, float min_val, float max_val);void Tmotor_mod(u8 mod);void get_Tmotor_measure(Tmotor_measure_t *ptr, CanRxMsg *Rxmsg);u8 set_Tmotor_torque(float torque);void Tmotor_Speed_Control(PID_PARM
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/125303.html
摘要:起因及介紹在處理原始對賬文件的時候,我將數據歸類后批量存入相應的表中。結論事務只能管著開啟事務的線程,其他子線程出了問題都感知不到,所以在多線程環境操作要慎重。高頻容易搞死服務器,低頻會阻塞自身程序。重試次數和超時時間根據業務情況設置。 起因及介紹 在處理原始對賬文件的時候,我將數據歸類后批量存入相應的表中。在持久化的時候,用了parallelStream(),想著同時存入很多表這樣可...
摘要:力矩控制模式電機在運行過程的電流,始終等于給定的值。設定電流為零,彈簧不被拉伸。比如機械臂從點運動到點,并限制揮舞過程中的最大速度和最大力矩。 目錄 說明一、電機...
摘要:一硬件框架與模型設計機械臂最核心的部分應該就是關節部分的伺服電機了,針對與文稿中的設計思路,每個伺服電機都為一獨立的控制系統,并通過總線的形式獲取數據并控制。 ##...
摘要:每個控制周期需要做的內容包括獲取陀螺儀和編碼器兩個傳感器的數據,傳入直立環和速度環算法中進行計算得到控制量,將控制量作用于直流電機上。 Ruff Lite Ruff Lite 是 Ruff 團隊針對 MCU(MicroController Unit,微控制器)推出的 Ruff OS,具有高實時性,占用內存小等特點。目前官方支持的開發板為TI TM4C1294-LaunchPad ,R...
摘要:綜合諸多考慮與相應調研,我們希望能夠制作出一款宿舍升降機為同學們提供更方便安全的上下床方式。摘要本設計采用開發板作為主控,結合壓力傳感器紅外避障傳感器電機驅動模塊實現了一個可以自動升降自動停止自動調速的宿舍升降機模型系統。 (第一次寫博客,記錄下自己大一時做的一個課設,如有不妥之處,還望多...
閱讀 3735·2023-01-11 11:02
閱讀 4244·2023-01-11 11:02
閱讀 3050·2023-01-11 11:02
閱讀 5180·2023-01-11 11:02
閱讀 4737·2023-01-11 11:02
閱讀 5534·2023-01-11 11:02
閱讀 5313·2023-01-11 11:02
閱讀 3986·2023-01-11 11:02