打印
[STM32F1]

电机PID补偿程序

[复制链接]
1677|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hapao|  楼主 | 2017-3-31 17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
电机的反馈补偿,应用了PID算法,本人不是太懂,但是最近急需弄明白32程序的PID语言意义。
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "pwm.h"
#include "timer.h"
#include "exti.h"
#include "usart.h"       




u16 counter;
u16 PWM_MOTO=3445;
u16 PWM_IN=70;
PID_AbsoluteType PID_Control;//定义PID算法的结构体
void PID_Init(void);
int main(void)
{       
        u16 led0pwmval=0;   
        u8 dir=1;       
         
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        delay_init();                     //延时函数初始化          
        uart_init(115200);
        LED_Init();                          //初始化与LED连接的硬件接口
        TIM5_Int_Init(99,71);                //0.1ms中断,用于计算输入信号触发与电机转一圈触发信号的时间差
        TIM4_PWM_Init(9999,0);////pwm控制电机转速
        TIM2_PWM_Init(1666,719);                //输出一个接近60 Hz的的信号
        TIM_SetCompare1(TIM4,PWM_MOTO);          //通道1
        //TIM_SetCompare1(TIM2,7999);
        TIM3_Int_Init(999,7199);        //100ms秒中断         
        EXTIX_Init();
        PID_Init();
           while(1)
        {
        //        delay_ms(4);                                                    
                if(USART_RX_STA & 0x8000)       
                {
                        USART_RX_STA=0;
                        if(USART_RX_BUF[0]==1)  PWM_MOTO+=USART_RX_BUF[1];                //串口调试转速
                        else                                                                                 PWM_MOTO-=USART_RX_BUF[1];
                //        if(USART_RX_BUF[0]==4)        TIM2_PWM_Init(100000/USART_RX_BUF[1],719);//串口改变输入信号
                        if(USART_RX_BUF[0]==2)                                //调节PID参数
                        {
                                PID_Control.kp = USART_RX_BUF[1] * 0.1f;
                                PID_Control.ki = USART_RX_BUF[2] * 0.1f;
                                PID_Control.kd = USART_RX_BUF[3] * 0.1f;
                                printf("P=%f I=%f D=%f\r\n",PID_Control.kp,PID_Control.ki,PID_Control.kd);
                        }
                        if(USART_RX_BUF[0]==3)                                //调节PID参数
                        {
                                PID_Control.kp1 = USART_RX_BUF[1] * 0.001f;
                                PID_Control.ki1 = USART_RX_BUF[2] * 0.001f;
                                PID_Control.kd1 = USART_RX_BUF[3] * 0.001f;
                                printf("P=%f I=%f D=%f\r\n",PID_Control.kp,PID_Control.ki,PID_Control.kd);
                        }
                        printf("%d\r\n",PWM_MOTO);
                        printf("%d\r\n",USART_RX_BUF[1]);
                        TIM_SetCompare1(TIM4,PWM_MOTO);
                }
               
        //printf("%d\r\n",InCounter);               
        }
}

////////////////////////////////////////////////////////////////////////
//绝对式PID算法
void PID_AbsoluteMode(PID_AbsoluteType* PID)        //速度环控制
{
// if(PID->kp      < 0)    PID->kp      = -PID->kp;
// if(PID->ki      < 0)    PID->ki      = -PID->ki;
// if(PID->kd      < 0)    PID->kd      = -PID->kd;
// if(PID->errILim < 0)    PID->errILim = -PID->errILim;

PID->errP = PID->errNow;  //读取现在的误差,用于kp控制

PID->errI += PID->errNow; //误差积分,用于ki控制

if(PID->errILim != 0)           //微分上限和下限
{
  if(     PID->errI >  PID->errILim)    PID->errI =  PID->errILim;
  else if(PID->errI < -PID->errILim)    PID->errI = -PID->errILim;
}

PID->errD = PID->errNow - PID->errOld;//误差微分,用于kd控制

PID->errOld = PID->errNow;        //保存现在的误差

PID->ctrOut = PID->kp * PID->errP + PID->ki * PID->errI + PID->kd * PID->errD;//计算绝对式PID输出

}
void PID_Trig(PID_AbsoluteType* PID)        //触发控制
{
        //u16 temp;
        //temp = (100.0f / Incounter1)
//        if(PID->errNow1 > 500)        PID->errNow1 = -(1000 - PID->errNow1);        //计算在输入信号的前还是后触发,100ms计算一次,数值大于50ms则算作输入信号之后触发
//         PID->errNow1 =  -PID->errNow1;                //根据触发先后顺序,0 - 500ms 是电机触发慢于输入信号触发
        PID->errP1 = PID->errNow1;  //读取现在的误差,用于kp控制
       
        PID->errI1 += PID->errNow1; //误差积分,用于ki控制
        if(PID->errILim1 != 0)           //微分上限和下限
{
  if(     PID->errI1 >  PID->errILim1)    PID->errI1 =  PID->errILim1;
  else if(PID->errI1 < -PID->errILim1)    PID->errI1 = -PID->errILim1;
}
PID->errD1 = PID->errNow1 - PID->errOld1;//误差微分,用于kd控制

PID->errOld1 = PID->errNow1;        //保存现在的误差

PID->ctrOut1 = PID->kp1 * PID->errP1 + PID->ki1 * PID->errI + PID->kd1 * PID->errD1;//计算绝对式PID输出
//if(PID->ctrOut1>55)                PID->ctrOut1 = 55;        //xianzhi
// if(PID->ctrOut1<-55)                PID->ctrOut1 = -55;        //xianzhi
}


