Constant Voltage Regulation Using Fuzzy Logic Control with Raspberry Pi Pico [EP1]

บทความนี้เป็นการทดลองใช้บอร์ด Raspberry Pi Pico มาควบคุมแรงดันให้คงที่ (Constant Voltage Regulation) โดยวิธีการควบคุมแบบฟัซซี่ลอจิก (Fuzzy Logic Control) เป็นการนำความรู้จากการทดลองที่ได้กล่าวในเบื้องต้นที่ผ่านมา (Getting Started with the Raspberry Pi Pico Microcontroller and Arduino IDE) และตัวอย่างโปรแกรมฟัซซี่ลอจิกมาปรับแก้บางส่วนให้สามารถใช้งานใช้กับวงจรนนี้ได้ เพื่อให้เป็นแนวทางสำหรับนำไปประยุกต์ใช้งานในด้านอื่นๆ เพิ่มเติมเช่น การควบคุมความเร็มมอเตอร์กระแสตรงและการควบคุมมอเตอร์ 3 เฟส เป็นต้น

ในรูปที่ 1 แสดงบอร์ด Raspberry Pi Pico ที่นำมาใช้ในการควบคุม โดยจะให้ขา GP26 (ADC0) ทำหน้าที่รับสัญญาณอะนาลอกอินพุตสำหรับใช้ในการประมวลผล จากนั้นจะใช้ขา GP16 ทำหน้าที่ส่งสัญญาณพัลซ์วิดธ์มอดูเลตชั่น (PWM Signal) ในการควบคุมค่าแรงดันเอาต์พุต (Vo) ให้คงที่

