คำอธิบาย
ชุดเรียนรู้และชุดทดลอง Arduino PID Control Vertical Take-Off PID-V2 (2 ใบพัด)
ออกแบบมาเพื่อ เข้าใจจริง ทำได้จริง กับหลักการควบคุม PID (Proportional-Integral-Derivative) ผ่านการทดลองควบคุมมอเตอร์และแรงยกของใบพัดแบบแนวตั้ง
ผู้เรียนจะได้เรียนรู้ตั้งแต่พื้นฐานของ PID ไปจนถึงการ ปรับจูนค่า P-I-D ด้วยตนเอง เห็นผลลัพธ์ทันทีจากพฤติกรรมของระบบ ไม่ใช่แค่ทฤษฎีบนกระดาษ
เหมาะสำหรับการปูพื้นฐาน ระบบควบคุมอัตโนมัติ (Automatic Control) ที่ต่อยอดได้ทั้งหุ่นยนต์ โดรน ระบบอุตสาหกรรม และงานเมคคาทรอนิกส์
จุดเด่น
- ชุดทดลอง 2 ใบพัด เห็นสมดุลและความไม่เสถียรของระบบชัดเจน
- เรียนรู้ PID จากสถานการณ์จริง ไม่ใช่ตัวอย่างจำลอง
- ใช้ Arduino เข้าใจง่าย แก้โค้ด ทดลองซ้ำได้ทันที
- เหมาะทั้งห้องเรียน เวิร์กช็อป และผู้เริ่มต้นสาย Control Engineering
ไม่ใช่แค่ “ชุดทดลอง” แต่เป็น ก้าวแรกของการเข้าใจระบบควบคุมแบบมืออาชีพ ถ้าคุม PID ได้ ระบบควบคุมที่เหลือจะง่ายขึ้นทันที
ตัวอย่างการใช้ Arduino
- การควบคุมแบบ P Control
- การควบคุมแบบ PI Control
- การควบคุมแบบ PID Control
Download
- คู่มือชุด + ใบงานการทดลอง PID เวอร์ชั่น 2 รุ่น 2 ใบพัด https://docs.google.com/document/d/14CfWwO3UU7WUvbsn-z-fpM8w0dl1KMf2feZlcDq1WH0/edit?usp=sharing
Source Code
- พร้อมทดลอง Code PID V2 และ PID Libraly https://drive.google.com/drive/folders/1qzyScbnFE_NOqYWezxroHtxDYTzlHSnE?usp=sharing
ในชุดประกอบด้วย
- 1 เซต x เรียนรู้ชุดทดลอง ตัวควบคุม PID รุ่น 2 ใบพัด
- *ในชุดไม่รวมบอร์ด Arduino และ สาย USB

Schematics PCB


เพื่อให้แน่ใจว่าถูกต้อง และผลลัพธ์การควบคุมจะเป็นไปตามตัวอย่างที่นำเสนอ โปรดตรวจสอบการต่อสายไฟที่เชื่อมโยงระหว่างบอร์ดทดลองและบอร์ด Arduino ที่นำมาต่อด้วยความรอบคอบ
- จ่ายไฟบวก 5 โวลท์เข้าที่พอร์ต USB ของชุดทดลอง PID-V2 สามารถใช้ไฟจาก USB หรือที่ชาร์จโทรศัพท์หรือพาวเวอร์แบงค์ก็ได้
- เชื่อมต่อสายสัญญาณเข้ากับบอร์ด Arduino UNO ดังต่อไปนี้
- เชื่อมต่อขา ดิจิตอล 9 และ 10 ของ Arduino UNO กับ IN1+ IN1- ของชุดทดลอง PID V2 เพื่อควบคุมมอเตอร์ตัวที่ 1 หรือ ฝั่งซ้ายมือ
- เชื่อมต่อขาดิจิตอล 11 และ 12 ของ Arduino UNO กับ IN2+ IN2- ของชุดทดลอง PID-V2 เพื่อควบคุมมอเตอร์ตัวที่ 2 หรือฝั่งขวามือ
- เชื่อมต่อขา analog ของ ตัวต้านทานปรับค่าได้ซึ่งในชุดทดลองเขียนว่า FB ให้ต่อเข้ากับขา analog 4 (A4)ของ Arduino UNO
- เชื่อมต่อขา +Vin ของชุดทดลอง PID V2 เข้ากับ +5V ของ Arduino UNO
- เชื่อมต่อขา GND ของชุดทดลอง PID V2 เข้ากับ GND ของ Arduino UNO

มาเริ่มกันด้วยบล็อกไดอะแกรมการควบคุมชุดแกนใบพัดแบบมอเตอร์ 2 ตัวเป็นดังรูปที่ 1