/*****************************************电机速度环伺服***********************************************/

s32 spdTag, spdNow, control;//定义一个目标速度,采样速度,控制量
u16 CC,CC1;
u8 C_Flag=1;
double k=1; //转速误差系数

void User_PidSpeedControl(s32 SpeedTag)
{
   spdNow = InCounter;                 //电机转一圈计数18个脉冲
         spdTag = SpeedTag;
       
   PID_Control.errNow =spdNow - spdTag+7.5; //计算并写入速度误差
   PID_Control.errNow1 = Time_2; //计算并写入速度误差
   
   // PID_AbsoluteMode(&PID_Control);    PID_Trig(&PID_Control);control = PID_Control.ctrOut + PID_Control.ctrOut1
                //control = PID_Control.ctrOut ;
         if(PID_Control.errNow == 0)        {CC++;if(CC>13) {CC=0; C_Flag=2;}CC1=0;}        //Trig PID 转速等于输入信号,开始调节触发
   else {CC1++;        if(CC1>20){CC1 = 0;C_Flag=1;}CC=0;}               
                //else {  control = PID_Control.ctrOut ;}         //读取控制值/ Speed PID算法
         if(C_Flag==2 && (Time_2>10 || Time_2<-10))                {            PID_Trig(&PID_Control);control =  PID_Control.ctrOut + PID_Control.ctrOut1;}
         if(C_Flag==1)    { PID_AbsoluteMode(&PID_Control); control = PID_Control.ctrOut ; }
         if(CC1>40) {CC=0;}
//         if(CC>40 && C_Flag==0)        {C_Flag=1;CC=0;}
//         if(CC>40 && C_Flag==1)        {C_Flag=0;CC=0;}
                 
         //if(control>4999)                control=4999;        //限幅
         //if(control<0)                        control=0;
   TIM_SetCompare1(TIM4,(control+3500)*k);                        //占空比在60%以上电机才开始转动
         //#ifdef _TEST_
                 printf("Motor=%d Out=%.1f Out1=%.1f C_Flag=%d errNow=%f \r\n",control,PID_Control.ctrOut,PID_Control.ctrOut1,C_Flag,PID_Control.errNow);
         //#endif
         //PID_Control.ctrOut1=0;                //清零
}

void PID_Init(void)
{
        PID_Control.kp      = 2.2f;             //写入比例系数
        PID_Control.ki      = 3.0f;              //写入积分系数
        PID_Control.kd      = 1.5f;              //写入微分系数
        PID_Control.errILim = 3000;           //写入误差积分上下限
        PID_Control.kp1      = 0.2f;             //写入比例系数
        PID_Control.ki1      = 0.00f;              //写入积分系数
        PID_Control.kd1      = 1.1f;              //写入微分系数
        PID_Control.errILim1 = 500;           //写入误差积分
}
沙发
zrflij| | 2017-3-31 18:05 | 只看该作者
加QQ 48256650 详聊

使用特权

评论回复
板凳
hapao|  楼主 | 2017-3-31 21:20 | 只看该作者
zrflij 发表于 2017-3-31 18:05
加QQ 48256650 详聊

好的

使用特权

评论回复
地板
yongwong99| | 2017-4-8 21:01 | 只看该作者
mark!

使用特权

评论回复
5
airwill| | 2017-4-11 07:10 | 只看该作者
想弄明白 PID, 最好先别看程序, 这一套控制算法, 有一些理论基础
也不算复杂, 看明白了理论, 程序算法迎刃而解

使用特权

评论回复
6
heisexingqisi| | 2017-4-11 15:12 | 只看该作者
要研究理论,先搞懂理论,然后再来看代码。

使用特权

评论回复
7
yiy| | 2017-4-11 21:24 | 只看该作者
先弄明白理论,再弄明白实现方法和代码。

使用特权

评论回复
8
Stannis| | 2017-4-13 21:50 | 只看该作者
PID控制器就是根据系统的误差,利用比例、积分、微分计算出控制量进行控制的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

12

帖子

1

粉丝