热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2.10PID控制算法(二)

关于PID各种整理例程基于stm32,位置式,增量式等1、增量式1.1增量式方式1structt_pid2{floatSetSpeed2;floatActua

关于PID各种整理例程基于stm32,位置式,增量式等


1、增量式


1.1 增量式 方式1

struct t_pid2
{float SetSpeed2;float ActualSpeed2;float err2;float err_next2;float err_last2;float Kp2,Ki2,Kd2;
}pid2;
void PID2_init()
{pid2.SetSpeed2=0.0;pid2.ActualSpeed2=0.0;pid2.err2=0.0;//当前值pid2.err_next2=0.0;//上一次值pid2.err_last2=0.0;//上上次值pid2.Kp2=0.2;pid2.Ki2=0.015;pid2.Kd2=0.2;
}
float PID2_realize(float speed)
{float incrementSpeed=0;pid2.SetSpeed2=speed;pid2.err2=pid2.SetSpeed2-pid2.ActualSpeed2;incrementSpeed=pid2.Kp2*(pid2.err2-pid2.err_next2)+pid2.Ki2*pid2.err2+pid2.Kd2*(pid2.err2-2*pid2.err_next2+pid2.err_last2);pid2.ActualSpeed2+=incrementSpeed;pid2.err_last2=pid2.err_next2;pid2.err_next2=pid2.err2;return pid2.ActualSpeed2;
}

1.1增量式 方式1 积分饱和

所谓的积分饱和现象是指如果系统存在一个方向的偏差,PID 控制器的输出由于积分作用的不断累加而加大,从而导致执行机构达到极限位置,若控制器输出 U(k)继续增大,执行器开度不可能再增大,此时计算机输出控制量超出了正常运行范围而进入饱和区。一旦系统出现反向偏差,u(k)逐渐从饱和区退出。进入饱和区越深则退出饱和区时间越长。在这段时间里,执行机构仍然停留在极限位置而不随偏差反向而立即做出相应的改变,这时系统就像失控一样,造成控制性能恶化,这种现象称为积分饱和现象或积分失控现象。

防止积分饱和的方法之一就是抗积分饱和法,该方法的思路是在计算 u(k)时,首先判断上一时刻的控制量 u(k-1)是否已经超出了极限范围: 如果u(k-1)>umax,则只累加负偏差; 如果 u(k-1)

在这里插入图片描述
如上图,很明显有三个过冲:
过程①:因为这个过程存在较大幅度变化的误差,因此积分器累积了较大的值,从图中可以看到,积分器的面积比较大(阴影部分)ek为正;

过程②:此时积分已经饱和,产生了较大的过冲,并且在较长的一段时间内,一直处于过冲的状态,ek为负;

过程③:积分脱离饱和状态,产生了积极的调节作用,消除静差,系统输出达到设定值 ek为正;

处理过程:
在这里插入图片描述

/*定义结构体和公用体*/
typedef struct
{float setpoint; //设定值float proportiongain; //比例系数float integralgain; //积分系数float derivativegain; //微分系数float lasterror; //前一拍偏差float preerror; //前两拍偏差float deadband; //死区float result; //输出值float maximum; //最大值float minimum; //最小值
}PID;void PIDRegulation(PID *vPID, float processValue)
{float thisError;float increment;float pError,dError,iError;thisError&#61;vPID->setpoint-processValue; //本次误差pError&#61;thisError-vPID->lasterror; //本次偏差与上次偏差之差iError&#61;0;dError&#61;thisError-2*(vPID->lasterror)&#43;vPID->preerror;if(vPID->result>vPID->maximum){if(thisError<&#61;0){iError&#61;thisError;}}elseif(vPID->result<vPID->minimum){if(thisError>&#61;0){iError&#61;thisError;}}else{iError&#61;thisError;}increment&#61;vPID->proportiongain*pError&#43;vPID->integralgain*iError&#43;vPID->derivativegain*dError; //增量计算vPID->preerror&#61;vPID->lasterror; //存放偏差用于下次运算vPID->lasterror&#61;thisError;vPID->result&#43;&#61;increment;
}

1.2 增量式 方式2

#define DEFAULT_SPEED -5 // mm/s 默认目标值
#define DEFAULT_PROPORTION 0.11f // Kp系数
#define DEFAULT_INTEGRAL 0.12f // Ki系数
#define DEFAULT_DERIVATIVE 0.03f // Kd系数
/*** 函数功能: PID结构体初始化* 输入参数: 无* 返 回 值: 无* 说 明: 初始化PID参数*/
void Init_PIDStruct()
{vPID.SetPoint &#61; DEFAULT_SPEED; // 目标值 单位:mm/svPID.Proportion &#61; DEFAULT_PROPORTION; // Kp系数vPID.Integral &#61; DEFAULT_INTEGRAL; // Ki系数vPID.Derivative &#61; DEFAULT_DERIVATIVE; // Kd系数 vPID.LastError &#61; 0;vPID.PrevError &#61; 0;vPID.SumError &#61; 0;
}/*** 函数功能&#xff1a;增量式PID速度环计算* 输入参数&#xff1a;NextPoint 由编码器得到的速度值 * TargetVal 目标值* 返 回 值&#xff1a;经过PID运算得到的增量值* 说 明&#xff1a;增量式 PID 速度环控制设计,计算得到的结果仍然是速度值*/
float IncPIDCalc(__IO float NextPoint,__IO float TargetVal) //临时变量,期望值
{__IO float iError &#61; 0,iIncpid &#61; 0; //当前误差iError &#61; TargetVal - NextPoint; // 增量计算
// if((iError<0.5f)&&(iError>-0.5f))
// iError &#61; 0; // |e| <0.5,不做调整iIncpid&#61;(vPID.Proportion * iError) // E[k]项-(vPID.Integral * vPID.LastError) // E[k-1]项&#43;(vPID.Derivative * vPID.PrevError); // E[k-2]项vPID.PrevError&#61;vPID.LastError; // 存储误差&#xff0c;用于下次计算vPID.LastError &#61; iError;return(iIncpid); // 返回增量值
}

2、位置式


2.1 位置式 方式1

struct t_pid
{float SetSpeed;float ActualSpeed;float err;float err_last;float Kp,Ki,Kd;float voltage;float integral;
}pid;
void PID_init()
{pid.SetSpeed&#61;0.0;pid.ActualSpeed&#61;0.0;pid.err&#61;0.0;pid.err_last&#61;0.0;pid.voltage&#61;0.0;pid.integral&#61;0.0;pid.Kp&#61;0.2;pid.Ki&#61;0.015;pid.Kd&#61;0.2;
}
float PID_realize(float speed)
{pid.SetSpeed&#61;speed;pid.err&#61;pid.SetSpeed-pid.ActualSpeed;pid.integral&#43;&#61;pid.err;pid.voltage&#61;pid.Kp*pid.err&#43;pid.Ki*pid.integral&#43;pid.Kd*(pid.err-pid.err_last);pid.err_last&#61;pid.err;pid.ActualSpeed&#61;pid.voltage*1.0;return pid.ActualSpeed;
}

2.2 位置式 方式2–积分分离

积分分离的概念&#xff0c;其基本思路是 当被控量与设定值偏差较大时&#xff0c;取消积分作用; 当被控量接近给定值时&#xff0c;引入积分控制&#xff0c;以消除静差&#xff0c;提高精度。

struct t_pid3
{float SetSpeed3;float ActualSpeed3;float err3;float err_last3;float Kp3,Ki3,Kd3;float voltage3;float integral3;
}pid3;
void PID3_init()
{pid3.SetSpeed3&#61;0.0;pid3.ActualSpeed3&#61;0.0;pid3.err3&#61;0.0;pid3.err_last3&#61;0.0;pid3.voltage3&#61;0.0;pid3.integral3&#61;0.0;pid3.Kp3&#61;0.2;pid3.Ki3&#61;0.04;pid3.Kd3&#61;0.2;
}
float PID3_realize(float speed)
{int index&#61;0;pid3.SetSpeed3&#61;speed;pid3.err3&#61;pid3.SetSpeed3-pid3.ActualSpeed3;pid3.integral3&#43;&#61;pid3.err3;if(abs((int)pid3.err3)>200)//积分分离{index&#61;0;}else{index&#61;1;pid3.integral3&#43;&#61;pid3.err3;}pid3.voltage3&#61;pid3.Kp3*pid3.err3&#43;index*pid3.Ki3*pid3.integral3&#43;pid3.Kd3*(pid3.err3-pid3.err_last3);pid3.err_last3&#61;pid3.err3;pid3.ActualSpeed3&#61;pid3.voltage3*1.0;return pid3.ActualSpeed3;
}

2.3 位置式 方式3–积分饱和

struct t_pid4
{float SetSpeed4; float ActualSpeed4; float err4; float err_last4;float Kp4,Ki4,Kd4;float voltage4; float integral4; float umax4;float umin4;
}pid4;
void PID4_init()
{pid4.SetSpeed4&#61;0.0;pid4.ActualSpeed4&#61;0.0;pid4.err4&#61;0.0;pid4.err_last4&#61;0.0;pid4.voltage4&#61;0.0;pid4.integral4&#61;0.0;pid4.Kp4&#61;0.2;pid4.Ki4&#61;0.1; pid4.Kd4&#61;0.2;pid4.umax4&#61;400;pid4.umin4&#61;-200;
}
float PID4_realize(float speed)
{int index;pid4.SetSpeed4&#61;speed;pid4.err4&#61;pid4.SetSpeed4-pid4.ActualSpeed4;if(pid4.ActualSpeed4>pid4.umax4) //示抗积分饱和{if(abs(pid4.err4)>200) //积分分离{index&#61;0;}else{index&#61;1;if(pid4.err4<0){pid4.integral4&#43;&#61;pid4.err4;}}}else if(pid4.ActualSpeed4<pid4.umin4){if(abs(pid4.err4)>200)//积分分离{index&#61;0;}else{index&#61;1;if(pid4.err4>0){pid4.integral4&#43;&#61;pid4.err4;}}}else{if(abs(pid4.err4)>200){index&#61;0;}else{index&#61;1;pid4.integral4&#43;&#61;pid4.err4;}}pid4.voltage4&#61;pid4.Kp4*pid4.err4&#43;index*pid4.Ki4*pid4.integral4&#43;pid4.Kd4*(pid4.err4-pid4.err_last4);
// pid4.voltage4&#61;pid4.Kp4*pid4.err4&#43;index*pid4.Ki4*pid4.integral4/2&#43;pid4.Kd4*(pid4.err4-pid4.err_last4);pid4.err_last4&#61;pid4.err4;pid4.ActualSpeed4&#61;pid4.voltage4*1.0;return pid4.ActualSpeed4;
}

2.4 位置式 方式4

struct t_pid5
{float SetSpeed5;float ActualSpeed5;float err5;float err_last5;float Kp5,Ki5,Kd5;float voltage5;float integral5;
}pid5;
void PID5_init()
{pid5.SetSpeed5&#61;0.0;pid5.ActualSpeed5&#61;0.0;pid5.err5&#61;0.0;pid5.err_last5&#61;0.0;pid5.voltage5&#61;0.0;pid5.integral5&#61;0.0;pid5.Kp5&#61;0.4;pid5.Ki5&#61;0.2;pid5.Kd5&#61;0.2;
}
float PID5_realize(float speed)
{float index;pid5.SetSpeed5&#61;speed;pid5.err5&#61;pid5.SetSpeed5-pid5.ActualSpeed5;if(abs(pid5.err5)>200){index&#61;0.0;}else if(abs(pid5.err5)<180){index&#61;1.0;pid5.integral5&#43;&#61;pid5.err5;}else{index&#61;(200-abs(pid5.err5))/20;pid5.integral5&#43;&#61;pid5.err5;}pid5.voltage5&#61;pid5.Kp5*pid5.err5&#43;index*pid5.Ki5*pid5.integral5&#43;pid5.Kd5*(pid5.err5-pid5.err_last5);pid5.err_last5&#61;pid5.err5;pid5.ActualSpeed5&#61;pid5.voltage5*1.0;return pid5.ActualSpeed5;
}

总结&#xff1a;从上面公式可以发现&#xff0c;对照PID控制算法&#xff08;一&#xff09;&#xff0c;其实就分位置式与增量式至于实现过冲&#xff0c;其实是一样的&#xff0c;只不过合并同类项不同而已。


推荐阅读
author-avatar
蒋小宁蒋小羊
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有