รูปที่ 1 บล็อกไดอะแกรมการควบคุมชุดแกนใบพัด รุ่น 2 มอเตอร์
การทำงานจะเริ่มจาก ค่า setpoint หรือค่าที่เราต้องการ จะถูกกำหนดไว้ในโปรแกรม ในตัวอย่างโค้ดคือบรรทัดที่ 35 ในที่นี้ค่าคือ 500 ซึ่งที่ค่านี้ตัวควบคุม PID จะทำให้แกนใบพัดเคลื่อนที่มาอยู่ในตำแหน่งที่ขนานกับพื้น
void loop() { Setpoint = 500; //เซตให้อยู่ตรงกลาง หากไม่ใช้ให้ใส่ // ข้างหน้า
สัญญาณป้อนกลับของระบบจะได้มาจากตัวต้านทานปรับค่าได้ ซึ่งมีแกนใบพัดติดอยู่ แรงดันเอาต์พุตของตัวต้านทานปรับค่าได้จะอยู่ในช่วง 0 ถึง 5 โวลต์ จากนั้นจะถูกแปลงเป็นสัญญาณดิจิตอลขนาด 10 บิต ด้วยโมดูลแปลงค่าอนาลอกเป็นดิจิตอลภายในตัวไมโครคอนโทรลเลอร์ ที่อยู่บนบอร์ด Arduino สัญญาณดิจิตอลที่แปลงได้นี้จะมีค่า 0 ถึง 1023
ค่า setpoint จะถูกนำมาลบด้วยค่าสัญญาณป้อนกลับ ได้เป็นสัญญาณ Error ก่อนที่จะป้อนเข้าสู่ตัวควบคุม PID เอาต์พุตของ PID จะเป็นสัญญาณ PWM ส่งไปยัง Driver motor เพื่อขับให้มอเตอร์หมุนใบพัดสร้างแรงยก หรือแรงผลักลง ให้แกนใบพัดเข้าสู่ตำแหน่งเป้าหมายที่ต้องการ
การควบคุม PID ในปัจจุบันสามารถทำได้ง่ายขึ้นมาก เพียงแค่การเรียกใช้ไลเบอรี่ที่มีโปรแกรมเมอร์ใจดีสร้างมาให้ใช้ เรามาเรียนรู้การประยุกต์ใช้ ไลเบอรี่ตัวนี้กันสักเล็กน้อย เริ่มจากการใช้งานจำเป็นต้องมีการ เรียกฟังชั่นมาใช้ด้วยวิธีในบรรทัดที่1 คือ คำสั่ง include ตามด้วยชื่อไลเบอรี่ ดังรูปด้านล่าง
#include <PID_v1.h>// เรียกใช้งาน Arduino-PID-Library https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
ต่อมาเป็นการประกาศตัวแปรในการควบคุมไอซีขับมอเตอร์ ซึ่งต่อกับขาต่างๆ ดังนี้
const int AIA = 9; // (pwm) pin connected to pin IN2- const int AIB = 10; // (pwm) pin connected to pin IN2+ const int BIA = 11; // (pwm) pin connected to pin IN1- const int BIB = 12; // (pwm) pin connected to pin IN1+

การประกาศตัวแปร ที่ใช้ในโปรแกรม
การประกาศตัวแปร พร้อมกับกำหนดค่าที่ต้องการ ในที่นี้คือตัวแปรเกี่ยวกับค่า PID พารามิเตอร์ ที่ประกอบด้วย ค่า Kp Ki และ Kd
double Setpoint, Feedback, Output; int count_time; //จูนระบบด้วยการปรับค่าเกน Kp และ Ki double Kp=50, Ki=30, Kd=0.8; // กำหนดค่าเกนทั้งสามตัว // เปิดการใช้งาน Arduino-PID-Library PID myPID(&Feedback, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
ส่วนการเปิดใช้งานฟังชั่น PID สร้างฟังชั่นPID ขึ้นมาที่ชื่อ myPID โดยมีการรับสัญญาณป้อนกลับที่ตัวแปรชื่อ Feedback และ สัญญาณเอาต์พุตที่คำนวณเสร็จแล้วจะถูกใส่ไว้ในตัวแปรที่ชื่อ Output และค่าที่ต้องการจะต้องใส่ค่าในตัวแปรชื่อ Setpoint สุดท้ายตามด้วย พารามิเตอร์ Kp Ki และ Kd ตามลำดับ
void setup(){
pinMode(AIA, OUTPUT); // set pins to output
pinMode(AIB, OUTPUT);
pinMode(BIA, OUTPUT);
pinMode(BIB, OUTPUT);
Setpoint = 500;//อ่านค่าทั้งต้องการ
Feedback = analogRead(A4); //อ่านค่าจากตัวตรวจจับตำแหน่ง
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(1);
myPID.SetOutputLimits(-255, 255); // ถ้าใช้ไฟจ่าย USB คอมพิวเตอร์ ลิมิตที่ +/-128 เพื่อไม่ให้คอมพอร์ตรีเซต
// แต่ถ้าใช้พาวเวอร์แบงค์ ค่าสูงสุดคือ +/-255
Serial.begin(19200);
}
ในส่วนการ setup เป็นการกำหนดขาที่ใช้ควบคุมชิปขับมอเตอร์ให้เป็นเอาต์พุต ทำการเซตค่า Setpoint เริ่มต้น เป็น 500
pinMode(AIA, OUTPUT); // set pins to output pinMode(AIB, OUTPUT); pinMode(BIA, OUTPUT); pinMode(BIB, OUTPUT);
ในส่วนการอ่านค่าสัญญาณอนาลอกที่ขา A4 ค่าที่อ่านได้จะถูกเก็บไว้ในตัวแปรชื่อ Feedback
Setpoint = 500;//อ่านค่าทั้งต้องการ
การตั้งค่าการทำงานของโมดูล PID กำหนดโหมดการทำงานเป็น Automatic ถัดมาเป็นการกำหนดค่าเวลาแซมปลิ้ง ในที่นี้กำหนดเป็นทุกๆ 1 msec (ถ้าไม่กำหนดจะมีค่าเริ่มต้นที่ 100 มิลลิเซค)
myPID.SetMode(AUTOMATIC); myPID.SetSampleTime(1);
ในส่วนการกำหนดค่าสูงสุดต่ำสุดของเอาต์พุต ในที่นี้กำหนดให้เป็น +/-255 ที่กำหนดให้มีเครื่องหมายบวกลบเนื่องจากการควบคุมมอเตอร์ในชุดทดลองนี้ต้องมีการหมุนกลับทางด้วยเราจึงใช้เครื่องหมายเป็นตัวบอกทิศทางว่าจะให้หมุนทวนเข็มหรือหมุนตามเข็ม ส่วนการหมุนช้าหรือหมุนเร็วจะมีค่า 0 ถึง 255 โดย 0 หมายถึงหยุดหมุน และ 255 หมายถึง หมุนเต็มกำลังสูงสุด
myPID.SetOutputLimits(-255, 255); // ถ้าใช้ไฟจ่าย USB คอมพิวเตอร์ ลิมิตที่ +/-128 เพื่อไม่ให้คอมพอร์ตรีเซต
// แต่ถ้าใช้พาวเวอร์แบงค์ ค่าสูงสุดคือ +/-255
Serial.begin(19200);
ในการทำงานปกติ ในฟังชัน loop การควบคุมตำแหน่งของแกนใบพัดจะวนลูปเพื่อทำงานที่เป็นขั้นตอนซ้ำๆ กัน ดังนี้คือ อันดับแรกอ่านค่า Setpoint ต่อมา อ่าน Feedback ที่ขา A4 ต่อมาทำการคำนวณ PID และสุดท้ายส่งค่าเอาต์พุตไปยังไอซีขับมอเตอร์
Feedback = analogRead(A4); // อ่านค่าจากเซนเซอร์ตรวจจับตำแหน่ง
myPID.Compute(); // สั่งให้ตัวPID เริ่มคำนวณ
//ค่าoutput จะอยู่ในช่วง +255 -255
if(Output>0) //1 ถึง 255
{
analogWrite(AIA, Output);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, Output);
}
if(Output==0) // สัญญาณป้อนกลับเท่ากับค่าที่ต้องการ สั่งมอเตอร์หยุด
{
analogWrite(AIA, 0);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, 0);
}
if(Output<0) //-1 ถึง -255
{
Output = Output *-1;
analogWrite(AIA, 0);
analogWrite(AIB, Output);
analogWrite(BIA, Output);
analogWrite(BIB, 0);
}
เงื่อนไข ค่าเอาต์พุตที่ออกจาก PID จะอยู่ในช่วง 1 ถึง 255 (ค่าบวก) จะสั่งให้มอเตอร์ M1 หมุนตามเข็มเกิดแรงกดลง และมอเตอร์ M2 หมุนทวนเข็มเกิดแรงยก
if(Output>0) //1 ถึง 255
{
analogWrite(AIA, Output);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, Output);
}

