Simple Temperature Control by using Fuzzy Logic Control Based on Arduino [EP4]

โครงงานการควบคุมอุณหภูมิแบบฟัซซี่ลอจิก (Fuzzy Logic Control : FLC) โดยใช้บอร์ด Arduino UNO ในตอนที่ 4 นี้จะเพิ่มการรับสัญญาณอินพุตเป็น 2 ส่วน และส่งสัญญาณเอาต์พุต 1 ช่อง ทั้งนี้เพื่อศึกษาการใช้คำสั่งในกรณีที่สัญญาณอินพุตมากกว่า 1 ส่วนขึ้นไป และยังคงใช้ไลบารี่ฟัซซี่ลอจิก <Fuzzy.h> ในการเขียนโปรแกรมเช่นเดิม ซึ่งในส่วนของสัญญาณอินพุตทั้ง 2 ช่องจะยังคงจำลองค่าอุณหภูมิในช่วง 0-40°C เพื่อให้เข้าใจได้ง่ายและสัญญาณเอาต์พุตจะเป็นพัลซ์วิดธ์มอดูเลตชั่นในการควบคุมโหลดต่างๆ

รูปที่ 1 ลักษณะการต่ออุปกรณ์สำหรับทดลอง
Temperature Control by using Fuzzy Logic Control Based on Arduino
รูปที่ 2 วงจรที่ใช้ในการทดลองการควบคุมแบบฟัซซี่ลอจิก

ในรูปที่ 1 และรูปที่ 2 แสดงลักษณะการต่ออุปกรณ์สำหรับทดลองและวงจรที่ใช้ในการทดลองการควบคุมแบบฟัซซี่ลอจิก โดยในการทดลองครั้งนี้จะใช้ตัวต้านทานปรับค่า (Variable Resistor : VR) จำนวน 2 ตัวเพื่อทดสอบการทำงานแทนค่าเซนเซอร์อุณหภูมิที่อ่านได้ในส่วนของอินพุตฟัซซี่ลอจิก ในส่วนเอาต์พุตสามารถส่งสัญญาณพัลซ์วิดธ์มอดูเลตชั่นที่ขา D13 (แอลอีดีบนบอร์ด Arduino) หรือต่อที่ขา D9 ก็ได้เช่นกัน ทั้งนี้เพื่อสังเกตผลที่ได้จากการทำงาน

// Arduino_advanced_sample_V3 

#include <Fuzzy.h>

Fuzzy *fuzzy = new Fuzzy();  // Fuzzy 

// FuzzyInput1
FuzzySet *error_NB = new FuzzySet(0, 5, 10, 15);
FuzzySet *error_Z = new FuzzySet(10, 20, 20, 25);
FuzzySet *error_PS = new FuzzySet(20, 30, 40, 40); 

// FuzzyInput2
FuzzySet *deltaError_NS = new FuzzySet(0, 5, 10, 15);
FuzzySet *deltaError_Z = new FuzzySet(10, 20, 20, 25);
FuzzySet *deltaError_PS = new FuzzySet(20, 30, 40, 40);

// FuzzyOutput
FuzzySet *slowOutput = new FuzzySet(1, 10, 20, 30);
FuzzySet *normalOutput = new FuzzySet(40, 50, 50, 60);
FuzzySet *quickOutput = new FuzzySet(70, 80, 100, 100);

