亿加合和智能车制作

标题: PID控制算法的个人理解,分享给和我一样的新手 [打印本页]

作者: 小车车    时间: 2013-11-1 13:03
标题: PID控制算法的个人理解,分享给和我一样的新手
PID控制算法,当时看了感觉很迷糊,不知道为什么,总感觉不靠谱,但是有没有实际的办法验证,看了很多例子,用了比较容易理解的例子,但是自己还是不相信。想了想,就自己构建了一个模型,在电脑上有验证了下,用的是vc6.0软件,可以清楚的看到输入和输出的次数,接近程度,需要的下载看看吧,也许有用,如果发现错误,还是希望能给个回复,指出来,让大家共同进步下。

作者: 小车车    时间: 2013-11-1 13:37
PID调节分为位置式和增量式,小车里面应该用的是位置式。看似很复杂的公式其实也没有那么令人捉摸不透,假设现在就是一个控制小车的车速度的问题,在任何一个时刻,一个环境,要想让小车的速度按照一个速度输出。必然存在着一个输入。这个输入值不能确定,确切说不能用数学公式准确的刻画,而且环境时刻在改变,即使知道了输入值和输出速度的关系,环境一旦改变对应关系自然也就变了,为了解决这个复杂问题,所以才引入了PID调节。
需要明白的是小车的速度和输入之间的关系不是线性的,肯定不存在v=k*in这种表达式。如果真的是这样的话,只需要一个k就可以调节了,假如现在的速度是3m/s,输入电压是3v,要想达到4m/s仅仅需要使得输入增大1v就搞定了,存在着数学关系in=in+(v1-v)*k0;v1是想要达到的速度,v是现在的速度,这个k0是可以确定的也就是k的倒数。但是这么做不切实际。
当初存在很多疑惑,认为通过这个k0调节足够,当初我认为即使只有k0输出也会在目标输出值上下进行震荡,但是会慢慢的靠近,一直可以成功达到标准的输出。没有必要用积分和微分,后来就用C语言编写一个程序简单的验证下自己的猜想。
已经知道了v和i之间的不存在线性关系。所以自己假设在一切条件不变的情况下存在着一个固定的数学关系式,当然不是线性的,为了方便起见,我们假设v=in*in;这个是存在的,但是假设我们还不知道,所以不能直接用这个公式控制速度。
假设现在in=1;v自然等于1,现在目标是要求v输出4,应该怎么办呢。
假设只有比例项控制C语言程序如下所示:
double y=16,x=4;,y1=100;//y=x*x,然后取得系数k=0.1
        //double  err=0;
        //double  err_array[100]={0};
        int i,t;
       
        while(1)
        {
        for(i=1;i<100;i++)
        {
                x=x+(y1-y)*0.1;//+(err_array[i]-err_array[i-1])*0.001;
                //err_array[i]=(64-y);
                y=x*x;
                printf("%d:  %lf  %lf\n",i,x,y);
               
        }
通过更改x和y的初始值和目标值运行可以观测程序运行结果,现在目标值是y1=100;系数目前是0.1
我把目标值改了。改成了81,x=9的时候才是理想控制,看一下运行结果。

果然和我想的一样开始x的值在应该输出的值上下震荡,逐渐接近于9,在第68次x=9.0000;这只是一个,貌似看着这样也可以控制,不需要积分和微分,
但是把x和y的值改变了,目标值改变下就不那么乐观了,比如说我现在把y1改成100,那么x输出应该是10才对,或者是一个非常非常接近与10的数,

这就是事实,执行10000次任然是一个10.07误差还是非常非常大的,说明系统存在某些不可消除的误差,仅仅靠比例项是不可行,很自然,比例项越大,达到目标值越快,但是也不是越大越好,过大震荡就很难消除,时间变长。要求控制速度是快,准,狠。时间长了自然是不行啊。电脑上不能随便设定系数,否则就没有结果了。上面这个次数当然是越少越好了。下面是引入了积分,其实这个积分就是求和,这个不像数学表达式是连续的,是间断的。采样周期也就是1ms吧。
下面是引入了积分的程序:

        double y=16,x=4; //y=x*x,然后取得系数k=0.1
        double  err=0;
        double  err_array[200]={0};
        int i,t;
        while(1)
        {
        for(i=1;i<100;i++)
        {
                x=x+(100-y)*0.1+(err_array[i-1]-err_array[i])*0.001;
                err_array[i]=(64-y);
                y=x*x;
                printf("%d:  %lf  %lf\n",i,x,y);
        }
在没有引入积分前100次后的结果是这个

引入积分后则是:


10.100和10.656,发现积分确实可以减少误差,一定存在着积分系数使得x更逼近或者能够达到目标值,只不过我没有仔细一个个实验,调节系数。系数一个个调,第一个确定了才能继续调节第二个,先调的是比例项,然后是积分项。这里只是一个简单的比方,没有过多的实际用处,也就是帮助理解下关系。实际用的时候恐怕要复杂点。
还有一个是微分系数,微分是就是求两次误差差值的差,反应了误差的变化趋势,有预测的意味。
下面是使用了微分后的代码
double y=16,x=4; //y=x*x,然后取得系数k=0.1
        double  err=0;
        double  err_array[200]={0};
        double  err_array1[200]={0};
        int i,t;
        while(1)
        {
        for(i=1;i<100;i++)
        {
                x=x+(100-y)*0.1+(err_array[i-1]-err_array[i])*0.001+(err_array1[i]-err_array1[i-1])*0.001;
                err_array1[i]=err_array[i-1]-err_array[i];
                err_array[i]=(64-y);
                y=x*x;
                printf("%d:  %lf  %lf\n",i,x,y);
        }
结果是:

更精准了一步,这就是一个简单的PID吧。
这是文本内容,图片内容见下载的文档
作者: yukunlinykl    时间: 2013-11-1 15:27
用excel或者origin或者matlab来仿真就方便多了。
作者: 小车车    时间: 2013-11-1 16:28
yukunlinykl 发表于 2013-11-1 15:27
用excel或者origin或者matlab来仿真就方便多了。

哦,谢谢哈 matlab还没有学,excel确实方便,可以直接看到图,更直观。

作者: 小布的梦    时间: 2013-11-1 19:17
受教啦 !:lol
作者: 飞鸿印雪    时间: 2013-11-1 21:12
这个学了自动控制原理   就都理解了
作者: jieyingxiao    时间: 2013-11-2 10:08
:)
作者: 刘浩宇    时间: 2013-11-6 09:15
搞不懂这个式子到底是增量式还是位置式? x=x+(y1-y)*0.1; 看y1-y这个是本次误差,应该是位置式,但是为什么要加x,不是增量式才需要再加上前一次的值么。
作者: 拉风滴小伙儿    时间: 2013-11-8 20:44

作者: 中华旺仔    时间: 2013-11-11 19:10

作者: 小布的梦    时间: 2014-1-16 22:15
看看!
作者: lanyu4577    时间: 2014-1-17 21:12
受教
作者: 小布的梦    时间: 2014-1-22 00:31
感觉很好

作者: 风流★花!少℃    时间: 2014-3-1 22:31
学习了
作者: 打出一片天!    时间: 2014-5-18 18:28
还是没看明白
作者: minnuli    时间: 2014-6-26 22:57

作者: wss425    时间: 2014-7-8 09:45
不错
作者: 五加六等于一    时间: 2014-8-1 08:38
不明觉厉
作者: cxr18220662742    时间: 2019-3-22 13:48
谢谢楼主分享




欢迎光临 亿加合和智能车制作 (http://111.231.132.190/) Powered by Discuz! X3.2