增量式PID的程序和疑问
本帖最后由 FuARM 于 2014-1-3 11:07 编辑这是本人按照公式写的一个增量式PID的程序,和测试程序,不知正确与否,恳请懂的人指出错误和建议。
想用在小车直流电机的控制上来,直流电机上有挡光片测速。MCU PWM调节转速。
按照推荐的调节PID的步骤,先将Ki=Kp*T/Ti置位0,将Kd=Kp*Td/T=0,当作纯比例控制器来调节,
因此让Ti=10000000.0(足够大就行,让Ki接近0),Td=0。此时A=Kp,B=-Kp;C=0;
增量计算(根据后面的程序改的伪代码):
e_0 = Set - Get;//目标值-本次测量值
delta = A*e_0 + B*e_1 + C*e_2 = Kp(e_0 - e_1) ;
e_2 = e_1;
e_1 = e_0;
out += delta;
那么,按照以上推导,在纯比例控制中,增量=Kp*(前两次误差的差值);
我的疑问是:
假设目标值是100,初始状态e_0=0,e_1=0;
时刻1测量值是10,那么误差就是90,e_0=90,e_1=0;那么delta增量会有一个值,同时实际输出量out也有一个值
如果时刻2测量值还是10,那么e_0=90,e_1=90; Kp(e_0 - e_1) =0;delta增量=0,此时out不增加。
试想,当输出量out还不足以驱动电机或者电机被负载堵转时,误差恒定不变,但是delta却等于0,输出out不变,电机也不会增加力矩,这似乎有悖我们控制电机转速的初衷。
以上是我的理解,不知道正确么,恳请大家指导。
/************************************************************************/
#include <math.h>
#define Kp (1.0) //PID调节的比例常数
#define Ti (10000000.0) //PID调节的积分常数
#define Td (0.0) //PID调节的微分时间常数
#define T (0.1) //采样周期
#define AA(Kp * (1 + (T / Ti) + (Td / T))) //A
#define BB ((-Kp) * (1+(2 * Td / T))) //B
#define CC (Kp * Td / T) //C
//误差的阀值,小于这个数值的时候,不做PID调整,避免误差较小时频繁调节引起震荡
#define Emin 3
//调整值限幅,防止积分饱和
#define Umax 20
#define Umin -20
//输出值限幅
#define Pmax 245
#define Pmin 0
typedef struct PID
{
int Set;//目标值
int Get;//当前测量值
int e_1;
int e_2;
double A;
double B;
double C;
int delta;
int out;
}PID_t;
void pid_init(PID_t * pPID);
void pid_ctrl(PID_t * pPID);
void pid_init(PID_t * pPID)
{
pPID->Set = 0;
pPID->Get = 0;
pPID->e_1 = 0;
pPID->e_2 = 0;
pPID->delta = 0;
pPID->out = 0;
pPID->A=AA;
pPID->B=BB;
pPID->C=CC;
}
void pid_ctrl(PID_t * pPID)
{
int e_0 = pPID->Set - pPID->Get;//求差值
pPID->delta = (int)(pPID->A*e_0 + pPID->B*pPID->e_1 + pPID->C*pPID->e_2);
pPID->e_2 = pPID->e_1;
pPID->e_1 = e_0;
pPID->out += pPID->delta;
}
PID_t PID_A;
void main(void)
{
int i;
pid_init(&PID_A);
printf("Kp=%f,Ki=%f,Kd=%f\n",Kp,(Kp*T/Ti),(Kp*Td/T));
printf("A=%f,B=%f,C=%f\n\n",AA,BB,CC);
printf("input the set val\n");
scanf("%d",&PID_A.Set);
printf("Set=%d\n",PID_A.Set);
while(1){
scanf("%d",&PID_A.Get);
pid_ctrl(&PID_A);
printf("get=%8d\n",PID_A.Get);
printf("delta=%8d, out=%8d\n",PID_A.delta,PID_A.out);
printf("e_1=%8d, e_2=%8d\n",PID_A.e_1,PID_A.e_2);
}
printf("leave");
}
发个公式,以上程序,就是按照这个公式来写的,应该是没有违背公式的。 没弄过PID,来学习 FuARM 发表于 2014-1-3 11:17
发个公式,以上程序,就是按照这个公式来写的,应该是没有违背公式的。 ...
先别管这些,先上实际系统,调试好电机驱动,旋转编码器以后再说如何转化理论公式的问题。
纸上谈兵对PID学习一点用都没有。 Gorgon_Meducer 发表于 2014-1-4 16:25
先别管这些,先上实际系统,调试好电机驱动,旋转编码器以后再说如何转化理论公式的问题。
纸上谈兵对PID ...
嗯,在实际板子上调试,电机速度基本调稳了,感觉效果还是很好的,速度比较稳定,施加一定的阻力给电机,速度也能稳定。
用的就是我发的这个代码的一个变形pPID->delta = pPID->Kp*((e0 - pPID->e_1)+pPID->Ki*e0+pPID->Kd*(e0-2* pPID->e_1+ pPID->e_2));
公式一样,只是把Kp,Ki,Kd分离出来调。
但是还是不明白,如果Ki=0,Kd=0;那么增量就是pPID->Kp*((e0 - pPID->e_1);电机堵转,或者速度被人为的限制死,那么前后两次的误差,应该就是相等的啊,于是增量岂不是0了?
我想应该是我的理解有问题。。。 增量为零不代表输出为零。增量式PID的输出是所有以前的累加量,而不是当前的增量。 学习贴,准备自己尝试一下 chenbelief_007 发表于 2014-1-5 23:12
增量为零不代表输出为零。增量式PID的输出是所有以前的累加量,而不是当前的增量。 ...
嗯,增量式PID的输出是所有以前的累加量,这个是对的。
但是我说的前提是,此时的转速已经被外力限定了,因此前后两次的误差之差应该是等于0,那么PID的输出就不会变(Ki=0;Kd=0),
我的理解是,此时如果PID的输出没有达到最大的话,如果电机速度没有达到目标速度,那么PID控制器理应继续增大输出量试图提高转速才对。 谢谢。。。。。。。 chenbelief_007 发表于 2014-1-5 23:12
增量为零不代表输出为零。增量式PID的输出是所有以前的累加量,而不是当前的增量。 ...
这么举个例子吧,还是看Ki,Kd都为0的纯比例的增量式。
假如PID输出量在增加的过程中,使得电机力矩和阻力恰好平衡了,而这时候还没有达到输出量的最大值,转速也没有达到目标速度,
根据公式计算,增量为0,输出量不再增加。
我感觉不合理的地方是:此时既然没有达到目标速度,而且输出量也没有达到最大,那么对于一个理想的控制器而言,应该继续增大输出才对啊,应该“竭尽全力”。
我想我的理解一定是错在哪里。恳请帮忙。 这时需要积分项来达到你的效果,一旦存在误差,积分项会不断增大,这时的输出就会增加,直到当前误差为零。 不应该说是积分项在增大,应该说增量不为零,输出就可以一直增加。 chenbelief_007 发表于 2014-1-6 14:40
不应该说是积分项在增大,应该说增量不为零,输出就可以一直增加。
关键现在看来,增量是0呀 反馈啊 正在准备自己弄一个~ 楼主你好,先借你的程序用一下,呵呵 ,在写毕设。
不知这个问题后来你思考的结果如何?我空想了一下,你设定的前提条件有问题,因为系统不可能凭空由一种状态突变到你所说的恒定误差状态。哪怕真的是从误差0突变到误差X,那也是一种阶跃,比例环节必然要做出响应,类似于系统启动t=0的时刻。
除非你debug然后自己改变量数值 {:biggrin:}
你觉得呢?
alexbird 发表于 2014-5-23 14:38
楼主你好,先借你的程序用一下,呵呵 ,在写毕设。
不知这个问题后来你思考的结果如何?我空想了一下,你 ...
我赶脚,也是这么个事儿。{:smile:} alexbird 发表于 2014-5-23 14:38
楼主你好,先借你的程序用一下,呵呵 ,在写毕设。
不知这个问题后来你思考的结果如何?我空想了一下,你 ...
我赶脚,也是这么个事儿。 {:smile:} FuARM 发表于 2014-5-29 11:48
我赶脚,也是这么个事儿。
但是,如果测量环节突然出错了,出现我说的恒定误差呢? alexbird 发表于 2014-5-23 14:38
楼主你好,先借你的程序用一下,呵呵 ,在写毕设。
不知这个问题后来你思考的结果如何?我空想了一下,你 ...
但是,如果测量环节突然出错了,出现我说的恒定误差呢? FuARM 发表于 2014-5-29 11:51
但是,如果测量环节突然出错了,出现我说的恒定误差呢?
都出错了,还谈什么呢
位置式PID出错的话,输出是错误的绝对位置,机器就直接飞了,比你这错误的后果严重多了。。。 还在努力学习中 学习了! FuARM 发表于 2014-1-5 22:39
嗯,在实际板子上调试,电机速度基本调稳了,感觉效果还是很好的,速度比较稳定,施加一定的阻力给电机, ...
楼主感觉到了这个时候就变成类似位置式的"静态误差" 了 对PID也不怎么理解来着里求解答~ 最近也在学习这个,非常感谢楼主。 楼主还在否?也在想找个问题。
Kp_speed*(devk-devk_1)+Ki_speed*devk
纯Kp下如果2次误差相等,输出就为0啊。 我也遇到了楼主这种问题,电机在启动前检测转速为0,pwm输出为0,如果设定一个很小的目标值,这时如果纯比例环节的话Kp(e_0 - e_1) 很小不足以使电机转动,因此下一次计算时Kp(e_0 - e_1)变为0 ,pwm输出不变,电机还是转不起来,以后电机永远转不起来了。
页:
[1]