เงื่อนไข ค่าเอาต์พุตจะเป็น 0 คือสั่งให้มอเตอร์หยุดหมุน
if(Output==0) // สัญญาณป้อนกลับเท่ากับค่าที่ต้องการ สั่งมอเตอร์หยุด
{
analogWrite(AIA, 0);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, 0);
}

เงื่อนไข ค่าเอาต์พุตที่ออกจาก PID จะอยู่ในช่วง -1 ถึง -255 (ค่าลบ) จะสั่งให้มอเตอร์ M2 หมุนตามเข็มเกิดแรงกดลง และมอเตอร์ M1 หมุนทวนเข็มเกิดแรงยก
if(Output>0) //1 ถึง 255
{
analogWrite(AIA, Output);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, Output);
}

การควบคุมแบบ P Control
ในการควบคุมแบบ P Control จะกำหนดให้ค่าพารามิเตอร์ของเทอม Ki และ Kd มีค่าเท่ากับ 0 ส่งผลให้ระบบควบคุมประกอบด้วยเฉพาะเทอม P (Proportional) เพียงอย่างเดียว โดยค่าพารามิเตอร์ที่ต้องปรับมีเพียงค่า Kp เท่านั้น
ตัวอย่างการปรับค่าพารามิเตอร์ของการควบคุมแบบ P Control แสดงดังรูปด้านล่าง หลังจากกำหนดค่า Kp ตามที่ต้องการแล้ว ให้ทำการอัปโหลดโปรแกรมไปยังบอร์ด Arduino จากนั้นสังเกตผลการตอบสนองของระบบ เพื่อศึกษาพฤติกรรมการควบคุมที่เกิดขึ้นจากการเปลี่ยนแปลงของค่า Kp