void setup()
{  
  Serial.begin(9600); // Set the Serial output
  pinMode(13,OUTPUT);
  
  // Every setup must occur in the function setup()
  // FuzzyInput1
  FuzzyInput *error = new FuzzyInput(1);
  error->addFuzzySet(error_NB);
  error->addFuzzySet(error_Z);
  error->addFuzzySet(error_PS);
  fuzzy->addFuzzyInput(error);

  // FuzzyInput2
  FuzzyInput *deltaError = new FuzzyInput(2);  
  deltaError->addFuzzySet(deltaError_NS);
  deltaError->addFuzzySet(deltaError_Z);
  deltaError->addFuzzySet(deltaError_PS);
  fuzzy->addFuzzyInput(deltaError);

  // FuzzyOutput
  FuzzyOutput *speedOutput = new FuzzyOutput(1);
  speedOutput->addFuzzySet(slowOutput);
  speedOutput->addFuzzySet(normalOutput);
  speedOutput->addFuzzySet(quickOutput);
  fuzzy->addFuzzyOutput(speedOutput);
    
//---- Building FuzzyRule (1)-----------------------------
  FuzzyRuleAntecedent *iferror_NBAnddeltaError_NS = new FuzzyRuleAntecedent();
  iferror_NBAnddeltaError_NS->joinWithAND(error_NB, deltaError_NS);

  FuzzyRuleConsequent *thenSpeedSlow = new FuzzyRuleConsequent();
  thenSpeedSlow->addOutput(slowOutput);

  FuzzyRule *fuzzyRule1 = new FuzzyRule(1,iferror_NBAnddeltaError_NS, thenSpeedSlow);
  fuzzy->addFuzzyRule(fuzzyRule1);  
   
 //---- Building FuzzyRule (2)-----------------------------
  FuzzyRuleAntecedent *iferror_ZAnddeltaError_Z = new FuzzyRuleAntecedent();
  iferror_ZAnddeltaError_Z->joinWithAND(error_Z, deltaError_Z);

  FuzzyRuleConsequent *thenSpeednormal = new FuzzyRuleConsequent();
  thenSpeednormal->addOutput(normalOutput);

  FuzzyRule *fuzzyRule2 = new FuzzyRule(2,iferror_ZAnddeltaError_Z, thenSpeednormal);
  fuzzy->addFuzzyRule(fuzzyRule2);

//---- Building FuzzyRule (3)-----------------------------
  FuzzyRuleAntecedent *iferror_PSAnddeltaError_PS = new FuzzyRuleAntecedent();
  iferror_PSAnddeltaError_PS->joinWithAND(error_PS, deltaError_PS);

  FuzzyRuleConsequent *thenSpeedquick = new FuzzyRuleConsequent();
  thenSpeedquick->addOutput(quickOutput);

  FuzzyRule *fuzzyRule3 = new FuzzyRule(3,iferror_PSAnddeltaError_PS, thenSpeedquick);
  fuzzy->addFuzzyRule(fuzzyRule3);  

  // Add more rules to cover all combinations for better control
  // ...
}

void loop()
{
  int Readtemp1 = analogRead(A1); // Read temperature pin A1 
  int input1 = map(Readtemp1, 0, 1023, 0, 40);  // Map temperature range (0-40°C)
  int Readtemp2 = analogRead(A2); // Read temperature pin A2 
  int input2 = map(Readtemp2, 0, 1023, 0, 40);  // Map temperature range (0-40°C)
  
  Serial.println(" ");
  Serial.print(" input1 = ");  // Error
  Serial.print(input1);
  Serial.print(", input2 = "); // DeltaError
  Serial.println(input2);
 
  fuzzy->setInput(1, input1);
  fuzzy->setInput(2, input2);

  fuzzy->fuzzify();

  Serial.print(" Error: error_NB-> ");
  Serial.print(error_NB->getPertinence());
  Serial.print(", error_Z-> ");
  Serial.print(error_Z->getPertinence());
  Serial.print(", error_PS-> ");
  Serial.println(error_PS->getPertinence());
 
  Serial.print(" DeltaError: deltaError_NS-> ");
  Serial.print(deltaError_NS->getPertinence());
  Serial.print(", deltaError_Z-> ");
  Serial.print(deltaError_Z->getPertinence());
  Serial.print(", deltaError_PS-> ");
  Serial.println(deltaError_PS->getPertinence());

  int output1 = fuzzy->defuzzify(1); 
  
  Serial.print(" Result: ");
  Serial.println(output1); 
   
//  analogWrite(13,(255*output1)/100);
  
  delay(1000);
}