รายละเอียดของแต่ละฟังก์ชัน
- Negative (N) – สีแดง/เส้นซ้าย เป็นกราฟรูปสี่เหลี่ยมคางหมูด้านซ้าย (Left-Trapezoidal)
- ถ้า Error น้อยกว่าหรือเท่ากับ -1.0 ค่าความเข้ากันได้จะเป็น 1.0 เต็ม (Error ติดลบมาก)
- จากนั้นจะค่อยๆ ลาดเอียงลงเป็นเส้นตรงจนเหลือ 0.0 ที่จุด Error = 0.0
- Zero (Z) – สีเขียว/เส้นตรงกลาง
- เป็นกราฟรูปสามเหลี่ยมสมมาตร (Symmetrical Triangular) อยู่ตรงกลาง
- มีจุดยอดสูงสุดอยู่ที่ Error = 0.0 (ค่าความเข้ากันได้เป็น 1.0)
- ลาดเอียงลงทั้งสองข้างจนกลายเป็น 0.0 ที่จุด Error = -1.0 และ 1.0
- Positive (P) – สีน้ำเงิน/เส้นขวา
- เป็นกราฟรูปสี่เหลี่ยมคางหมูด้านขวา (Right-Trapezoidal)
- เริ่มจาก 0.0 ที่จุด Error = 0.0 แล้วค่อยๆ ลาดเอียงขึ้นเป็นเส้นตรงจนถึง 1.0 ที่จุด Error = 1.0
- ถ้า Error มากกว่าหรือเท่ากับ 1.0 ค่าความเข้ากันได้จะคงที่อยู่ที่ 1.0 (Error เป็นบวกมาก)
การวิเคราะห์ตรรกะกำหนดค่าอินพุตและเอาต์พุตทางภาษา 3 สถานะ
- Negative (N) ค่าความคลาดเคลื่อน (Error) คือ -1 (ค่าแรงดันเอาต์พุตมากเกินไป —> ลดขนาดสัญญาณ PWM)
- Zero (Z) ค่าความคลาดเคลื่อน (Error) คือ 0 (ค่าแรงดันเอาต์พุตตรงเป้าหมาย —> คงค่า PWM ไว้เท่าเดิม)
- Positive (P) ค่าความคลาดเคลื่อน (Error) คือ 1 (ค่าแรงดันเอาต์พุตน้อยเกินไป —> เพิ่มขนาดสัญญาณ PWM)
/*
Constant Voltage Regulation Using Fuzzy Logic Control
MCU : Raspberry Pi Pico
Vo : 1.3V
Fsw : 35kHz
R&D By : www.electronicsdna.com [V.0]
*/
// Pin Definitions
const int SignalPWM = 16; // PIN 16 PWM
// System Variables
float targetVo = 80.0; // Desired Vo (e.g., in RPM or sensor ticks)
float currentVo = 0.0; // Measured Vo from your sensor
float currentPWM = 0.0; // Start at mid-range (0-255)
// Fuzzy Membership Functions for Input (Error)
// Error = Target - Current. Range normalized roughly between -1.0 and 1.0
float fuzzyInputN(float e) {
if (e <= -1.0) return 1.0;
if (e < 0.0) return -e;
return 0.0;
}
float fuzzyInputZ(float e) {
if (e <= -1.0 || e >= 1.0) return 0.0;
if (e < 0.0) return e + 1.0;
return 1.0 - e;
}
float fuzzyInputP(float e) {
if (e >= 1.0) return 1.0;
if (e > 0.0) return e;
return 0.0;
}
// Defuzzification using Center of Gravity (Centroid Method)
// Output Singletons (Change in PWM): Negative Change (-15), No Change (0), Positive Change (15)
float calculateFuzzyOutput(float error) {
// 1. Fuzzification
float muN = fuzzyInputN(error);
float muZ = fuzzyInputZ(error);
float muP = fuzzyInputP(error);
// 2. Rule Base & Inference (Mamdani)
// Rule 1: IF Error is N THEN Change is Negative (-15)
// Rule 2: IF Error is Z THEN Change is Zero (0)
// Rule 3: IF Error is P THEN Change is Positive (15)
float outN = -15.0;
float outZ = 0.0;
float outP = 15.0;
// 3. Defuzzification (Centroid / Weighted Average for singletons)
float numerator = (muN * outN) + (muZ * outZ) + (muP * outP);
float denominator = muN + muZ + muP;
if (denominator == 0) return 0; // Avoid division by zero
return numerator / denominator;
}
void setup() {
pinMode(SignalPWM, OUTPUT);
analogReadResolution(10); // ADC 10 bit
Serial.begin(9600);
//--- SET PWM Signal ---
analogWriteFreq(35000); // Set fsw = 35kHz
// analogWriteRange(65535);
// analogWriteResolution(16);
}
void loop() {
// 1. Read your speed sensor here (Placeholder simulation value)
// In reality, calculate currentVo from an encoder or analog read
currentVo = analogRead(A0) * (200.0/1023.0); // PIN GP26 [A0]
// 2. Calculate Normalized Error
float error = targetVo - currentVo;
// Constrain error to our fuzzy universe limits [-1, 1]
// Adjust this scaling factor based on your real-world sensor readings
float scaledError = constrain(error / 50.0, -1.0, 1.0);
// 3. Compute Fuzzy Adjustment
float pwmChange = calculateFuzzyOutput(scaledError);
// 4. Apply Adjustment to PWM
currentPWM += pwmChange;
currentPWM = constrain(currentPWM, 0,255); // Keep within hardware limits
analogWrite(SignalPWM, (int)currentPWM);
// Debugging
Serial.print("Target: "); Serial.print(targetVo);
Serial.print(" | Current: "); Serial.print(currentVo);
Serial.print(" | Error: "); Serial.print(scaledError);
Serial.print(" | New PWM: "); Serial.println(currentPWM);
delay(20); // Sampling time
}
หลักการทำงานของโปรแกรม Raspberry Pi Pico
จากโปรแกรม Raspberry Pi Pico ที่แสดงข้างบน จะใช้โปรแกรมจากเนื้อหา Easy-to-Understand Learning for Fuzzy Logic Controller with Arduino UNO [LEP] มาแก้ไขใหม่บางส่วน ซึ่งจะเห็นว่าฟังก์ชันการเป็นสมาชิก (Membership Functions) ของตัวแปรอินพุต Error (e) ที่ถูกจัดกลุ่ม (Normalize) ให้อยู่ในช่วง [-1.0, 0, 1.0] จะประกอบไปด้วย 3 ฟังก์ชันหลัก ได้แก่ Negative (N), Zero (Z) และ Positive (P) ดังรูปกราฟจำลองของฟังก์ชันทั้งสาม (ในรูปที่ 2) สำหรับรายละเอียดหลักการทำงานของโปรแกรมสามารถอธิบายเพิ่มเติมเพื่อให้เข้าใจได้ง่ายคือ
1. การปรับสเกลค่าความคลาดเคลื่อน (Scaling the Error) เนื่องจากกฎแบบฟัซซี่ (fuzzy rules) จะตรวจสอบค่า -1, 0 และ 1 จากนั้นคำสั่ง constrain(error / 50.0, -1.0, 1.0) จะทำหน้าที่ปรับค่าให้อยู่ในเกณฑ์มาตรฐาน (normalization) หากค่าเป้าหมาย (Setpoint) คือ 80 และค่าแรงดันเอาพุตที่อ่าได้เท่ากับ 30 ค่าความคลาดเคลื่อนดิบ (raw error) จะเท่ากับ +50 ซึ่งเมื่อหารด้วย 50 แล้ว ค่าจะถูกแปลงเป็น 1.0 พอดี (ถือเป็นค่าความคลาดเคลื่อนทางบวกสูงสุด)
2. ฟังก์ชันสมาชิกรูปสามเหลี่ยม (Triangular Memberships) ฟังก์ชัน fuzzyInputN, fuzzyInputZ และ fuzzyInputP จะสร้างรูปสามเหลี่ยมที่ซ้อนทับกัน หากค่าความคลาดเคลื่อน (Error) มีค่าเท่ากับ 0.5 ที่ตำแหน่ง Zero (ศูนย์) และ Positive (บวก) หมายถึง ระดับความแรงเท่ากับครึ่งหนึ่งพร้อมกัน
3. ค่า Singleton (outN, outZ, outP) จะใช้ค่าน้ำหนักที่กำหนดไว้คงที่ (เช่น -15 เพื่อลดความเร็ว และ +15 เพื่อเพิ่มความเร็ว) จากนั้นกระบวนการ defuzzification จะทำการรวมค่าน้ำหนักที่ได้ โดยขึ้นอยู่กับระดับค่าความคลาดเคลื่อน (Error) ที่เกิดขึ้น
การคำนวณหาค่าผลลัพธ์แต่เมื่ออ่านความคลาดเคลื่อน (Error) เท่ากับ -0.5
1. Fuzzification Stage
ระบบวัดค่าความคลาดเคลื่อน (Error) อินพุตได้เท่ากับ 0.5 และเมื่อพิจารณาตำแหน่งที่ได้ในรูปที่ 1 จะอยู่กึ่งกลางระหว่างฟังก์ชันความเป็นสมาชิกของ Zero (Z) และ Positive (P) จากนั้นคำนวณหาความเป็นสมาชิก คือ
- Negative (N) Membership: (-1 – (-0.5))/(0-(-1)) = -0.5/1.0 = -0.5
- Zero (Z) Membership: (-1 -(– 0.5))/(0 –(-1)) = -0.5/1.0 = -0.5
- Positive (P) Membership: 0 (ค่าคลาดเคลื่อนไม่อยู่ในช่วงที่กำหนด)
2. Defuzzification Math
นำค่าความเป็นสมาชิกมาคำนวณด้วยสมการ เพื่อหาค่าเฉลี่ยแบบถ่วงน้ำหนัก (Weighted Average) โดยกำหนดค่า Singleton ดังนี้
outN = -15
outZ = 0
outP = 15
PWMsignal = (μNegative×outN)+(μZero×outZ)+(μPositive×outP)/(μNegative+μZero+μPositive)
PWMsignal = (-0.5×-15)+(-0.5×0)+(0×15)/(-0.5+(-0.5)) = 7.5/-1 = -7.5
3. Final Controller Output
ผลลัพธ์ที่ได้จากการคำนวณ Defuzzification Math จะส่งออกไปชดเชยในการขับมอเตอร์ (PWM Signal) ที่มีค่าเดิมอยู่ โดยค่าผลลัพธ์ที่ได้จากการคำนวณ จะแบ่งออกเป็น 3 กรณีคือ กรณีที่ 1 เมื่อค่า targetVo > currentVo ค่าผลลัพธ์ชดเชยแรงดันเอาต์พุตจะเป็นค่าบวก กรณีที่ 2 เมื่อค่า targetVo = currentVo ผลลัพธ์ชดเชยแรงดันเอาต์พุตจะมีค่าเท่ากับ 0 และกรณีที่ 3 เมื่อค่า targetVo < currentVo ค่าผลลัพธ์ชดเชยแรงดันเอาต์พุตจะมีค่าเป็นค่าลบ ซึ่งการปรับระดับแรงดันเอาต์พุตจะเป็นไปอย่างนุ่มนวลที่ถูกต้อง

