iTCLab : Internet-Based TCLab - PID, AI, and IoT-based Temperature Control Lab Kit. Suitable for researchers, Lecturers, Students, Teachers, and Electronics-Informatics Vocational School Students. This kit can be used for Learning: IoT, System Dynamics, Control, AI, Arduino and Python Programming, etc.

Riset IoT PID Control

Administrator | 03 May 2022

Riset IoT PID Control


Riset iTCLab : Pengendalian Suhu Via IoT Menggunakan PID-iTCLab 



Arsitektur Sistem:

Arsitektur Sistem Pengendalian Suhu Via IoT Menggunakan PID-iTCLab seperti diperlihatkan pada gambar berikut ini. 




Metode Pengendalian:

Metode Pengendalian Suhu Via IoT Menggunakan PID-iTCLab seperti diperlihatkan pada gambar berikut ini. 




Perangkat yang diperlukan:

  • Aplikasi : IoT MQTT Panel di HP Android
  • Cloud IoT sebagai Broker MQTT : hivemq.com
  • Device : Menggunakan Kit iTCLab




Berikut ini contoh program yang harus diupload ke Kit iTCLab:

/*************************************************
 * Program : Pengendalian Suhu dengan PID via IoT
 *           Menggunakan Kit iTCLab
 * Oleh    : Tim io-t.net
 * Surabaya, 25 April 2022
 *************************************************/

#include <WiFi.h>
#include <PubSubClient.h>
#include <Arduino.h> 

const char* ssid = "wifi"; // Enter your WiFi name
const char* password = "Password"; // Enter WiFi password

#define mqttServer "broker.hivemq.com"
#define mqttPort 1883

WiFiServer server(80);
WiFiClient espClient;
PubSubClient client(espClient);

String Topic;
String Payload;

// constants
const int baud = 115200;       // serial baud rate

// pin numbers corresponding to signals on the iTCLab Shield
const int pinT1   = 34;         // T1
const int pinT2   = 35;         // T2
const int pinQ1   = 32;         // Q1
const int pinQ2   = 33;         // Q2
const int pinLED  = 26;         // LED

// setting PWM properties
const int freq = 5000; //5000
const int ledChannel = 0;
const int Q1Channel = 1;
const int Q2Channel = 2;
const int resolutionLedChannel = 8; //Resolution 8, 10, 12, 15
const int resolutionQ1Channel = 8; //Resolution 8, 10, 12, 15
const int resolutionQ2Channel = 8; //Resolution 8, 10, 12, 15

float cel, cel1, degC, degC1;
float P, I, D;
float KP, KI, KD, op0, ophi, oplo, error, dpv;

float sp = 30,  //set point
pv = 0,        //current temperature
pv_last = 0,   //prior temperature
ierr = 0,      //integral error
dt = 0,        //time between measurements
op = 0;        //PID controller output

int autoSet = 0;  // autoSet = 1 otomatis sesuai Default
//float Kc = 0;
//float tauI = 0;
//float tauD = 0;

// Default = autoset = 1 otomatis sesuai Default
 float Kc = 10.0; // K / %Heater
 float tauI = 50.0; // sec
 float tauD = 1.0;  // sec

unsigned long ts = 0, new_ts = 0; //timestamp
const float batas_suhu_atas = 58;

// global variables
float Q1 = 0;                 // value written to Q1 pin
float Q2 = 0;                 // value written to Q2 pin
int iwrite_value = 25;        // integer value for writing
int iwrite_led = 255;         // integer value for writing
int iwrite_min = 0;           // integer value for writing

