Bootstrap

关于PID的输入输出是什么--供自己复习使用

本人也是个新手,最近对平衡车感兴趣,所以恶补了一些关于pid的知识,下面是关于pid的文章,后续在平衡车上有进展也会出一些关于平衡车的文章。第一次写文章,有许多的不足之处,希望给位网友给予指正。

在过程控制中,按偏差的比例(P)、积分(I)和微分(D)进行控制的PID控制器(亦称PID调节器)是应用最为广泛的一种自动控制器。(该段摘自百度)

上面便是pid最简要的描述,而关于pid的细讲P,I,D这三部分是干什么的,想要学习从最基础的公式变形到代码这一层,这些在网上有大量的资料,这里就不在赘述,下面来讲讲我对pid的一些特别的理解。


首先,先看公式

△u(k)=Kp * e(k)+Ki / T * ∫ e(k) dt+Kd*d e(k);

这个公式我们不用特别的去理解,按照上面的公式,可离散化之后用代码表示

float PID(float actual_val)
{
		/*计算目标值与实际值的误差*/
    err = target_val - actual_val;
  
    integral += err;    // 误差累积

		/*PID算法实现*/
    actual_val = Kp * err + 
                 Ki * integral + 
                 Kd * (err - err_last);
		/*误差传递*/
    err_last = err;
    
		/*返回当前实际值*/
    return actual_val;
}

便得到位置式pid,一般在运用到位置式pid的时候,直接复制这段公式就可以直接用了。

从位置式pid做差求增量,便可得到增量式pid

△u(k)=Kp * e(k-1)+Ki *e(k) +Kd *(e(k)-2e(k-1)+e(k-2));

同样,这个公式不用太在意,看不懂没太大关系,主要是要有对增量式pid的大概印象就行,重要的是代码部分:

float PID(float actual_val)
{
	/*计算目标值与实际值的误差*/
  err=target_val-actual_val;
	/*PID算法实现*/
	actual_val += Kp*(err - err_next) 
                 + Ki*err 
                 + Kd*(err - 2 * err_next + err_last);
	/*传递误差*/
	err_last = err_next;
	err_next = err;
	/*返回当前实际值*/
	return actual_val;
}

由公式可看到增量式pid与最近三次的error有关。增量式与位置式的代码部分大部分相同,但它们的实际运用大不相同.它们具体区别可参考文章位置式PID与增量式PID区别浅析


说完基本的,再来说说本章重点,这是困惑我,也可能是困惑大部分新手许久的一个问题,pid算法的输入与输出是什么呢?为什么在用pid控制电机转速的时候输入一个编码器的测量值就可以自动输出一个数,这个数可以直接用于pwm占空比的设置,从而直接控制电机呢?看完接下来的文章,希望可以帮助你解决这个问题。


假设我们设置一个定时器,来定时读取编码器的值,相邻两次读取的值做差得到值a,只要a一直保持不变,是不是电机的速度也就一直不变呢。有了这个最简单的控制电机转速的概念,就可以引用pid算法了。我们假设目标值target_val=200,一开始电机不转,读取做差测得的值便是0,这时就会产生error,有了error,pid就可以运算,假设pid运算出来的值b=1,用这个值去设置pwm占空比,显然太小,电机甚至不转动,然而电机不转动,继续产生error,产生的过程与之前说的同理,但是由于积分i的作用这次pid运算出来的值b更大了,假如b=2吧,用b去设置pwm的占空比,还是太小,电机还是不动,那就接着pid运算,如此反复,最终b=50,这个值刚好是电机转动了起来,但是速度太低,相邻两次读取编码器的值做差之后还是小于200,还是有error,继续pid运算,b一直增大,最终b达到某个值,使得电机的转速满足相邻两次读取编码器的值做差等于200这一条件,这时error为0,pid运算出来的值还是最终的那个b,最后稳定达到我们设置的预期值。总的来说,pid运算出的结果就是一个控制信号,其余的什么也不是,而输入的可以是任何东西。

理解上面的内容后,是不是就可以理解网上一些用电流,电压之类的与速度毫不相干的值来控制电机速度了呢?希望这篇文章对有这些疑惑的小伙伴有一定的帮助,这是我第一次写文章,为了巩固自己所学,同时也便利一下他人。

;