รูปที่ 10 ลักษณะสัญญาณป้อนกลับ (เส้นสีแดง) เมื่อควบคุมด้วย P control เพียงอย่างเดียว จะมีปัญหาออฟเซต

รูปที่ 11 หากเพิ่มค่า Kp มากขึ้น เพื่ออยากจะกำจัดออฟเซต ก็จะเกิดการแกว่งกลับไปมาระหว่าง setpoint
การทำงานของการควบคุมแบบ P Control
หรือที่เรียกว่า การควบคุมแบบสัดส่วน (Proportional Control) เป็นวิธีควบคุมที่กำหนดให้สัญญาณเอาต์พุตแปรผันโดยตรงตามความแตกต่างระหว่างค่าที่ต้องการ (Setpoint) กับสัญญาณป้อนกลับ (Feedback)
กล่าวคือ เมื่อสัญญาณป้อนกลับอยู่ห่างจากค่า Setpoint มาก ความคลาดเคลื่อน (Error) จะมีค่าสูง ส่งผลให้สัญญาณเอาต์พุตมีค่าสูงตามไปด้วย เพื่อขับให้ระบบเคลื่อนที่เข้าหาค่าเป้าหมายอย่างรวดเร็ว เมื่อระบบเคลื่อนเข้าใกล้ Setpoint มากขึ้น ค่า Error จะลดลง ทำให้สัญญาณเอาต์พุตค่อย ๆ ลดลงตามสัดส่วน และเข้าใกล้ศูนย์
อย่างไรก็ตาม ในทางปฏิบัติ เมื่อสัญญาณป้อนกลับเข้าใกล้ค่า Setpoint มาก สัญญาณเอาต์พุตจะมีค่าต่ำมากจนไม่เพียงพอที่จะเอาชนะแรงต้านต่าง ๆ ของระบบ เช่น แรงเสียดทานหรือแรงเฉื่อย ส่งผลให้กลไกของระบบ (ในกรณีนี้คือแกนใบพัด) ไม่สามารถเคลื่อนที่ไปถึงตำแหน่ง Setpoint ได้จริง ระบบจะหยุดอยู่ที่ตำแหน่งซึ่งใกล้เคียงค่าเป้าหมาย แต่ยังไม่ตรงกับค่า Setpoint อย่างสมบูรณ์
ลักษณะพฤติกรรมดังกล่าว เมื่อพิจารณาในช่วงใกล้ค่า Setpoint จะมีลักษณะดังแสดงใน รูปที่ 10
-
จุด A แสดงถึงการใช้แรงภายนอกผลักแกนใบพัดให้ออกจากตำแหน่งกึ่งกลางของระบบ ซึ่งกำหนดค่า Setpoint = 500 เนื่องจากค่าที่อ่านจาก ADC อยู่ในช่วง 0–1023 เมื่อแกนใบพัดถูกผลักออกจากตำแหน่งดังกล่าว สัญญาณป้อนกลับ (Feedback แสดงด้วยเส้นสีแดง) จะเริ่มเบี่ยงเบนออกจากค่า Setpoint (เส้นสีน้ำเงิน)
ทันทีที่เกิดความแตกต่างระหว่างสัญญาณ Feedback และค่า Setpoint ระบบควบคุมแบบ P จะตอบสนองโดยเพิ่มสัญญาณเอาต์พุตเพื่อขับมอเตอร์อย่างรวดเร็ว ซึ่งสามารถสังเกตได้ที่ จุด B โดยสัญญาณเอาต์พุต (เส้นสีเขียว) จะเพิ่มขึ้นทันทีเป็น 100% เพื่อสร้างแรงสูงสุดในการดันแกนใบพัดกลับเข้าสู่ตำแหน่งเป้าหมาย
ในระบบนี้ กำหนดให้ค่าเอาต์พุต 100% เท่ากับค่า 255 และค่าเอาต์พุต 0% เท่ากับค่า 0 โดยค่าดังกล่าวจะถูกส่งต่อไปยังไอซีขับมอเตอร์เพื่อควบคุมการทำงานของมอเตอร์โดยตรง
-
เมื่อเวลาผ่านไป หากพิจารณาที่ จุด C จะพบว่าเส้นแสดงค่า Setpoint (เส้นสีน้ำเงิน) และเส้นแสดงค่า Feedback (เส้นสีแดง) มีลักษณะขนานกัน แสดงให้เห็นว่าระบบได้เข้าสู่สภาวะคงตัว โดยมีสาเหตุมาจากแรงดันเอาต์พุตที่ใช้ขับมอเตอร์มีค่าน้อยเกินกว่าที่จะเอาชนะแรงต้านของระบบ ส่งผลให้แกนใบพัดไม่สามารถเคลื่อนที่เข้าสู่ตำแหน่ง Setpoint ได้
เมื่อสังเกตที่ จุด D จะเห็นว่าเส้นสัญญาณเอาต์พุต (เส้นสีเขียว) ยังคงมีค่าไม่เท่ากับศูนย์ กล่าวคือยังมีแรงดันจ่ายให้กับมอเตอร์อยู่ มอเตอร์จึงสามารถหมุนได้เล็กน้อย แต่แรงดังกล่าวไม่เพียงพอที่จะทำให้แกนใบพัดเคลื่อนที่เข้าสู่ค่า Setpoint ได้อย่างสมบูรณ์ ส่งผลให้แกนใบพัดค้างอยู่ที่ตำแหน่งดังกล่าวตลอดเวลา จนกว่าจะมีแรงภายนอกมากระทำ หรือมีการเปลี่ยนแปลงค่า Setpoint ใหม่
สภาวะที่เกิดช่องว่างระหว่างค่า Setpoint และสัญญาณ Feedback นี้ เรียกว่า ค่าออฟเซต (Offset) ซึ่งถือเป็นพฤติกรรมที่เกิดขึ้นตามธรรมชาติของการควบคุมแบบ P Control หากต้องการลดค่าออฟเซตดังกล่าวโดยยังใช้การควบคุมแบบ P Control วิธีที่สามารถทำได้คือการเพิ่มค่า Kp ให้สูงขึ้น เพื่อให้ระบบตอบสนองแรงขึ้นและทำให้ช่องว่างระหว่าง Setpoint และ Feedback แคบลง
อย่างไรก็ตาม เมื่อเพิ่มค่า Kp จนถึงระดับหนึ่ง ระบบจะไม่สามารถเคลื่อนเข้าสู่ Setpoint ได้อย่างราบรื่นอีกต่อไป แต่จะเกิดการแกว่งไปมารอบค่า Setpoint ดังแสดงใน รูปที่ 11 โดยสัญญาณแรงดันที่จ่ายให้มอเตอร์จะมีค่าสูงสุดทันที ส่งผลให้เกิดแรงในทิศทางตรงกันข้ามผลักแกนใบพัดให้เคลื่อนเข้าสู่ Setpoint แต่เนื่องจากมอเตอร์หมุนด้วยความแรงสูง ทำให้เกิดแรงเฉื่อย แม้จะมีการหยุดจ่ายแรงดันแล้ว แกนใบพัดก็ยังคงเคลื่อนที่เลยตำแหน่ง Setpoint ไป
เมื่อแกนใบพัดเคลื่อนที่เลยค่า Setpoint ตัวควบคุมแบบ P จะสั่งให้มอเตอร์หมุนกลับในทิศทางตรงกันข้ามด้วยความแรงสูงสุดอีกครั้ง กระบวนการนี้จะเกิดซ้ำไปมาอย่างต่อเนื่อง ส่งผลให้แกนใบพัดเคลื่อนที่ขึ้นและลง หรือแกว่งกลับไปกลับมารอบค่า Setpoint ซึ่งเป็นพฤติกรรมที่ไม่พึงประสงค์
วิธีแก้ไขในกรณีนี้คือการลดค่า Kp ลงจนกระทั่งการแกว่งของแกนใบพัดหยุดลง อย่างไรก็ตาม แม้ระบบจะมีความเสถียรมากขึ้นแล้ว ก็ยังคงต้องเผชิญกับปัญหาค่าออฟเซตเช่นเดิม ซึ่งเป็นข้อจำกัดพื้นฐานของการควบคุมแบบ P Control
การควบคุมแบบ PI Control
เพื่อแก้ไขปัญหาค่าออฟเซตที่เกิดขึ้นในการควบคุมแบบ P Control จึงมีการนำการควบคุมแบบ อินทิกรัล (Integral Control) เข้ามาเสริม ทำให้เกิดการควบคุมแบบ PI Control โดยมีจุดประสงค์หลักเพื่อกำจัดค่าออฟเซตที่เกิดขึ้นเมื่อระบบเข้าสู่สภาวะคงตัว (Steady State)
หลักการทำงานของส่วนอินทิกรัลคือการนำค่าความคลาดเคลื่อน (Error) ที่เกิดขึ้นในแต่ละช่วงเวลามาสะสมต่อเนื่อง เมื่อเวลาผ่านไป หากระบบยังไม่สามารถเข้าสู่ค่า Setpoint ได้ ค่า Error ที่ถูกสะสมจะเพิ่มขึ้นเรื่อย ๆ ส่งผลให้สัญญาณเอาต์พุตจากส่วนอินทิกรัลเพิ่มสูงขึ้นตามลำดับ
สัญญาณเอาต์พุตที่เพิ่มขึ้นนี้จะถูกนำไปใช้ขับมอเตอร์ให้หมุนด้วยแรงที่มากขึ้นอย่างค่อยเป็นค่อยไป ทำให้แกนใบพัดสามารถเอาชนะแรงต้านของระบบ และเคลื่อนที่เข้าสู่ตำแหน่ง Setpoint ได้อย่างนิ่มนวล โดยไม่เกิดการหยุดค้างก่อนถึงค่าเป้าหมายเหมือนในกรณีของการควบคุมแบบ P Control เพียงอย่างเดียว
ลักษณะการตอบสนองของระบบเมื่อใช้การควบคุมแบบ PI Control แสดงดัง รูปที่ 12