void setup() {
  // put your setup code here, to run once:

  ts = millis();
  Serial.begin(baud); 
  while (!Serial) {
    ; // wait for serial port to connect.
  }

  // configure pinQ1 PWM functionalitites
  ledcSetup(Q1Channel, freq, resolutionQ1Channel);
  
  // attach the channel to the pinQ1 to be controlled
  ledcAttachPin(pinQ1, Q1Channel); 

  // configure pinQ2 PWM functionalitites
  ledcSetup(Q2Channel, freq, resolutionQ2Channel);
  
  // attach the channel to the pinQ2 to be controlled
  ledcAttachPin(pinQ2, Q2Channel);   

  // configure pinLED PWM functionalitites
  ledcSetup(ledChannel, freq, resolutionLedChannel);
  
  // attach the channel to the pinLED to be controlled
  ledcAttachPin(pinLED, ledChannel); 

  ledcWrite(Q1Channel,0);
  ledcWrite(Q2Channel,0); 
  ledcWrite(ledChannel,0); 
 
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid); 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
 
  // Connect to Server IoT (CloudMQTT)
  client.setServer(mqttServer, mqttPort);
  client.setCallback(receivedCallback);
 
  while (!client.connected()) {
    Serial.println("Connecting to MQTT Broker ...");
 
//    if (client.connect("ESP32Client", mqttUser, mqttPassword )) {
     if (client.connect("iTCLab Suhu dengan Kendali PID...")) { 

      Serial.println("connected");
      Serial.print("Message received: ");
   
    } else {
      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(1000);
    }
    client.subscribe("autoSet");
    client.subscribe("SetPoint");    
    client.subscribe("Nilai_Kc");
    client.subscribe("Nilai_tauI");
    client.subscribe("Nilai_tauD");
  }
}

void Q1on(){
    ledcWrite(Q1Channel,iwrite_value);
    //Q1 = iwrite_value/255*100;
    //Serial.println(Q1);
}

void Q1off(){
    ledcWrite(Q1Channel,iwrite_min);
    //Q1 = iwrite_min/255*100;
    //Serial.println(Q1);
}

void Q2on(){
    ledcWrite(Q2Channel,iwrite_value);
    //Q2 = iwrite_value/255*100;
    //Serial.println(Q2);
}

void Q2off(){
    ledcWrite(Q2Channel,iwrite_min);
    //Q2 = iwrite_min/255*100;
    //Serial.println(Q2);
}

void ledon(){
    ledcWrite(ledChannel,iwrite_led);
}

void ledoff(){
    ledcWrite(ledChannel,iwrite_min);
}

void cektemp(){
  degC = analogRead(pinT1) * 0.322265625 ;    // use for 3.3v AREF
  cel = degC/10;
  degC1 = analogRead(pinT2) * 0.322265625 ;    // use for 3.3v AREF
  cel1 = degC1/10;

  //Serial.print("Temperature T1: ");
  //Serial.print(cel);   // print the temperature T1 in Celsius
  //Serial.print("°C");
  //Serial.print("  ~  "); // separator between Celsius and Fahrenheit
  //Serial.print("Temperature T2: ");
  //Serial.print(cel1);   // print the temperature T2 in Celsius
  //Serial.println("°C");
}


// PID Controller
// inputs -----------------------------------
// sp = setpoint
// pv = current temperature
// pv_last = prior temperature
// ierr = integral error
// dt = time increment between measurements
// outputs ----------------------------------
// op = output of the PID controller
// P = proportional contribution
// I = integral contribution
// D = derivative contribution

float pid(float sp, float Kc, float tauI, float tauD, float pv, float pv_last, float& ierr, float dt) {
  //float Kc = 10.0; // K / %Heater
  //float tauI = 50.0; // sec
  //float tauD = 1.0;  // sec
  // PID coefficients
  float KP = Kc;
  float KI = Kc / tauI;
  float KD = Kc*tauD; 
  // upper and lower bounds on heater level
  float ophi = 100;
  float oplo = 0;
  // calculate the error
  float error = sp - pv;
  // calculate the integral error
  ierr = ierr + KI * error * dt;  
  // calculate the measurement derivative
  float dpv = (pv - pv_last) / dt;
  // calculate the PID output
  float P = KP * error; //proportional contribution
  float I = ierr; //integral contribution
  float D = -KD * dpv; //derivative contribution
  float op = P + I + D;
  // implement anti-reset windup
  if ((op < oplo) || (op > ophi)) {
    I = I - KI * error * dt;
    // clip output
    op = max(oplo, min(ophi, op));
  }
  ierr = I; 
  Serial.println("sp="+String(sp) + " pv=" + String(pv) + " dt=" + String(dt) + " op=" + String(op) + " P=" + String(P) + " I=" + String(I) + " D=" + String(D));
  return op;
}

