1.比例控制
设定一个标准值,传感器每次返回一个值,这两个值之差构成了一个序列,每次根据这个偏差输出一个,OUT0为偏置值,Kp为比例系数。其中偏差包括当前偏差、历史偏差和最近偏差。
2.积分控制
对每一次得到传感器的返回值,返回之前所有偏差值之和,,但是单纯的积分控制也会出现问题,如果历史的偏差值是好的,便不再管现在的偏差值到底是大是小,会导致历史情况干扰当前情况。所以与比例控制相同,我们也许增加一个偏置值。
3.微分控制
前一个时刻差值为,当前时刻差,对这两个时间点,将其偏差相减。,它可以说明我们的偏差的变化趋势。同样也会加一个偏置,,out0用于维持。
4.参数设置
(1)Sk处理
,T称为采样周期,即间隔一部分时间,保证上一次算出得结果已经输出,在不同的情况下,采样周期要改变。Ti称为积分常数,它是人为确定的,它越大,则PID最终输出结果越强,反之则削弱。若果Ti过小,则非常容易产生过冲,即先超过额定值,再慢慢下降到额定值。积分项在比例项失效时发生作用。
(2)Dk处理
,这里的T也是采样周期,Td为微分常数。
此时新的单片机中PID算法表达式:
这种方法称为位置式PID,但是有大量历史数据累加,计数比较繁琐。
5.增量式PID
对于控制系统本身具有记忆功能,可以采用增量式PID
增量式PID即
6.C语言PID伪代码
//pid.h
#ifndef _pid_
#define _pid_
#include "stm32f10x_conf.h"
typedef struct{
float Sv;//用户设定值
float Pv;//实际值
float Kp;
float T;//计算周期或者采样周期
float Ti;
float Td;
float Ek,Ek_1;//本次偏差与上一次偏差
float SEk;//历史偏差之和
float OUT0;
float C10ms;
float pwmcycle;//pwm周期
float OUT;//本次应该输出的值
}PID;
extern PID pid;//存放pid算法所需的数据
void PID_calc();
#endif
//pid.c
#include "pid.h"
PID pid;//存放PID的数据
void PID_calc(){//pid计算
float DelEk;
float ti=pid.T/pid.Ti;
float ki=ti*pid.Kp;
float td=pid.Td/pid.T;
float kd=pid.Kp*td;
float Iout,Pout,Dout;
if(pid.C10ms<pid.T/10){
//计算周期没到
return;
}
pid.Ek=pid.Sv-pid.Pv;//得到当前的偏差值
pid.SEk+=pid.Ek;//历史偏差总和
DelEk=pid.Ek-pid.Ek_1;//最近两次的偏差之差
Pout=pid.Kp*pid.Ek;//比例
Iout=pid.SEk*ki;//积分
Dout=kd*DelEk;//微分
if(Pout+Iout+Dout+pid.OUT0>pid.pwmcycle){
pid.OUT=pid.pwmcycle;
}
else if(Pout+Iout+Dout+pid.OUT0<0){
pid.OUT=0;
}else{
pid.OUT=Pout+Iout+Dout+pid.OUT0;
}
pid.Ek_1=pid.Ek;//更新偏差
pid.C10ms=0;
}
对于控制输出部分:
void PID_out{
static u16 pw;
pw++;
if(pw>=pid.pwmcycle){
pw=0;
}
//每次dosomething为1ms
if(pw<pid.OUT){
//do something
}
else{
//do something else
}
}
网友评论