自动车速度闭环控制器设计

速度闭环控制器设计
在过程控制中,按偏差的比例(P)、积分(I)和微分(D)进行控制的PID控制器(亦称PID调节器)是应用最为广泛的一种自动控制器。它具有原理简单,易于实现,适用面广,控制参数相互独立,参数的选定比较简单等优点;而且在理论上可以证明,对于过程控制的典型对象──“一阶滞后+纯滞后”与“二阶滞后+纯滞后”的控制对象,PID控制器是一种最优控制。PID调节规律是连续系统动态品质校正的一种有效方法,它的参数整定方式简便,结构改变灵活
在这里插入图片描述
图1. PID控制系统原理图
离散化公式:
在这里插入图片描述
当|e(t)<=β时
在这里插入图片描述
当|e(t)|>β时,q0 = Kp(1+Td/T);q1 = -Kp(1+2Td/T);q2 = Kp Td /T;u(t) = u(t-1) + Δu(t)

参数调整一般步骤:

1、确定比例增益。

P确定比例增益P时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0,PID为纯比例调节。输入设定为系统允许的最大值的60%70%,由0逐渐加大比例增益P,直至系统出现振荡。再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的60%70%。比例增益P调试完成。

2、确定积分时间常数Ti。比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。

3、确定微分时间常数Td。微分时间常数Td一般不用设定,为0即可。若要设定,与确定P和Ti的方法相同,取不振荡时的30%。

4、系统空载、带载联调,再对PID参数进行微调,直至满足要求。

PID控制器参数整定的方法:

1、理论计算整定法。它主要是依据系统的数学模型,经过理论计算确定控制器参数。这种方法所得到的计算数据未必可以直接用,还必须通过工程实际进行调整和修改。

2、工程整定方法,它主要依赖工程经验,直接在控制系统的试验中进行,且方法简单、易于掌握,在工程实际中被广泛采用。PID控制器参数的工程整定方法,主要有临界比例法、反应曲线法和衰减法。三种方法各有其特点,其共同点都是通过试验,然后按照工程经验公式对控制器参数进行整定。现在一般采用的是临界比例法。利用该方法进行PID控制器参数的整定步骤如下:

(1)首先预选择一个足够短的采样周期让系统工作。

(2)仅加入比例控制环节,直到系统对输入的阶跃响应出现临界振荡,记下这时的比例放大系数和临界振荡周期。

(3)在一定的控制度下通过公式计算得到PID控制器的参数。

控制器主要由两个数据结构类型:



typedef struct

{

       float de ;                             //各个电机当前误差值

       float fe ;                              //各个电机误差积分

       float de1;                            //各个电机历史误差1

       float de2;                            //各个电机历史误差2

       int out;                             //各个通道最终PWM输出

      }PIDDateBaseTypedef;                  //pid数据结构类型

 

typedef
struct

{

       float kp;                                     //比例权重

       float ki;                                      //积分权重

       float kd;                                     //微分权重

       
}PIDParamBaseTypedef;               //pid参数结构类型

控制器的执行由定时器中断分频器发起,实现过程部分代码:



#define
MOTOR_OUTPUT_MAX                                   999

#define
MOTOR_SPEED_PID_KP                           2.400

#define
MOTOR_SPEED_PID_KI                            1.000

#define
MOTOR_SPEED_PID_KD                           0.000

#define
PI                                                                                 3.1415926535897932384626433832795

 

const
PIDParamBaseTypedef PARAM_PID = {//电机pid速度控制参数

 

       .kp = MOTOR_SPEED_PID_KP,                        //比例权重

       .ki = MOTOR_SPEED_PID_KI,                         //积分权重

       .kd = MOTOR_SPEED_PID_KD,                       //微分权重

};

 

float
g_TargetSpeed[4]      = {0,0,0,0};//目的速度

float
g_MotorSpeed[4]      = {0,0,0,0};//当前速度

 

//速度值更新

void
updataSpeed(void)

{

       int16_t etr[4];

       

       //获得编码器值

       etr[0] = TIM1->CNT;//M1

       TIM1->CNT = 0;

       etr[1] = TIM4->CNT;//M2

       TIM4->CNT = 0;

       etr[2] = TIM3->CNT;//M3

       TIM3->CNT = 0;

       etr[3] = TIM2->CNT;//M4

       TIM2->CNT = 0;

       

       for(int i = 0;i < 4;i++)

       {

              float etrtemp = 0;

              

              //编码器脉冲计算轮角速度

              //360度常量 2*80 = 160t

              etrtemp = ((float)(etr[i] %
30000)) / (2.0 * 80.0);

              //角速度计算轮线速度

              etrtemp = etrtemp * (66 * PI);

              //写入线速度到全局

              g_MotorSpeed[i] = etrtemp * 10.0 *
0.25;

       }

}

 

