极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 49241|回复: 40

PID学习笔记(先翻译大神教程)

  [复制链接]
发表于 2011-11-16 11:24:00 | 显示全部楼层 |阅读模式
本帖最后由 三水 于 2011-11-16 11:47 编辑

提高初学者PID原文地址:
http://brettbeauregard.com/blog/ ... s-pid-introduction/

提高初学者的PID:
这里是第一次接触PID需要学习的公式:
pidalgorithm-300x72.png
它能引导大多数人写出如下的PID控制器代码:
  1. /*working variables*/
  2. unsigned long lastTime;
  3. double Input, Output, Setpoint;
  4. double errSum, lastErr;
  5. double kp, ki, kd;
  6. void Compute()
  7. {
  8.    /*How long since we last calculated*/
  9.    unsigned long now = millis();
  10.    double timeChange = (double)(now - lastTime);

  11.    /*Compute all the working error variables*/
  12.    double error = Setpoint - Input;
  13.    errSum += (error * timeChange);
  14.    double dErr = (error - lastErr) / timeChange;

  15.    /*Compute PID Output*/
  16.    Output = kp * error + ki * errSum + kd * dErr;

  17.    /*Remember some variables for next time*/
  18.    lastErr = error;
  19.    lastTime = now;
  20. }

  21. void SetTunings(double Kp, double Ki, double Kd)
  22. {
  23.    kp = Kp;
  24.    ki = Ki;
  25.    kd = Kd;
  26. }
复制代码
Compute()被称作定期或不定期的,它工作非常正常。虽然这个系列不是“工作的最好的”。如果我们想做出和工业PID控制器相近的驱动器,我们需要解决几个问题:
Sample Time(采样时间)——如果这是一个固定的时间间隔,PID算法的功能实现将是非常好的。如果已知了这个间隔时间,代码中也可以简化一些内部的数学运算。
Derivative Kick(微分的过冲)——不是最大的问题,但是很容易解决,所以我们也将处理这个问题。
On-The-Fly Tuning Changes——好的PID函数是当调整参数的时候不会干扰内部运算的。
Reset Windup Mitigation(缓解积分饱和)——我们将会了解什么是积分饱和,并且在有利的方向上进行解决方案的实施。
On/Off (Auto/Manual)(开关-自动或手动)——在大多数应用中,有时候我们希望关闭PID控制器手动调节输出而不受控制器的干涉。
Initialization(初始化)——当控制器打开的时候我们希望是“无扰切换”,即我们不希望输出值忽然变成一个新的值。
Controller Direction(控制器的方向)——这是最后一个不是在鲁棒本身名称下的变化。它是为了确保用户能输入正确的调优参数而设计的。

一旦我们解决了这些问题,我们将有一个对PID算法深刻的了解。我们还会拥有最新的Arduino PID控制库。所以不管你是想自己写出自己的PID算法还是想去了解PID算法里到底发生了什么,我希望这些都能帮上你。现在我们开始旅程吧。

评分

参与人数 1 +2 收起 理由
弘毅 + 2 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2011-11-16 11:45:17 | 显示全部楼层
三水老弟,再提炼提炼变成我们国人自己的语言就完美了.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-11-16 12:04:34 | 显示全部楼层
提高初学者的PID——采样时间
初学者的PID被称作不规则的,这就有了以下两个问题:
》你没有从PID中得到一致的状态特性,因为有时它是非常快的变化,有时却没有。
》你需要额外的数学运算解决微分和积分,它们都同时依赖于时间的变化。

解决方法:
确保PID定义在一个固定的时间间隔里。我这样做的原因是让compute指令每个周期都被调用一次。根据之前设定好的采样周期,PID决定是该计算还是立刻返回值。

一旦我们知道了PID是在一个恒定的时间内运算,微分和积分也就变得简单了。