โปรแกรม Arduino สำหรับประมวลผลแบบฟัซซี่ลอจิกจะแบ่งออกเป็น 3 ส่วนคือ ในส่วนแรกที่คำสั่ง #include <Fuzzy.h> จะทำหน้าประกาศใช้งานฟังก์ชั่นไลบารี่ฟัซซี่ลอจิก ถัดลงมาจะเป็นการกำหนดค่า FuzzyINPUT, FuzzyOUTPUT ส่วนที่สอง void setup() ที่หน้าที่กำหนดอัตราการสื่อสารของพอร์ตอนุกรมเท่ากับ 9600, FuzzyRule และการกำหนดความกว้างของสัญญาณพัลซ์วิดธ์มอดูเลตชั่นที่ขา D13 ด้วยคำสั่ง analogWrite(13,output); ส่วนที่สาม void loop() จะทำหน้าที่รับค่าสัญญาณอินพุตด้วยคำสั่ง int Readtemp1 = analogRead(A1); และ int Readtemp2 = analogRead(A2); จากนั้นจะใช้คำสั่ง int input = map(Readtemp, 0, 1023, 0, 40); เพื่อเปลี่ยนค่าที่อ่านได้ 0-1023 ให้อยู่ในช่วง 0-40 (หมายถึงช่วงอุณหภูมิ 0-40°C) และแสดงผลด้วยคำสั่ง Serial.print(input); จากนั้นจะเป็นคำสั่งให้ประมวลผล fuzzy->setInput(x, input); คำสั่ง fuzzy->fuzzify(); แสดงผลด้วยคำสั่ง Serial.print(Error:); , Serial.print(deltaError:); และคำสั่ง float output = fuzzy->defuzzify(1); ซึ่งจะได้ค่าเอาต์พุตออกมาที่ตัวแปร output เพื่อกำหนดสัญญาณพัลซ์วิดธ์มอดูเลตชั่นที่ขา D13

ในการทดลองนี้จะกำหนด FuzzyRule ไว้เพียง 3 ส่วนคือ

สำหรับการกำหนดกฏของฟัซซี่ลอจิกที่ตำแหน่ง Building FuzzyRule1, 2 และ 3 ในตัวอย่างนี้ ผู้ออกแบบระบบควบคุมจะต้องทดลองปรับให้ระบบการทำงานเป็นไปตามที่ต้องการ โดยสามารถปรับตัวเลขภายในหรือเพิ่มจำนวน FuzzyINPUT, FuzzyOUTPUT และกฏของฟัซซี่ลอจิก FuzzyRule ให้เหมาะสมกับระบบที่ต้องการควบคุมนั้นๆ ได้

Temperature Control by using Fuzzy Logic Control Based on Arduino
รูปที่ 3 เมื่อกำหนดอุณหภูมิ input1 = 12°C, input2 = 10°C และ Result คือ PWM = 15%
Temperature Control by using Fuzzy Logic Control Based on Arduino
รูปที่ 4 เมื่อกำหนดอุณหภูมิ input1 = 15°C, input2 = 20°C และ Result คือ PWM = 50%
Temperature Control by using Fuzzy Logic Control Based on Arduino
รูปที่ 5 เมื่อกำหนดอุณหภูมิ input1 = 30°C, input2 = 25°C และ Result คือ PWM = 86%

สำหรับการควบคุมอุณหภูมิแบบฟัซซี่ลอจิก (Fuzzy Logic Control : FLC) โดยใช้บอร์ด Arduino UNO ในตอนที่ 4 นี้ จะเป็นการทดลองเพิ่มจำนวนอินพุตเป็น 2 ส่วน และส่งสัญญาณเอาต์พุต 1 ช่อง ทั้งนี้เพื่อศึกษาการใช้คำสั่งสำหรับ 2 อินพุต รวมทั้งการทดลองปรับตัวเลขภายใน FuzzyINPUT, FuzzyOUTPUT และกฏของฟัซซี่ลอจิก FuzzyRule โดยจะสังเกตลักษณะการทำงานที่เกิดขึ้น ทั้งนี้เพื่อให้เข้าใจการควบคุมอุณหภูมิแบบฟัซซี่ลอจิกได้อีกแบบหนึ่งและสามารถนำไปประยุกต์ใช้งานได้ง่ายขึ้น

Reference

  1. https://en.wikipedia.org/wiki/Fuzzy_control_system
  2. https://forum.arduino.cc/t/how-make-fuzzy-logic-coding-for-arduino-uno/282381/4
  3. https://github.com/alvesoaj/eFLL
  4. https://github.com/amimaro/FuzzyLibrary
  5. https://www.microjpm.com/products/ad52300/
  6. https://c1555f5ec9.clvaw-cdnwnd.com/34662fcf1f1e607c561442431023ac8e/200010020-73ac173ac3/AD52300%20uJPM%20Datasheet.PDF
  7. https://www.tinkercad.com/dashboard
  8. https://www.circuitbasics.com/arduino-thermistor-temperature-sensor-tutorial/
  9. https://gemini.google.com/
  10. https://copilot.microsoft.com