void receivedCallback(char* topic, byte* payload, unsigned int length) {
  Topic = topic;
  char autoS[60];
  int i;
  for (i=0;i 1000) {   

  char suhu1[4];
  char suhu2[4];
  char Nilai_op[4];
  char Tampil_SP[4];
  char Tampil_Kc[4];
  char Tampil_tauI[4];
  char Tampil_tauD[4];
  client.loop();
  
  // put your main code here, to run repeatedly:
  cektemp();
  if (cel > batas_suhu_atas){
    Q1off();
    ledon();
  }
  else {
    Q1on();
    ledoff();
  }
  if (cel1 > batas_suhu_atas){
    Q2off();
    ledon();
  }
  else {
    Q2on();
    ledoff();
  }
   
  if(Topic=="autoSet"){
    autoSet=Payload.toInt();
  }
   if(Topic=="Nilai_Kc"){
    Kc=Payload.toFloat();
  }
   if(Topic=="Nilai_tauI"){
    tauI=Payload.toFloat();
  }
   if(Topic=="Nilai_tauD"){
    tauD=Payload.toFloat()/6;
  }
   if(Topic=="SetPoint"){
    sp=Payload.toFloat();
  }
  Serial.println("<-------------------------->");
  Serial.print("autoSet: ");
  Serial.println(autoSet);
  Serial.print("SetPoint: ");
  Serial.println(sp);
  Serial.print("Nilai_Kc: ");
  Serial.println(Kc);
  Serial.print("Nilai_tauI: ");
  Serial.println(tauI);
  Serial.print("Nilai_tauD: ");
  Serial.println(tauD);
  Serial.println("<-------------------------->");

  dtostrf(cel, 1, 0, suhu1);
  client.publish("Suhu1",suhu1);

  dtostrf(cel1, 1, 0, suhu2);
  client.publish("Suhu2",suhu2);

  dtostrf(sp, 1, 0, Tampil_SP);
  client.publish("Tampil_SP",Tampil_SP);

  dtostrf(Kc, 1, 0, Tampil_Kc);
  client.publish("Tampil_Kc",Tampil_Kc);

  dtostrf(tauI, 1, 0, Tampil_tauI);
  client.publish("Tampil_tauI",Tampil_tauI);

  dtostrf(tauD, 1, 0, Tampil_tauD);
  client.publish("Tampil_tauD",Tampil_tauD);  

  if(autoSet==1){
     sp = 35;
     Kc = 10.0; // K / %Heater
     tauI = 50.0; // sec
     tauD = 1.0;  // sec
     
  }else if(autoSet == 0){
    // bisa diubah2, sesuai yg muncul terakhir, dan setelah diubah2
  }
     pv = cel;   // Temperature T1
     dt = (new_ts - ts) / 1000.0;
     ts = new_ts;
  
     op = pid(sp,Kc,tauI,tauD,pv,pv_last,ierr,dt); // PID Process
     
     ledcWrite(Q1Channel,op);
     pv_last = pv;
  
     dtostrf(op, 1, 0, Nilai_op);
     client.publish("Nilai_op",Nilai_op);
  }
}

Download Program Monitoring dan Kontrol Suhu dengan PID via IoT dalam Arduino (silahkan klik-kanan Save link as)di sini : 09-IoT_PID_Control.ino.



Tampilan melalui Serial Monitor di laptop, seperti terlihat pada gambar berikut:




Seting pada HP Android, menggunakan IoT MQTT Panel sebagai berikut:












Jika berhasil konek ke Broker MQTT, maka hasilnya adalah sebagai berikut: