(一)PID控制算法(P:比例 I:积分 D:微分)
(二)首先先说明原理,使用的是数字PID算法,模拟PID算法在计算机这样的系统中是不能够直接使用的,数字PID算法又分为位置式PID控制算法和增量式PID控制算法,那么下面从原理上说明这两种算法
(三)原理分析如图
(四)从上面图中我们可以得到定义
定义变量
用户设定值: SV
当前值(实际值): PV
偏差: E = SV - PV
(五)如果我们在一段时间内就从传感器读取一个值,那么我们就可以得到一个实际值的数据序列,,那么我们也会得到一个偏差值的序列
读取时间: t(1) t(2) ------ t(k-1) t(k)
读取到的值: X(1) X(2) ------ X(k-1) X(k)
偏差值: E(1) E(2) ------ E(k-1) E(k)
那么我们从偏差值中可以知道: E(X) > 0 说明未达标
E(X) = 0 说明正好达标
E(X) < 0 说明超标
(六)比例控制(P),作用:对偏差起到及时反映的作用,一旦产生偏差,控制器立即做出反映.............
定义:
比例系数:Kp (根据系统进行调节)
比例输出:POUT = Kp * E(k)
POUT = Kp * E(k) + OUT0
OUT0说明:OUT0是防止E(K) = 0 时候比例控制不作用,所以添加个OUT0进去,OUT0可以根据系统定义大小
Kp说明:如果我们得到一个偏差之后,将偏差进行放大或者缩小来让控制器进行控制
(七)积分控制(I),作用:消除静差............
从上面我们得到偏差序列:
偏差值: E(1) E(2) ------ E(k-1) E(k)
定义,历史偏差值之和:S(k) = E(1) + E(2) + .... + E(k-1) + E(K)
定义,积分输出: IOUT = Kp * S(k) + OUT0
(八)微分控制(D),作用:反映偏差信号的变化趋势.............
从上面我们得到偏差序列:
偏差值: E(1) E(2) ------ E(k-1) E(k)
定义,偏差之差:D(k) = E(k) - E(k-1)
定义,微分输出:DOUT = Kp * D(k) + OUT0
(九)那么我们从上面就能得出PID的控制算法
PIDOUT = POUT + IOUT + DOUT
= (Kp * E(k) + OUT0) + (Kp * S(k) + OUT0) + (Kp * D(k) +OUT0)
= Kp * (E(k) + S(k) + D(k)) + OUT0
OUT0防止PIDOUT = 0 时候算法还有输出,防止失去控控制
比例(P):考虑当前
积分(I):考虑历史
微分(D):考虑未来
(十)位置式PID,上面只是简单的说明了一下原理,那么实际的数字PID控制算法中,额,那个变换公式打不出来,自行百度,这里就直接打出结果
Ti:积分常数 TD:微分常数 T:计算周期
上面两个是变化后的积分和微分的那个,那么我们把上面的两个替换到第九点中,我们就得到位置上PIDOUT的公式,两个式子是一样的
(十一)增量式PID,本次基础上加上多少偏差:△OUT
/**********************分割线************************/
(十二)上面的只是PID的原理说明,那么数字PID的公式是
(十三)那么我们将上面的公式通过通过C语言写出来
1. 位置式PID
#ifndef _pid_
#define _pid_
#include 'stm32f10x_conf.h'
#define MODEL_P 1
#define MODEL_PI 2
#define MODEL_PID 3
typedef struct
{
u8 choose_model; //使用哪个模式调节
float Sv; //用户设定值
float Pv; //当前值,实际值
float Kp; //比例系数
float T; //PID计算周期--采样周期
u16 Tdata; //判断PID周期到没到
float Ti; //积分时间常数
float Td; //微分系数
float Ek; //本次偏差
float Ek_1; //上次偏差
float SEk; //历史偏差之和
float Iout; //积分输出
float Pout; //比例输出
float Dout; //微分输出
float OUT0; //一个维持的输出,防止失控
float OUT; //计数最终得到的值
u16 pwmcycle;//pwm周期
}PID;
extern PID pid; //存放PID算法所需要的数据
void PID_Calc(void); //pid计算
void PID_Init(void); //PID初始化
#endif
#include 'pid.h'
#include 'PWM_Config.h'
#include 'USART_Config.h' //USART设置
PID pid; //存放PID算法所需要的数据
void PID_Init()
{
pid.choose_model = MODEL_PID;
pid.T=330; //采样周期,定时器使用1ms,则最小执行PID的周期为330ms
pid.Sv=280; //用户设定值
pid.Kp=0.5; //比例系数
pid.Ti=180; //积分时间
pid.Td=1; //微分时间
pid.OUT0=0; //一个维持的输出
pid.pwmcycle = 330; //PWM的周期
}
void PID_Calc() //pid计算
{
float DelEk; //本次和上次偏差,最近两次偏差之差
float ti,ki;
float td;
float kd;
float out;
if(pid.Tdata < (pid.T)) //最小计算周期未到
{
return ;
}
pid.Tdata = 0;
pid.Ek=pid.Sv-pid.Pv; //得到当前的偏差值
pid.Pout=pid.Kp*pid.Ek; //比例输出
pid.SEk+=pid.Ek; //历史偏差总和
DelEk=pid.Ek-pid.Ek_1; //最近两次偏差之差
ti=pid.T/pid.Ti;
ki=ti*pid.Kp;
pid.Iout=ki*pid.SEk*pid.Kp; //积分输出
/*注意:上面程序中多了个pid.Kp,原程序中有,请自动删除,正确的应该是pid.Iout=ki*pid.SEK */
td=pid.Td/pid.T;
kd=pid.Kp*td;
pid.Dout=kd*DelEk; //微分输出
switch(pid.choose_model)
{
case MODEL_P: out= pid.Pout; printf('使用P运算rn') ;
break;
case MODEL_PI: out= pid.Pout+ pid.Iout; printf('使用PI运算rn') ;
break;
case MODEL_PID: out= pid.Pout+ pid.Iout+ pid.Dout; printf('使用PID运算rn') ;
break;
}
printf('PID算得的OUT:t%drn',(int)out) ;
//////////////////////////////////////////////////////////
/*判断算出的数是否符合控制要求*/
if(out>pid.pwmcycle) //不能比PWM周期大,最大就是全高吗
{
pid.OUT=pid.pwmcycle;
}
else if(out<0) //值不能为负数
{
pid.OUT=pid.OUT0;
}
else
{
pid.OUT=out;
}
printf('实际输出使用的pid.OUT:t%drn',(int)pid.OUT) ;
pid.Ek_1=pid.Ek; //更新偏差
Turn_Angle((int)pid.OUT); //输出PWM
}
2.增量式PID
#ifndef _pid_
#define _pid_
#include 'stm32f10x_conf.h'
#define MODEL_P 1
#define MODEL_PI 2
#define MODEL_PID 3
typedef struct
{
u8 choose_model; //使用哪个模式调节
float curr; //当前值
float set; //设定值
float En; //当前时刻
float En_1; //前一时刻
float En_2; //前二时刻
float Kp; //比例系数
float T; //采样周期---控制周期,每隔T控制器输出一次PID运算结果
u16 Tdata; //判断PID周期到没到
float Ti; //积分时间常数
float Td; //微分时间常数
float Dout; //增量PID计算本次应该输出的增量值--本次计算的结果
float OUT0; //一个维持的输出,防止失控
short currpwm; //当前的pwm宽度
u16 pwmcycle; //pwm周期
}PID;
extern u8 STATUS;
extern PID pid;
void PIDParament_Init(void); /*增量式PID初始化*/
void pid_calc(void); /*pid计算 并输出*/
#endif
#include 'pid.h'
#include 'PWM_Config.h'
#include 'USART_Config.h' //USART设置
PID pid;
void PIDParament_Init() //
{
pid.choose_model = MODEL_PID;
pid.T=330; //采样周期,定时器使用1ms,则最小执行PID的周期为330ms
pid.set =280; //用户设定值
pid.Kp=0.5; //比例系数
pid.Ti=40; //微分系数常数
pid.Td=10; //积分时间常数
pid.OUT0=0; //一个维持的输出
pid.pwmcycle = 330; //PWM的周期