PID算法的原理和实现(二)

上一节我们主要讲了什么是PID,以及PID的主要原理,这一章我们来讲PID的分类以及实现。

PID的分类

PID在离散域中主要分为两大类:位置式PID和增量式PID。二者之间有什么区别和联系呢?听我细细道来。

位置式PID

位置式的PID的表达公式为:位置式PID公式

KP:比例系数
ek:第k次的输入量与目标量的偏差值
KI:积分系数
KI后面的乘数:每次的偏差值的累加
KD:微分系数
ek - ek-1:第k次的偏差值和第k-1次的偏差值的差值

位置式PID的优点就是能够记录一开始到现在的偏差值,能够更好的将系统给稳定下来,达到的稳定值更接近目标值。

有利也有弊,他也有对应的缺点:首先因为要记录一开始到现在的偏差值,所以计算量就很大;再者还是因为它的积分项是一直累加的,所以他有时就会出现超出输出值的现象,所以还要加入积分项的限幅条件。总之这个累加的积分项既可以是它的优势又是它的劣势。

以下是C语言的代码实现:

#define IntegralMAX	1000	//积分项上限
#define IntegralMIN	0		//积分项下限
struct _pid{
	float SetSpeed;             //实际速度
	float ActualSpeed;          //目标速度
	float err;                  //偏差值
	float err_last;            //上次的偏差值
	float Kp,Ki,Kd;            //比例系数、积分系数、微分系数
	float P,I,D;
}pid;
/*
******PID各个系数的初始化函数******
*函 数 名:PID_init
*输	入:
		Kp:比例系数
		Ki:积分系数
		Kd:微分系数
*/
void PID_init(float Kp,float Ki,float Kd){
	pid.SetSpeed = 0.0;
	pid.ActualSpeed = 0.0;
	pid.err = 0.0;
	pid.err_last = 0.0;
	pid.Kp = Kp;
	pid.Ki = Ki;
	pid.Kd = Kd;
}
/*
******PID算法的实现函数******
*函 数 名:PID_realize
*输	入:
		new_speed:实际速度
		hope_speed:目标速度
*输	出:
		PID的控制值
*/
float PID_realize(float *new_speed,float hope_speed){
	pid.SetSpeed = hope_speed;
	pid.ActualSpeed = *new_speed;
	pid.err = pid.SetSpeed - pid.ActualSpeed;
	pid.P = pid.err * pid.Kp;
	pid.I = pid.I + pid.err * pid.Ki;
	if(pid.I > IntegralMAX)
		pid.I = IntegralMAX;
	if(pid.I < IntegralMIN)
		pid.I = IntegralMIN;
	pid.D = (pid.err_last - pid.err) * pid.Kd;
	*new_speed = pid.P + pid.I + pid.D;
	pid.err_last=pid.err;
	return *new_speed;
}

增量式PID

增量式的PID的表达公式为:

增量式PID

其实这个增量式是从位置式变形过来的将第K次的控制值减去第K-1次的控制值得到一个控制值的差值,这个差值就是增量式PID的输出。

从表达式中可以很好的看出这个增量式的优点:我们只需要知道前后三次的测量值就能够求出控制的增量,而且它的误差量不会累积。

但也是因为它简单的计算,就会造成部分受控对象出现稳态误差。

以下是C语言的实现代码:

struct _pid{
	float SetSpeed;             //实际速度
	float ActualSpeed;          //目标速度
	float err;                  //偏差值
	float err_last;            //上次的偏差值
	float err_last_last;		//上上次的偏差值
	float Kp,Ki,Kd;            //比例系数、积分系数、微分系数
	float P,I,D;
}pid;
/*
******PID各个系数的初始化函数******
*函 数 名:PID_init
*输	入:
		Kp:比例系数
		Ki:积分系数
		Kd:微分系数
*/
void PID_init(float Kp,float Ki,float Kd){
	pid.SetSpeed = 0.0;
	pid.ActualSpeed = 0.0;
	pid.err = 0.0;
	pid.err_last = 0.0;
	pid.err_last_last = 0.0;
	pid.Kp = Kp;
	pid.Ki = Ki;
	pid.Kd = Kd;
}
/*
******PID算法的实现函数******
*函 数 名:PID_realize
*输	入:
		new_speed:实际速度
		hope_speed:目标速度
*输	出:
		PID的控制量的增量
*/
float PID_realize(float new_speed,float hope_speed){
	pid.SetSpeed = hope_speed;
	pid.ActualSpeed = new_speed;
	pid.err = pid.SetSpeed - pid.ActualSpeed;
	pid.P = pid.err * pid.Kp;
	pid.I = pid.err_last * pid.Ki;
	pid.D = pid.err_last_last * pid.Kd;
	pid.err_last=pid.err_last_last;
	pid.err_last_last=pid.err;
	return pid.P - pid.I + pid.D;
}

其实PID的实现并不难,只要能够理解PID的原理,能够运用它的公式,要想实现它就非常的简单了。

今天就到这里,以后我会更新我用PID调节的小车。
谢谢大家的观看。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值