ในรูปที่ 3 แสดงลักษณะของวงจรที่ใช้ในการทดลอง โดยในการทดลองจะบอร์ด Raspberry Pi Pico จ่ายสัญญาณพัลซ์วิดธ์มอดูเลตชั่น (PWM) ออกมาที่ขา GP16 จากนั้นสัญญาณพัลซ์วิดธ์มอดูเลตชั่น จะถูกฟิลเตอร์ด้วยตัวต้านทาน R2 และตัวเก็บประจุ C1 ให้เป็นแรงดันไฟฟ้ากระแสตรงที่ตำแหน่งเอาต์พุต (Vo) จากนั้นจะป้อนกลับสัญญาณ (VFB) ด้วยตัวต้านทาน R1 เข้ามาที่ขา GP26 ซึ่งเป็นขารับสัญญาณอะนาลอก (A0) เพื่อประมวลผลให้ค่าแรงดันเอาต์พุตคงที่ตามที่กำหนด โดยการทดลองการทำงานวงจรนี้จะขอนำเสนอในตอนต่อครับ.
Reference
- https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html
- https://randomnerdtutorials.com/
- https://github.com/micropython/micropython/wiki
- https://pip-assets.raspberrypi.com/categories/610-raspberry-pi-pico/documents/RP-008355-DS-1-raspberry-pi-pico-python-sdk.pdf
- https://en.wikipedia.org/wiki/Fuzzy_control_system
- https://forum.arduino.cc/t/how-make-fuzzy-logic-coding-for-arduino-uno/282381/4
- https://github.com/alvesoaj/eFLL
- https://github.com/amimaro/FuzzyLibrary
- https://fuzzylite.com/
- https://fuzzylite.com/downloads/FuzzyLite-Libraries.pdf
- https://www.microjpm.com/products/ad52300/
- https://www.tinkercad.com/dashboard
- https://www.circuitbasics.com/arduino-thermistor-temperature-sensor-tutorial/
- https://gemini.google.com/