代码:
  1. /*working variables*/
  2. unsigned long lastTime;
  3. double Input, Output, Setpoint;
  4. double errSum, lastErr;
  5. double kp, ki, kd;
  6. int SampleTime = 1000; //1 sec
  7. void Compute()
  8. {
  9.    unsigned long now = millis();
  10.    int timeChange = (now - lastTime);
  11.    if(timeChange>=SampleTime)
  12.    {
  13.       /*Compute all the working error variables*/
  14.       double error = Setpoint - Input;
  15.       errSum += error;
  16.       double dErr = (error - lastErr);

  17.       /*Compute PID Output*/
  18.       Output = kp * error + ki * errSum + kd * dErr;

  19.       /*Remember some variables for next time*/
  20.       lastErr = error;
  21.       lastTime = now;
  22.    }
  23. }

  24. void SetTunings(double Kp, double Ki, double Kd)
  25. {
  26.   double SampleTimeInSec = ((double)SampleTime)/1000;
  27.    kp = Kp;
  28.    ki = Ki * SampleTimeInSec;
  29.    kd = Kd / SampleTimeInSec;
  30. }

  31. void SetSampleTime(int NewSampleTime)
  32. {
  33.    if (NewSampleTime > 0)
  34.    {
  35.       double ratio  = (double)NewSampleTime
  36.                       / (double)SampleTime;
  37.       ki *= ratio;
  38.       kd /= ratio;
  39.       SampleTime = (unsigned long)NewSampleTime;
  40.    }
  41. }
复制代码
在第10和第11行,如果它的时间可以计算出来,那就将由算法本身决定。因为我们现在知道样本之间的时间是相同的,我们并不需要不断乘以时间的变化。我们只需要适当调整Ki和Kd(30和31行),虽然在数学上的结果是等价的,但更有效。

虽然这样做又一个小小的波动。如果用户在操作过程中决定改变采样时间,Ki和Kd将需要重新调整来以对这一新的变化做出反应。这就第39-42行代码所处理的问题。

另外请注意我在第29行将采样时间转换成秒s了。严格的的说这是没有必要的,只是允许用户输入的Ki和Kd是uint型的s而不是ms。

……待续
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-11-16 12:06:52 | 显示全部楼层
ChocolateUni 发表于 2011-11-16 11:45
三水老弟,再提炼提炼变成我们国人自己的语言就完美了.

T T还得好好学习PID,能应用了应该能写点学习总结
回复 支持 反对

使用道具 举报

发表于 2011-12-4 17:18:12 | 显示全部楼层
呵呵,山水牛呀~
回复 支持 反对

使用道具 举报

发表于 2012-1-8 11:43:07 | 显示全部楼层
ANDROID的PID_v1  Lib 有使用的例子么
回复 支持 反对

使用道具 举报

发表于 2012-1-10 11:50:19 | 显示全部楼层
我在想我的小车跑偏定位修正是否能用PID....太高深了啊
回复 支持 反对

使用道具 举报

发表于 2012-2-2 15:33:52 | 显示全部楼层
收藏下,谢谢分享。
回复 支持 反对

使用道具 举报

发表于 2012-2-2 20:32:18 | 显示全部楼层
不错啊,山水
回复 支持 反对

使用道具 举报

发表于 2012-2-10 21:09:38 | 显示全部楼层
看不懂。。不明白用途用法
回复 支持 反对

使用道具 举报

发表于 2012-3-24 15:57:11 | 显示全部楼层
我想知道Arduino的库有什么不一样,好像pid算法本身很简单,为啥非要写成个库文件呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-3-24 17:15:50 | 显示全部楼层
黑马 发表于 2012-3-24 15:57
我想知道Arduino的库有什么不一样,好像pid算法本身很简单,为啥非要写成个库文件呢?

我看了下arduino的库,只是直接调用。确实,只有那几行代码而已
回复 支持 反对

使用道具 举报

发表于 2012-3-24 17:23:22 | 显示全部楼层
三水 发表于 2012-3-24 17:15
我看了下arduino的库,只是直接调用。确实,只有那几行代码而已

嗯,好像还有个自整定的库,不知道怎么样,看起来比较大
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-3-24 20:59:31 | 显示全部楼层
黑马 发表于 2012-3-24 17:23
嗯,好像还有个自整定的库,不知道怎么样,看起来比较大

但是方便使用,估计就这个功能而已。PID库有个是直接设置PID三个数值直接使用输出值就是。
回复 支持 反对

使用道具 举报

发表于 2012-3-26 17:39:54 | 显示全部楼层
关于采样时间还是想不通,原本的时间微分相当于计算了两次计算的实际间隔。而在第二个帖子里改成了时间超过采样时间才重新计算,并把采样时间当成时间的微分。前者可以理解,毕竟没必要那么频繁的进行变动,但是后者似乎没什么优势么,无非减小了一次减运算,用近似值代替,感觉有点得不偿失呢?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-3-21 22:11 , Processed in 0.053096 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表