极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 94346|回复: 18

新人贴PID控制温度

[复制链接]
发表于 2014-5-21 11:14:22 | 显示全部楼层 |阅读模式
原文在这里http://www.geek-workshop.com/thread-704-1-1.html
http://www.geek-workshop.com/thread-197-1-1.html
我先是在他们的程序基础上做的,但是一直有瑕疵,经过总结做了些许修改,得到了比较满意的结果,所以和想大家分享一下

上代码:
  1. /***************************
  2. PID temp control for Arduino
  3. by yby
  4. 数据采集    2014-05-11
  5.    
  6. PID控制     
  7. PID整定
  8. 温度控制
  9. ************头文件***************/

  10. #include <OneWire.h>                                 //单总线的库
  11. #include <DallasTemperature.h>                    //DS18B20头文件

  12. /************ 传感器参数 ***********/
  13. #define ONE_WIRE_BUS 2                            //2号引脚是温度传感器所在引脚

  14. OneWire oneWire(ONE_WIRE_BUS);

  15. DallasTemperature sensors(&oneWire);

  16. /********** 温度传感器滤波用数值 *********/

  17. double Input=0.0;                                       //定义输入
  18. float f_angle = 0.0;                                     //滤波前的值
  19. float f_angle_old=0.0;                                 // 滤波处理后的温度值

  20. /*********** PID控制器参数 *********/
  21. unsigned long lastTime;                             // 前次时间
  22. float Output = 0.0;                                    // PID输出值
  23. double  lastErr=0.0,lLastErr=0.0;                 //前一次差值、前前一次差值e(k-1)、e(k-2)
  24. double q0,q1,q2;


  25. /************ 程序初始化 ***********/
  26. void setup() {
  27.     sensors.begin();                                    //温度传感器初始化
  28.     Serial.begin(9600);                                // 开启串口以便监视数据
  29.     delay(1000);                                        //1s延时用以准备
  30.   }
  31. /************** 主程序 *************/
  32. void loop()
  33. { unsigned long now = millis();                                      // 当前时间(ms)
  34.   double timeChange =(double)(now-lastTime)/1000;         // 采样时间(s)
  35.    
  36.         
  37.   sensors.requestTemperatures();
  38.   float temp=sensors.getTempCByIndex(0);                       //温度传感器所采集到的值赋给temp   
  39.   f_angle= temp;                                                          //temp赋给  f_angle用以消抖滤波
  40. /************** 温度传感器消抖滤波*************/
  41.   if((f_angle_old-f_angle>3)||(f_angle-f_angle_old>3))        //温度是一个大滞后,缓变值,所以如果突然变化超过3度,
  42.     Input = f_angle_old;                                                 //其实一度以上就可以把它当作噪声消除了
  43.     else Input = f_angle;                                                //此处滤波只是为了消除他对PID输出的影响,因此实际图表中仍能看到抖波

  44.    
  45.    
  46.     /************ PID控制器 ***********/
  47.     now = millis();                                                           // 当前时间(ms)
  48.          
  49.     float Kp = 0.54009801, KI =10.2, Kd =0.00973,Ki=0.0;      // 比例系数、积分系数、微分系数
  50.     float SampleTime = 4.35;                                            // 采样时间(s)
  51.     float Setpoint = 70;                                                    // 设定目标值(degree)
  52.     float outMin = 0, outMax = 50;                                    // 输出上限、输出下限            阀值最高只有50度,
  53.     if(timeChange >= SampleTime)                                   //判断是否到达设定采样时间
  54.       {double error = (double)Setpoint - Input;                    // 偏差值
  55.               
  56.               
  57. //             if((Setpoint-Input<0.4)&&(Setpoint-Input>0))                                          //这段注解了,可以作为积分分离PID,这样就可以只在一定范围内用PID
  58. //               {Ki=KI;}                                                                                         //为追求快速达到预定值的效果,可以在此范围以外使用PI调节
  59. //               else if((Setpoint-Input>-0.8)&&(Setpoint-Input<0))
  60. //                       {Ki=KI;}
  61. //               else Ki=0;
  62.          

  63.       
  64.       q0=(100.0/Kp)*(1+1/KI+Kd/1);                                                                       //这就是我与原本那几位用的不一样的公式的地方
  65.       q1=-(100.0/Kp)*(1+2*Kd/1);                                                                          //公式我会在后面列出来
  66.       q2=(100.0/Kp)*Kd/1;                                                                                     //主要原因我认为是出在积分处,原帖的积分计算方式虽然在数学层面上是一样的,但是在编程时还是有问题
  67.        Output = q0* error +q1*lastErr+q2*lLastErr;                                                   // 计算输出值
  68.        Output = constrain(Output, outMin, outMax);                                                   // 限定值域
  69.       
  70.        analogWrite(5,Output/140*255);                                                                   //我的加热器是用的PTC加热板,驱动方式是用的大功率电机驱动板,所以这里直接用PWM驱动5号引脚就好了
  71.                                                                                                                      //140是PTC满载时所能达到的温度,到140就恒温了
  72.        lLastErr = lastErr;                                    //上一次的偏差值已经成为上上次的偏差值了
  73.        lastErr  = error;                                      //这次的偏差值已经成为上一次的了
  74.        lastTime = now;                                     // 记录本次时间
  75.     }
  76. /************ 参数上传 ***********/
  77.   //  Serial.print(now);          // 计算时间
  78.    // Serial.print(",");
  79.     Serial.print(f_angle, 6);   // 输出的温度
  80.     Serial.print(",");
  81.    Serial.println(Output,6);    // PID输出阀值
  82.   //  Serial.println(";");

  83.     delay(90);
  84.     f_angle_old = f_angle;    //滤波对比用的,和上面的原理一样
  85. }
