直流无刷电机的调试与代码开源(配套资源)
生活随笔
收集整理的這篇文章主要介紹了
直流无刷电机的调试与代码开源(配套资源)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
本周對手頭的一款大疆M3508直流無刷電機調(diào)試的相關(guān)內(nèi)容進行整理及個人的代碼進行分享。
一、M3508直流無刷電機
直流無刷電機的工作原理此處不做闡述,相關(guān)資料也易查詢。
1.1電機結(jié)構(gòu)與連接樣式圖
1.2電機參數(shù)
具體不多加闡述,感興趣的可到官網(wǎng)下載相關(guān)資料和軟件驅(qū)動,連接如下:
M3508減速電機套裝 (robomaster.com)
1.3分電板
電源采用12V,通過一塊分電板對單片機主板、電機和電源模塊進行連接,這個分電板通過PCB簡單設(shè)計,實現(xiàn)多少電壓輸入,多少電壓輸出。分電板的PCB圖如下所示:
2.STM32程序:
控制一個電機,需要1個PWM,2個高低電位
2.1 控制原理圖
反饋值(測量值)- 設(shè)定值(目標(biāo)值)= 控制偏差;
控制偏差給到控制器;
從而將偏差給到電機,在經(jīng)過編碼器獲得反饋;
實現(xiàn)閉環(huán)
?
相關(guān)pid.c代碼如下:
#include"pid.h"#define speed_max 482struct _pid {float ExpectedValue;//定義設(shè)定值float ActualValue;//定義實際值 float err;//定義偏差值float err_prev;//定義前一個的偏差值float integral;//定義積分項float Kp, Ki, Kd;//定義比例、積分、微分系數(shù)float curmax, curmin;//定義電流最值 }pid;void PID_Init(){//初始化pid各值pid.ExpectedValue=0.0;pid.ActualValue = 0.0;pid.err = 0.0;pid.err_prev = 0.0;pid.integral = 0.0;pid.Kp = 1.0;pid.Ki = 0.1;pid.Kd = 0.2;pid.curmax = 3000;pid.curmin = -3000;} //限幅 void abs_limit(float *object, float abs_max) {if(*object > abs_max) *object = abs_max;if(*object < -abs_max) *object = -abs_max; }/* 輸入:期望轉(zhuǎn)速 輸出:位置型單環(huán)PID結(jié)果*/ float PID_Realize(float set_speed,float get_speed){//ste_speed期望轉(zhuǎn)速 £?get_speed實際轉(zhuǎn)速pid.ExpectedValue = set_speed;pid.ActualValue = get_speed;pid.err = pid.ExpectedValue-pid.ActualValue;//計算誤差err//計算積分項pid.integral += pid.err;//位置式PID公式float Value = pid.Kp*pid.err + pid.Ki*pid.integral+pid.Kp*(pid.err-pid.err_prev);//誤差換代pid.err_prev=pid.err;if(Value<pid.curmin)return pid.curmin;else if(Value>pid.curmax)return pid.curmax;elsereturn Value;}/********************************************************************************************************/ void pid_struct_init(pid_t* pid, float kp, float ki, float kd) {pid->err[NOW] = 0;pid->err[LAST] = 0;pid->err[LLAST] = 0;pid->pos_out = 0;pid->pout = 0;pid->iout = 0;pid->dout = 0;pid->p = kp;pid->i = ki;pid->d = kd;pid->pos_abs = 0;pid->pos_goal = 0;}//μ¥?·pidfloat single_pid_calculate(pid_t * pid_s) {pid_s->err[NOW] = pid_s->target - pid_s->measure;//當(dāng)前誤差//p項 比例項pid_s->pout = pid_s->p * pid_s->err[NOW];//i項 積分項pid_s->iout += pid_s->i * pid_s->err[NOW];//d項 微分項pid_s->dout = pid_s->d * (pid_s->err[NOW] - pid_s->err[LAST]);pid_s->pos_out = pid_s->pout + pid_s->iout + pid_s->dout;//誤差更新pid_s->err[LAST] = pid_s->err[NOW];abs_limit(&(pid_s->pos_out),3000);return pid_s->pos_out; }//雙環(huán)pid float double_pid_calculate(pid_t * pid_I , pid_t* pid_O)//I是速度,o是角度 {/****************************角度環(huán)**************************************/pid_O->err[NOW] = pid_O->target - pid_O->measure;//當(dāng)前誤差 /*//p項 比例項pid_O->pout = pid_O->p * (pid_O->err[NOW] - pid_O->err[LAST]);//i項 積分項pid_O->iout += pid_O->i * pid_O->err[NOW];//d項 微分項pid_O->dout = pid_O->d * (pid_O->err[NOW] - 2*pid_O->err[LAST] + pid_O->err[LLAST]); */if((pid_O->err[NOW]>-50) || (pid_O->err[NOW]<50)){pid_O->iout = 0; //設(shè)置死區(qū)}pid_O->pout = pid_O->p * pid_O->err[NOW];pid_O->iout += pid_O->i * pid_O->err[NOW];pid_O->dout = pid_O->d * (pid_O->err[NOW] - pid_O->err[LAST]);pid_O->pos_out = pid_O->pout + pid_O->iout + pid_O->dout;//算出速度應(yīng)設(shè)置的值abs_limit(&(pid_O->pos_out),3000);//誤差更新pid_O->err[LAST] = pid_O->err[NOW];pid_O->err[LLAST] = pid_O->err[LAST];/*******************************速度環(huán)************************************/pid_I->err[NOW] = pid_O->pos_out - pid_I->measure;//μ±?°?ó2?//p項 比例項pid_I->pout = pid_I->p * pid_I->err[NOW];//i項 積分項pid_I->iout += pid_I->i * pid_I->err[NOW]; //d項 微分項pid_I->dout = pid_I->d * (pid_I->err[NOW] - pid_I->err[LAST]);pid_I->result =pid_I->pout + pid_I->iout + pid_I->dout;//應(yīng)設(shè)置的電流值//誤差更新pid_I->err[LAST] = pid_I->err[NOW];abs_limit(&(pid_I->result),8000);return pid_I->result; }pid.h
enum {LLAST = 0,LAST = 1,NOW = 2, }; void PID_Init(void); float PID_Realize(float current,float ActualValue);typedef struct __pid_t {float p;float i;float d;float target; //目標(biāo)值float measure; //測量值float err[3]; //誤差float result;float pout; float iout; float dout; float pos_goal; //目標(biāo)角度 float pos_abs; //絕對角度float pos_out; //本次位置式輸出 }pid_t;typedef struct {float pos_goal;//目標(biāo)位置float pos_abs;//絕對位置float pos_offset;//位置補償float eer;//誤差float eer_eer;//上次誤差 }ANGLE_TypeDef;void pid_struct_init(pid_t* pid, float kp, float ki, float kd);float single_pid_calculate(pid_t * pid_s); float double_pid_calculate(pid_t * pid_I , pid_t* pid_O);主函數(shù)
#include "main.h" #include "key.h" #include "led.h" #include "can.h" #include "tim.h" #include "pid.h"int i;unsigned char Temp_Value_3508 = { 0 };//CAN接受電機溫度 short Torque_Value_3508 = { 0 }; //CAN實際扭矩電流 short Velocity_Value_3508 = { 0 }; //CAN接受實際轉(zhuǎn)速 short Position_Value_3508 = { 0 }; //CAN接受機械角度 short Velocity_3508_ID1=0; //CAN實際轉(zhuǎn)速 short Position_3508_ID1=0; //CAN接受機械角度 short Torque_3508_ID1=0; //CAN實際扭轉(zhuǎn)電流 unsigned char Temp_Value_3508_ID1=0; //CAN接受電機溫度 pid_t PID,PID_I,PID_O; //o為角度,i為速度 short set_current1; //PID計算后當(dāng)前需要傳輸電流值short Velocity_3508_ID1_Set_Speed=0; //設(shè)定轉(zhuǎn)速ANGLE_TypeDef motor_angle;void CAN1_TX_IRQHandler( void ) //CAN發(fā)送中斷 清楚發(fā)送中斷標(biāo)志 {if ( CAN_GetITStatus( CAN1, CAN_IT_TME ) != RESET ){CAN_ClearITPendingBit( CAN1, CAN_IT_TME );} } void CAN1_RX0_IRQHandler( void ) //CA接受中斷 更新當(dāng)前實際轉(zhuǎn)速 且清楚接受中斷標(biāo)志位 {CanRxMsg rx_message;if ( CAN_GetITStatus( CAN1, CAN_IT_FMP0 ) != RESET )//判斷是否是fifo0消息掛起中斷(即收到消息){CAN_ClearITPendingBit( CAN1, CAN_IT_FMP0 );CAN_Receive( CAN1, CAN_FIFO0, &rx_message);if ( (rx_message.IDE == CAN_Id_Standard) && (rx_message.RTR == CAN_RTR_Data) && (rx_message.DLC == 8) ) /* ±ê×????¢êy?Y???¢êy?Y3¤?è?a8 */{Temp_Value_3508 = rx_message.Data[6]; Torque_Value_3508 = (rx_message.Data[4] << 8) | (rx_message.Data[5]);Velocity_Value_3508 = (rx_message.Data[2] << 8) | (rx_message.Data[3]);Position_Value_3508 = (rx_message.Data[0] << 8) | (rx_message.Data[1]);Velocity_3508_ID1=Velocity_Value_3508; Position_3508_ID1=Position_Value_3508;Torque_3508_ID1=Torque_Value_3508;Temp_Value_3508_ID1=Temp_Value_3508;PID.measure = Velocity_3508_ID1;//2aá??μPID_I.measure = Velocity_Value_3508;PID_O.measure = Position_Value_3508;}} }int main(void) {delay_init( 180 ); delay_ms( 100 );KEY_Init();Led_Init();CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_7tq,CAN_BS1_7tq,3,CAN_Mode_Normal); £?ò?°?2?ó??ˉ£???ê?500kbpsdelay_ms(100);PID_Init(); pid_struct_init(&PID,1,0.1,0.2);//3?ê??ˉpidμ?èy??2?êy?μp£?i£?dpid_struct_init(&PID_I,5,0.1,3);pid_struct_init(&PID_O,10,0.1,5);Tick_TIM7_Init(1000);while (1){ if(key==0){motor_angle.pos_goal = 0;LED3=1;LED4=0;}else if(key==1){motor_angle.pos_goal = -2160;LED3=0;LED4=1;}delay_ms(10);}}void Motor_Angle_Cal(float T) {float res1, res2;static float pos,pos_old;pos =(PID_O.measure/8192.0f*360.0f);motor_angle.eer=pos - pos_old;//???è?ó2?μ?????if(motor_angle.eer>0) { res1=motor_angle.eer-T;res2=motor_angle.eer;}else{res1=motor_angle.eer+T;res2=motor_angle.eer;}if(fabs(res1)<fabs(res2)) {motor_angle.eer_eer = res1;}else{motor_angle.eer_eer = res2;}motor_angle.pos_abs += motor_angle.eer_eer; motor_angle.pos_offset=motor_angle.pos_goal-motor_angle.pos_abs;pos_old = pos; }void TIM7_IRQHandler( void ) {if ( TIM_GetITStatus( TIM7, TIM_IT_Update ) == SET ){/******************μ¥?·******************/// set_current1 = single_pid_calculate(&PID);/******************???·******************/Motor_Angle_Cal(360);PID_O.target = motor_angle.pos_offset;PID_O.measure = 0;set_current1 = 0;// set_current1=PID_Realize(Velocity_3508_ID1_Set_Speed,Velocity_3508_ID1); CAN1_Send_Msg(set_current1,set_current1,set_current1,set_current1);//éè??μ?á÷?μ}TIM_ClearITPendingBit( TIM7, TIM_IT_Update ); }?
?
總結(jié)
以上是生活随笔為你收集整理的直流无刷电机的调试与代码开源(配套资源)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 9、摩擦力
- 下一篇: Linux 环境变量配置全攻略,超详细~