//设定目的速度

void
SetTargetSpeed(int16_t s1,int16_t s2,int16_t s3,int16_t s4)

{

       g_TargetSpeed[0] = s1;

       g_TargetSpeed[1] = s2;

       g_TargetSpeed[2] = s3;

       g_TargetSpeed[3] = s4;

}

 

//上传速度值

void
sendUpMotorSpeed(void)

{

       uint8_t str[500];

       //sprintf((char
*)str,"%03.2f,%03.2f,%03.2f,%03.2f\r\n",g_MotorSpeed[0],g_MotorSpeed[1],g_MotorSpeed[2],g_MotorSpeed[3]);

       

   

       

       //分速度的合成

       float Vx = (((g_MotorSpeed[0] +
g_MotorSpeed[2]) / 2) + 

                                            ((g_MotorSpeed[1] + g_MotorSpeed[3]) / 2) ) /
2;

       

       float Vw = ((((g_MotorSpeed[0] -
g_MotorSpeed[2]) / 2) * 0.891749586 / 187.833) + 

                                            (((g_MotorSpeed[1] - g_MotorSpeed[3]) / 2) *
0.891749586 / 187.833)) / 2;

       

       uint8_t Syx,Syw;

       

       Syx = (Vx >= 0) ? 'A':'B';

       Syw = (Vw >= 0) ? 'A':'B';

       

       Vx = (Vx >= 0) ? Vx : -Vx;

       Vw = (Vw >= 0) ? Vw : -Vw;

       

       

       uint16_t vxi = Vx ;

       uint16_t vwi = Vw * 1000;

       

       

       sprintf((char
*)str,"<S%c%03d,%c%04d>\r\n",Syx,vxi,Syw,vwi);

       

       if(g_MotorSpeed[0] != 0)

       {

              USART_SendString(USART3,str);

       }

       USART_SendString(USART1,str);

}

 

/**

  * @brief 
MotorSpeedPidCtrl.

  *        
Out = Kp[e(k)]+ki∑e(k)+Kd[e(k)-2e(k-1)+e(k-2)]

  *        
其中积分项和微分项受大扰动误差阀值范围生效标志位控制

  * @retval None

  */

void
MotorSpeedPidCtrl(void)

{

       static PIDDateBaseTypedef pid[4] = {

              [0].de    = 0, [1].de    = 0, [2].de    = 0, [3].de    = 0, 

              [0].fe     = 0,  [1].fe  = 0, 
[2].fe  = 0,  [3].fe  =
0, 

              [0].de1 = 0,  [1].de1 = 0, 
[2].de1 = 0,  [3].de1 = 0, 

              [0].de2 = 0,  [1].de2 = 0, 
[2].de2 = 0,  [3].de2 = 0, 

              [0].out = 0,  [1].out = 0, 
[2].out = 0,  [3].out = 0, 

       };

       

       //进行PID控制计算

       for(int i = 0;i < 4;i++)

       {

              //计算当前误差并移动历史误差

              pid[i].de2     =  pid[i].de1;

              pid[i].de1     =  pid[i].de;

              pid[i].de       =  g_TargetSpeed[i] -
g_MotorSpeed[i];

              pid[i].fe  +=  pid[i].de;

              //pid[i]控制器核心方程

              pid[i].out =  PARAM_PID.kp * pid[i].de   + 

                                                               PARAM_PID.ki
* pid[i].fe     + 

                                                               PARAM_PID.kd
* ( pid[i].de - 2 * pid[i].de1          + pid[i].de2) * (pid[i].de < 100);

              //输出限制幅度

              pid[i].out = (pid[i].out >
MOTOR_OUTPUT_MAX) ? MOTOR_OUTPUT_MAX : pid[i].out;

              pid[i].out = (pid[i].out
<-MOTOR_OUTPUT_MAX) ?-MOTOR_OUTPUT_MAX : pid[i].out;

              

              //输出死区限制

              

              

       }

       //输出到电机控制

       setMotorPWM(pid[0].out,pid[1].out,pid[2].out,pid[3].out);

       

       

       //uint8_t str[50];

       //sprintf((char
*)str,"%d,%d,%d,%d\r\n",pid[0].out,pid[1].out,pid[2].out,pid[3].out);

       //USART_SendString(USART1,str);

}

 

//pid控制器执行周期分频器

void
PID_Divider(void)

{

       static uint32_t div = 0;

       div++;

       if(div >= 100)

       {

              div = 0;

              //更新当前速度

              updataSpeed();

              //上传速度信息

              sendUpMotorSpeed();

              //执行电机PID控制器

              MotorSpeedPidCtrl();

       }

}

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值