รูปที่ 12 กราฟการควบคุมด้วย PI control
การทำงานของ PI Control
จาก รูปที่ 12 ที่แสดงการทำงานของระบบควบคุมแบบ PI Control ซึ่งประกอบด้วยเทอม P (Proportional) และ I (Integral) ทำงานร่วมกัน สามารถอธิบายพฤติกรรมของระบบได้ดังนี้
ที่ จุด A แสดงการใช้แรงภายนอกผลักแกนใบพัด (เส้นสีแดง) ให้ออกจากตำแหน่ง Setpoint (เส้นสีน้ำเงิน) เมื่อระบบใช้การควบคุมแบบ PI Control จะพบว่าแกนใบพัดสามารถเคลื่อนที่กลับเข้าสู่ตำแหน่ง Setpoint ได้อย่างสมบูรณ์ ซึ่งแตกต่างจากการควบคุมแบบ P Control เพียงอย่างเดียวที่มักจะเกิดค่าออฟเซตและไม่สามารถเข้าถึง Setpoint ได้จริง
ระหว่างการเคลื่อนที่จาก จุด A ไปยังจุด B จะสังเกตเห็นการแกว่งขึ้นลงของแกนใบพัดเล็กน้อย ซึ่งเป็นผลจากการทำงานร่วมกันของเทอม P ที่ตอบสนองต่อ Error อย่างรวดเร็ว และเทอม I ที่ทำหน้าที่สะสม Error เพื่อเพิ่มแรงขับให้ระบบ อย่างไรก็ตาม การแกว่งดังกล่าวจะลดลงเมื่อระบบเข้าใกล้ตำแหน่งเป้าหมาย
เมื่อพิจารณาที่ จุด C จะเห็นว่า แม้แกนใบพัดจะเข้าสู่ตำแหน่ง Setpoint แล้ว สัญญาณเอาต์พุต (เส้นสีเขียว) ยังคงมีค่าไม่เป็นศูนย์ โดยเอาต์พุตดังกล่าวถูกส่งไปยังไอซีขับมอเตอร์เพื่อสร้างแรงเพียงพอในการรักษาให้แกนใบพัดคงอยู่ที่ตำแหน่ง Setpoint และเอาชนะแรงรบกวนหรือแรงต้านของระบบ นี่คือบทบาทสำคัญของเทอมอินทิกรัลในการกำจัดค่าออฟเซตอย่างถาวร
การปรับค่า Ki (การจูนระบบ)
จากประสบการณ์ในการใช้งานจริง การปรับค่า Ki มักทำโดยการเพิ่มค่าทีละน้อยและสังเกตผลตอบสนองของระบบ วิธีการปรับในลักษณะนี้เรียกว่า การจูนแบบลองผิดลองถูก (Trial and Error) ซึ่งจะดำเนินการต่อไปจนกว่าระบบจะแสดงพฤติกรรมที่ผู้ควบคุมพึงพอใจ
การตัดสินใจว่าจะหยุดการจูนเมื่อใด จะขึ้นอยู่กับข้อกำหนดของระบบเป็นหลัก ได้แก่
- เวลาที่ระบบใช้ในการเข้าสู่ตำแหน่ง Setpoint มากหรือน้อยเพียงใด
- ระบบสามารถยอมรับการเกิดโอเวอร์ชูต (Overshoot) ได้หรือไม่
- ค่าความคลาดเคลื่อนที่ยอมรับได้เมื่อระบบเข้าสู่สภาวะคงตัว
ปัจจัยทั้งหมดนี้จะเป็นตัวกำหนดค่าพารามิเตอร์ของ PI Control และเป็นเกณฑ์ในการพิจารณาว่าการจูนระบบได้ผลลัพธ์ที่เหมาะสมแล้วหรือยัง
การควบคุมแบบ PID Control
จากการพิจารณาการควบคุมแบบ PI Control จะเห็นว่า ในช่วงเวลาที่ระบบถูกรบกวน เช่น การใช้แรงภายนอกผลักแกนใบพัดให้ออกจากตำแหน่งเดิม แม้ว่าระบบจะสามารถเคลื่อนกลับเข้าสู่ตำแหน่ง Setpoint ได้อย่างสมบูรณ์ แต่ระหว่างการเคลื่อนที่ดังกล่าวยังคงเกิดการแกว่งขึ้นลงรอบค่า Setpoint หรือเกิดโอเวอร์ชูตอยู่บ้าง ก่อนที่ระบบจะกลับเข้าสู่สภาวะคงตัว
ในกรณีที่ระบบมีข้อกำหนดไม่ยอมให้เกิดโอเวอร์ชูต หรือจำเป็นต้องควบคุมการเคลื่อนที่ให้มีความนิ่มนวลและเสถียรมากขึ้น จึงต้องเพิ่มเทอม D (Derivative Control) เข้ามาในการควบคุม ทำให้เกิดการควบคุมแบบ PID Control
บทบาทของเทอม D คือการตอบสนองต่ออัตราการเปลี่ยนแปลงของความคลาดเคลื่อน (Rate of Change of Error) ซึ่งเปรียบเสมือนแรงหน่วงที่ช่วยชะลอการเคลื่อนที่ของระบบ เมื่อระบบมีแนวโน้มจะเคลื่อนที่เร็วเกินไปหรือกำลังจะเกิดการเคลื่อนที่เลยค่า Setpoint เทอม D จะสร้างสัญญาณเอาต์พุตในทิศทางตรงข้ามเพื่อลดความเร็วและแรงเฉื่อยของระบบ ส่งผลให้การแกว่งและโอเวอร์ชูตลดลงอย่างชัดเจน
ตัวอย่างผลการทดลองเมื่อเพิ่มเทอม D เข้ามาในระบบควบคุมแบบ PID Control แสดงดัง รูปที่ 13 ซึ่งจะเห็นได้ว่าการตอบสนองของระบบมีความราบรื่นมากขึ้น การแกว่งรอบค่า Setpoint ลดลง และระบบสามารถกลับเข้าสู่ตำแหน่งเป้าหมายได้อย่างรวดเร็วและเสถียรยิ่งขึ้น