复制代码









这个公式的主要好处在于比之前使用的公式在实际使用中积分能力更强,虽然不是很明白为什么,
大概是因为计算时,位置型PID更适合计算机编程使用吧,这是书上写的。
下面是波形图
第一张是用的原帖的算法,可以看出曲线一直在震荡,我试了很多积分值大概测了20组左右都无法得到满意的波形
最后一张是用新算法得到的,效果还不错



备注一下:在曲线图中,灰色直线是设定的目标值,蓝颜色曲线是控制过程中的输出阀值,红色曲线为实际所测温度变化曲线。

图中的蓝色曲线之所以看起来不是圆滑的曲线就是因为温控系统有很大的滞后性,所以在采样频率上设置的非常低,接近5s左右,因此我们会看到锯齿状边缘。
单纯的比例调节和PD调节都具有一定的局限性。滞后性的存在更需要积分环节,不然温度永远无法达到恒温(此处恒温也是有一定的区间+/-0.5摄氏度)。

PID参数的整定有很多方法,网上有很多,我就不赘述了,个人觉得最重要的还是多做实验,自然就会找到其中的规律,第一次发帖如有谬误请多包含












本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2014-5-22 07:55:49 | 显示全部楼层
说实话,好烂!加温控制完全类似于开关量。
回复 支持 反对

使用道具 举报

发表于 2014-5-22 07:57:55 | 显示全部楼层
像接热水这类惯量如此大的系统,有比例环节P就够了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-5-22 10:07:57 | 显示全部楼层
PINKWALKMAN 发表于 2014-5-22 07:55
说实话,好烂!加温控制完全类似于开关量。

为什么说是开关量?为什么只需要比例环节?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-5-22 10:10:49 | 显示全部楼层
PINKWALKMAN 发表于 2014-5-22 07:57
像接热水这类惯量如此大的系统,有比例环节P就够了。

如果只有比例环节波形如下

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-5-22 10:14:22 | 显示全部楼层
PINKWALKMAN 发表于 2014-5-22 07:55
说实话,好烂!加温控制完全类似于开关量。

曲线图中蓝色的曲线为阀值,有连续的波形变化,红色的曲线为温度,所以我不能理解你所说的什么叫开关量
回复 支持 反对

使用道具 举报

发表于 2014-11-16 18:49:11 | 显示全部楼层
问下各位,我想试下用PID控制温度,通过PWM控制12v电压的话, 已经有一个12v/2.5a的变压器了,是否能用这种电压转换模块:   或其他?

http://item.taobao.com/item.htm?spm=a230r.1.14.1.36CI5w&id=39623115296&ns=1&abbucket=8#detail

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2014-11-16 19:42:40 | 显示全部楼层
菜鸟前来学习,绝对是好贴,赞一个!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-12-21 15:27:30 | 显示全部楼层
ssunrise 发表于 2014-11-16 18:49
问下各位,我想试下用PID控制温度,通过PWM控制12v电压的话, 已经有一个12v/2.5a的变压器了,是否能用这种 ...

可以用这样的装置来控制12V的电压,虽然用万用表测你的电压是有变化的,其实万用表取的只是平均值。所以,这个装置可以理解为高频率的继电器,但是比继电器更稳定,更高功率!推荐使用此类模块,还有更大功率和速度的此类模块可以在TB上找到!
回复 支持 反对

使用道具 举报

发表于 2016-9-23 11:02:18 | 显示全部楼层
ssunrise 发表于 2014-11-16 18:49
问下各位,我想试下用PID控制温度,通过PWM控制12v电压的话, 已经有一个12v/2.5a的变压器了,是否能用这种 ...

这种方法怎么样了  楼主
回复 支持 反对

使用道具 举报

发表于 2016-9-25 00:42:47 | 显示全部楼层
我先来mark一下,慢慢看
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-12-9 13:08:58 | 显示全部楼层
xia07134105 发表于 2016-9-23 11:02
**** 作者被禁止或删除 内容自动屏蔽 ****

不好意思好久没上论坛,这个是我的毕业设计当时得了奖。其实代码很简单,可以修改的地方还很多。如果有需要可以拿去用
回复 支持 反对

使用道具 举报

发表于 2020-4-19 22:20:13 | 显示全部楼层
您好请问下那个阈值50摄氏度为什么是50,还有 analogWrite(5,Output/140*255);     后面那个Output/140*255不是很懂。。
回复 支持 反对

使用道具 举报

发表于 2020-9-14 16:52:29 | 显示全部楼层
liminglm 发表于 2020-4-19 22:20
您好请问下那个阈值50摄氏度为什么是50,还有 analogWrite(5,Output/140*255);     后面那个Output/140*255 ...

我也看不懂这里,如果PWM精度是1024 ,255要改成1024? ,  那么140是output的最大值?
回复 支持 反对

使用道具 举报

发表于 2020-10-27 21:14:27 | 显示全部楼层
问一下,这个图形怎么得到的?
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-28 20:45 , Processed in 0.058276 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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