PID应用实操-电吹风
看了几遍这个B站UP主的PID系列教程,才初步理解PID的一些原理。但深入理解还需结合实际操作,就跟着UP主搭建一个电吹风的实验平台。
实验硬件
比较方便的办法是购买PLC+HMI电脑仿真,我为了省钱加学习的路线采用ESP32+C#上位机来搭建。ESP32的ADC分辨率为12位(Arduino ESP32 ADC功能介绍以及模拟量信号读取示例),分辨率比较高,但准确度一般(ESP32数据采集入门(5)压力传感器),ESP32的ADC采样电压最高3.3V,所以在常规选用热电阻变送器24V 4~20mA的模拟量系统中,需要串联一个166Ω的电阻,可以通过选用几个合适的电阻串联;准确度通过实测电压我这个ESP32的ADC采样电压偏小0.092V,因此需要在程序中加上这个偏差以修正。但在实际使用中采集的温度波动还是很大,ESP32的ADC只能用在准确度要求不高的场合。
我采用家里原有的3档飞科电吹风,对电路加以改造。拆解时需要特别注意飞科的电吹风是真难拆。使用时将电吹风开关打到冷风档,然后引出开关使主发热丝接通的1和2两个引脚。
▲电路图
▲用昆仑通态HMI+西门子200smart ST40搭建的DEMO
清单如下
名称 | 参数 | 数量 | 备注 |
---|---|---|---|
ESP32模块+电气材料 | 利用Arduino做控制 | 1 | 见电路图 |
电吹风 | 飞科3档电吹风 | 1 | 各品牌电吹风电路稍有差别,需要拆解核实电路 |
24VDC电源 | 24V 5A | 1 | 原有明纬开关电源 |
固态继电器 | 直流控交流,10A | 1 | 含散热底座 |
PT100 | A级精度 | 1 | 三线制 |
PT100温度变送器 | 24VDC,-50~100℃,4~20mA | 1 | 输出两线制 |
电阻 | 166Ω | 1 | 合适的几个电阻串联 |
硬件部分
▲实际电路
▲电吹风改造(引出红色箭头两根线到固态继电器)
调试及代码
C#上位机读取ESP32串口打印的参数,然后显示曲线,并写入SQLite数据库中,便于导出分析,具体数据分析处理可以参见UP主的视频教程。C#上位机编写部分参考了这位UP主的教程。
上位机软件:analog_temperature.zip ,导出的CSV文件数据位于软件data文件夹下。
PID调节还是采用迷你掌上平衡车里面的蓝牙调试工具:BtSerialDebugAndControl.zip
由于ADC采样波动较大,采用一阶滤波法进行滤波。
▲上位机演示
▲上位机导出数据
代码如下
#include <Arduino.h>
#include "BluetoothSerial.h"
const int potPin = 36;
const int pwmPin = 33;
float kp = 1.6, ki = 0.05, kd = 0.2;
float bias, integrate, bias_old=0;
int set_T=50,T_PWM;
char DATA;
float ADC_VALUE = 0;
float voltage_value = 0;
float Temperature = 0;
float TS=0.5; //时间系数
float A1;
float A2;
int i;
BluetoothSerial SerialBT; //实例化esp32的蓝牙串口对象
void TempraturePID()
{
bias=set_T - Temperature; //这一次的温度偏差
if (ki!=0)
{
integrate +=bias; //偏差的积分
}
else
{
integrate=0;
}
T_PWM=kp*bias+ki*integrate+kd*bias_old;
bias_old=bias;
if(T_PWM>256)
{
T_PWM=256;
}
}
void serial_out()
{
i=i+1;
if(i==5)
{
Serial.println(Temperature);
i=0;
}
}
void serial_debug()
{
if (SerialBT.available() > 0)
{
DATA = SerialBT.read();
delay(5);
switch (DATA)
{
case '0':
kp -= 0.1; //比例kp项-
break;
case '1':
kp += 0.1; //比例kp项+
break;
case '2':
ki -= 0.1; //积分项ki-
break;
case '3':
ki += 0.1; //积分项ki+
break;
case '4':
kd -= 0.1; //微分项kd-
break;
case '5':
kd += 0.1; // 微分项kd+
break;
case '6':
set_T -= 1; //设定温度值-
break;
case '7':
set_T += 1; //设定温度值+
break;
}
/*调试时PID极性限制*/
if (kp < 0)kp = 0;
if (ki < 0)ki = 0;
if (kd < 0)kd = 0;
/*蓝牙串口打印输出显示*/
SerialBT.print("set_T:");
SerialBT.print(set_T);
SerialBT.print(" kp:");
SerialBT.print(kp);
SerialBT.print(" ki:");
SerialBT.print(ki);
SerialBT.print(" kd:");
SerialBT.println(kd);
SerialBT.println("--------------------");
}
}
void setup()
{
Serial.begin(9600);
SerialBT.begin("ESP32_PID"); // Bluetooth device name
//pinMode(pwmPin, OUTPUT);
ledcSetup(0, 1000, 8); // pwm频道, 频率, 精度8 位分辨率
ledcAttachPin(pwmPin, 0); // 将GPIO与LEDC通道绑定
delay(100);//循环前延时,确保各种初始和准备完成
}
void loop()
{
TempraturePID();
serial_debug();
ledcWrite(0, T_PWM);// 将通道 0 的占空比调整为 T_PWM
ADC_VALUE = analogRead(potPin); //读取引脚电压值
voltage_value = (ADC_VALUE * 3.3 ) / (4095);
A1 = (-50.0) + ((ADC_VALUE+114)-819)*0.045787; //150/(4095-(4095-819))=0.045787,114为esp32测得电压比稳压源显示电压平均低0.092V
Temperature = A1*TS+(1-TS)*A2; //一阶滤波法
// Serial.print("bias");
// Serial.print(bias);
// Serial.print(" T_PWM=");
// Serial.print(T_PWM);
// Serial.print(" T=");
// Serial.println(Temperature);
serial_out();
A2 = Temperature;
delay(200);
}