รูปที่ 13 ผลตอบสนองการควบคุมแกนใบพัดด้วย PID Control
เทอม D ที่ถูกเพิ่มเข้ามาในระบบควบคุม จะทำหน้าที่ต้านทานการเปลี่ยนแปลงของระบบที่เกิดขึ้นอย่างฉับพลัน โดย D ย่อมาจาก Differential (Derivative) ซึ่งเป็นการพิจารณาอัตราการเปลี่ยนแปลงของความคลาดเคลื่อน เทอมนี้ทำหน้าที่เสมือนแรงหน่วง ช่วยลดความเร็วและแรงเฉื่อยของระบบก่อนที่การเคลื่อนที่จะเกิดการเลยค่า Setpoint
เมื่อพิจารณาที่ ตำแหน่ง A ซึ่งเป็นจุดที่ใช้แรงภายนอกผลักแกนใบพัดให้ออกจากตำแหน่งเดิม หลังจากนั้นตัวควบคุมแบบ PID Control จะควบคุมให้แกนใบพัดค่อย ๆ เคลื่อนที่กลับเข้าสู่ตำแหน่ง Setpoint อย่างนิ่มนวล โดยไม่เกิดโอเวอร์ชูต ซึ่งสามารถสังเกตได้ชัดเจนที่บริเวณ จุด B เมื่อเปรียบเทียบกับการตอบสนองของระบบในกรณี PI Control (รูปที่ 12)
อย่างไรก็ตาม ผู้ทดลองสามารถปรับเปลี่ยนค่า Kp, Ki และ Kd ได้ตามความเหมาะสม เพื่อศึกษาพฤติกรรมการตอบสนองของระบบที่เปลี่ยนแปลงไปเมื่อค่าพารามิเตอร์ของ PID เปลี่ยนแปลง การปรับค่าดังกล่าวจะช่วยให้เข้าใจลักษณะการทำงานของระบบควบคุมได้ดียิ่งขึ้น
ควรตระหนักว่าค่าพารามิเตอร์ของ PID Control ที่จูนได้เหมาะสมแล้ว จะเหมาะกับระบบที่ทำการจูนเท่านั้น หากนำไปประยุกต์ใช้กับระบบอื่น เช่น ระบบควบคุมอุณหภูมิ ความเย็น ความดันอากาศ หรือความเร็วรอบของมอเตอร์ จำเป็นต้องทำการจูนค่า PID พารามิเตอร์ ใหม่ทุกครั้ง แม้ว่าหลักการและแนวคิดในการจูนค่าจะยังคงเหมือนเดิมก็ตาม
#include <PID_v1.h>// เรียกใช้งาน Arduino-PID-Library https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
const int AIA = 9; // (pwm) pin connected to pin IN2-
const int AIB = 10; // (pwm) pin connected to pin IN2+
const int BIA = 11; // (pwm) pin connected to pin IN1-
const int BIB = 12; // (pwm) pin connected to pin IN1+
double Setpoint, Feedback, Output;
int count_time;
//จูนระบบด้วยการปรับค่าเกน Kp และ Ki
double Kp=50, Ki=30, Kd=0.8; // กำหนดค่าเกนทั้งสามตัว
// เปิดการใช้งาน Arduino-PID-Library
PID myPID(&Feedback, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup(){
pinMode(AIA, OUTPUT); // set pins to output
pinMode(AIB, OUTPUT);
pinMode(BIA, OUTPUT);
pinMode(BIB, OUTPUT);
Setpoint = 500;//อ่านค่าทั้งต้องการ
Feedback = analogRead(A4); //อ่านค่าจากตัวตรวจจับตำแหน่ง
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(1);
myPID.SetOutputLimits(-255, 255); // ถ้าใช้ไฟจ่าย USB คอมพิวเตอร์ ลิมิตที่ +/-128 เพื่อไม่ให้คอมพอร์ตรีเซต
// แต่ถ้าใช้พาวเวอร์แบงค์ ค่าสูงสุดคือ +/-255
Serial.begin(19200);
}
void loop()
{
Setpoint = 500; //เซตให้อยู่ตรงกลาง หากไม่ใช้ให้ใส่ // ข้างหน้า
//count_time++; //หากต้องการดูผลตอบสนองจะต้องมีการเปลี่ยน setpoint
//if(count_time<=400)Setpoint = 450; // กลับไปมา ในที่นี้คือค่า 450 กับ 650
//if(count_time>400)Setpoint = 650; // แกนใบพัดก็จะเปลี่ยนตำแหน่งไปมา
//if(count_time>800)count_time = 0; // ให้เอาเครื่องหมาย // หน้าบรรทัดที่ 37 ถึง 40 ออก
Feedback = analogRead(A4); // อ่านค่าจากเซนเซอร์ตรวจจับตำแหน่ง
myPID.Compute(); // สั่งให้ตัวPID เริ่มคำนวณ
//ค่าoutput จะอยู่ในช่วง +255 -255
if(Output>0) //1 ถึง 255
{
analogWrite(AIA, Output);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, Output);
}
if(Output==0) // สัญญาณป้อนกลับเท่ากับค่าที่ต้องการ สั่งมอเตอร์หยุด
{
analogWrite(AIA, 0);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, 0);
}
if(Output<0) //-1 ถึง -255
{
Output = Output *-1;
analogWrite(AIA, 0);
analogWrite(AIB, Output);
analogWrite(BIA, Output);
analogWrite(BIB, 0);
}
// แสดงผลกราฟ
Serial.print("\n"); // New line
Serial.print (Setpoint); // Setpoint มีค่าอยู่ในช่วง 0 ถึง 1023
Serial.print("\t");
Serial.print (Feedback); // Feedback มีค่าอยู่ในช่วง 0 ถึง 1023
Serial.print("\t");
Serial.print((Output/255)*100); // Output มีค่าอยู่ในช่วง 0 ถึง 255
Serial.print("\t"); // แต่เวลาแสดงผลทำเป็น% อยู่ในช่วง 0-100%
Serial.print( 1000);
Serial.print("\t");
Serial.print( 100);
Serial.print("\t");
Serial.print( 0);
}
#include <PID_v1.h>// เรียกใช้งาน Arduino-PID-Library https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
const int AIA = 9; // (pwm) pin connected to pin IN1+
const int AIB = 10; // (pwm) pin connected to pin IN1-
const int BIA = 11; // (pwm) pin connected to pin IN2+
const int BIB = 12; // (pwm) pin connected to pin IN2-
#define NUMPWM 2
double Setpoint, Feedback, Output;
int count_time;
//จูนระบบด้วยการปรับค่าเกน Kp และ Ki
double Kp=12, Ki=4, Kd=0; // กำหนดค่าเกนทั้งสามตัว
PID myPID(&Feedback, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);// เปิดการใช้งาน Arduino-PID-Library
void setup(){
pinMode(AIA, OUTPUT); // set pins to output
pinMode(AIB, OUTPUT);
pinMode(BIA, OUTPUT);
pinMode(BIB, OUTPUT);
Setpoint = 500;//อ่านค่าทั้งต้องการ
Feedback = analogRead(A4); //อ่านค่าจากตัวตรวจจับตำแหน่ง
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(1);
myPID.SetOutputLimits(-255, 255); // ถ้าใช้ไฟจ่าย USB คอมพิวเตอร์ ลิมิตที่ +/-128 เพื่อไม่ให้คอมพอร์ตรีเซต
// แต่ถ้าใช้พาวเวอร์แบงค์ ค่าสูงสุดคือ +/-255
Serial.begin(19200);
}
void loop(){
count_time++;
if(count_time<=400)Setpoint = 450;
if(count_time>400)Setpoint = 650;
if(count_time>800)count_time = 0;
Feedback = analogRead(A4); // อ่านค่าจากเซนเซอร์ตรวจจับตำแหน่ง
myPID.Compute(); // สั่งให้ตัวPID เริ่มคำนวณ
if(Output>0){
analogWrite(AIA, Output);
analogWrite(AIB, 0);
analogWrite(BIA, 0);
analogWrite(BIB, Output);
}
if(Output<0){
Output = Output *-1;
analogWrite(AIA, 0);
analogWrite(AIB, Output);
analogWrite(BIA, Output);
analogWrite(BIB, 0);
}
// แสดงผลกราฟ
Serial.print("\n"); // New line
Serial.print((Setpoint/1023)*100); // Setpoint
Serial.print("\t");
Serial.print((Feedback/1023)*100); // Feedback
Serial.print("\t");
Serial.print((Output/255)*10); // Output
Serial.print("\t");
Serial.print( 100);
Serial.print("\t");
Serial.print( 10);
Serial.print("\t");
Serial.print( 0);
}






รีวิว
ยังไม่มีบทวิจารณ์