看了几遍这个B站UP主1PID系列教程,才初步理解PID的一些原理。但深入理解还需结合实际操作,就跟着UP主搭建一个电吹风的实验平台。

实验硬件

比较方便的办法是购买PLC+HMI电脑仿真,我为了省钱加学习的路线采用ESP32+C#上位机来搭建。ESP32的ADC分辨率为12位(官方:模数转换器 (ADC)Arduino ESP32 ADC功能介绍以及模拟量信号读取示例),分辨率比较高,但准确度一般(ESP32数据采集入门(5)压力传感器),ESP32的ADC采样电压最高3.3V,所以在常规选用热电阻变送器24V 4~20mA的模拟量系统中,需要串联一个166Ω的电阻,可以通过选用几个合适的电阻串联;准确度通过实测电压我这个ESP32的ADC采样电压偏小0.092V,因此需要在程序中加上这个偏差以修正。但在实际使用中采集的温度波动还是很大,ESP32的ADC只能用在准确度要求不高的场合。
我采用家里原有的3档飞科电吹风,对电路加以改造。拆解时需要特别注意飞科的电吹风是真难拆。使用时将电吹风开关打到冷风档,然后引出开关使主发热丝接通的1和2两个引脚。

电路图

电路图.png

MCGSpro数据监控及导出.gif
▲用昆仑通态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 合适的几个电阻串联

接线实物图.png
▲实际电路

电吹风改造.png
▲电吹风改造(引出红色箭头两根线到固态继电器)

调试及代码

C#上位机读取ESP32串口打印的参数,然后显示曲线,并写入SQLite数据库中,便于导出分析,具体数据分析处理可以参见UP主的视频教程。C#上位机编写部分参考了这位UP主的教程2
上位机软件:analog_temperature.zip ,导出的CSV文件数据位于软件data文件夹下。

PID调节还是采用迷你掌上平衡车里面的蓝牙调试工具:BtSerialDebugAndControl.zip

由于ADC采样波动较大,采用一阶滤波法进行滤波。

上位机演示.gif
▲上位机演示

代码如下

#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);
}

  1. 等角螺线的个人空间-哔哩哔哩:https://b23.tv/LHeIsAj 

  2. 【入门】最简单的上位机,三分钟,一步一步教你做串口接收软件:https://b23.tv/PhUU0Yf 

标签: ESP32, PID

添加新评论

选择表情