คำอธิบาย
ชุดทดลองสำหรับเรียนรู้ระบบควบคุมแบบ Open-loop, P, PI และ PID ผ่านการควบคุมตำแหน่งแกนใบพัด ผู้เรียนสามารถปรับค่า Kp, Ki และ Kd พร้อมดูกราฟผลตอบสนองของระบบ เพื่อทำความเข้าใจ Setpoint, Feedback, Error, Input และ Output ได้จากการทดลองจริง
คุณสมบัติเด่น
- เรียนรู้หลักการควบคุมตำแหน่งแบบ Closed-loop
- ทดลองเปรียบเทียบ Open-loop, P, PI และ PID
- ปรับค่า Kp, Ki และ Kd เพื่อสังเกตพฤติกรรมของระบบ
- ศึกษาความสัมพันธ์ระหว่าง Setpoint, Feedback, Error และ Output
- แสดงกราฟผลตอบสนองของตำแหน่งแกนใบพัดผ่าน Arduino
- ศึกษา Rise Time, Overshoot, Settling Time และ Steady-state Error
- มีตัวอย่างโปรแกรม Arduino ทั้งแบบเขียนสมการ PID และใช้ PID Library
- เหมาะสำหรับห้องปฏิบัติการ ระบบควบคุม อิเล็กทรอนิกส์ เมคคาทรอนิกส์ และระบบอัตโนมัติ
สเปกสินค้า (Specifications)
- รุ่น: PID-V2
- ประเภทชุดทดลอง: Vertical Take-Off PID Training Kit
- จำนวนใบพัด: 2 ใบพัด
- ตัวแปรควบคุม: ตำแหน่งเชิงมุมของแกนใบพัด
- Setpoint: ค่าตำแหน่งเป้าหมายที่ผู้ทดลองกำหนด
- Feedback: สัญญาณตำแหน่งจริงจากแกนใบพัด
- Error: ค่าความแตกต่างระหว่าง Setpoint และ Feedback
- Output: สัญญาณ PWM สำหรับควบคุมความเร็วรอบมอเตอร์และแรงยกของใบพัด
- ระบบควบคุมที่รองรับ: Open-loop, P, PI และ PID
- พารามิเตอร์ที่ปรับได้: Kp, Ki และ Kd
- โปรแกรมควบคุมตัวอย่าง: Arduino IDE
- การแสดงผล: กราฟ Setpoint, Feedback และ Output
- บอร์ดควบคุมที่ใช้ในตัวอย่าง: Arduino Uno
ผลของการปรับค่า Kp, Ki และ Kd
- Kp หรือ Proportional Gain ช่วยให้ระบบตอบสนองเร็วขึ้นและลด Rise Time แต่ถ้าปรับสูงเกินไป ระบบอาจแกว่งหรือเกิด Overshoot
- Ki หรือ Integral Gain ช่วยลด Steady-state Error และทำให้ Feedback เข้าใกล้ Setpoint มากขึ้น แต่ถ้าปรับสูงเกินไป อาจทำให้ Overshoot เพิ่มและใช้เวลานานกว่าจะนิ่ง
- Kd หรือ Derivative Gain ช่วยต้านการเปลี่ยนแปลงอย่างรวดเร็ว ลด Overshoot และช่วยให้ระบบนิ่งเร็วขึ้น แต่ค่าที่สูงเกินไปอาจไวต่อสัญญาณรบกวน
ตัวอย่างใบงาน Arduino
- การควบคุมแบบ Open-loop
- การควบคุมแบบ P
- การควบคุมแบบ PI
- การควบคุมแบบ PID
- การควบคุมแบบ PID โดยใช้ PID Library
การนำไปใช้งาน
- ใช้ประกอบการเรียนวิชาระบบควบคุมอัตโนมัติ
- ใช้ศึกษาการออกแบบและปรับแต่งตัวควบคุม PID
- ใช้ทดลองระบบควบคุมตำแหน่งแบบ Closed-loop
- ใช้เปรียบเทียบผลตอบสนองระหว่าง P, PI และ PID
- ใช้ศึกษาวิธีปรับค่า PID แบบทดลองและวิธี Ziegler–Nichols
- เหมาะสำหรับโรงเรียน วิทยาลัย มหาวิทยาลัย และศูนย์ฝึกอบรมด้านเมคคาทรอนิกส์
Dimension

ในชุดประกอบด้วย
- 1 ชุด ชุดทดลองตัวควบคุมแบบ 2 ใบพัด
Schematics PCB


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

เริ่มต้นจากการทำความเข้าใจ บล็อกไดอะแกรมของระบบควบคุมชุดแกนใบพัดแบบมอเตอร์ 2 ตัว ซึ่งแสดงโครงสร้างการทำงานและความสัมพันธ์ระหว่างส่วนต่าง ๆ ของระบบ ดังแสดงใน รูปที่ 1

รูปที่ 1 บล็อกไดอะแกรมการควบคุมชุดแกนใบพัด รุ่น 2 มอเตอร์
- การทำงานของระบบเริ่มต้นจากการกำหนดค่า Setpoint ซึ่งเป็นค่าตำแหน่งเป้าหมายที่ต้องการให้ระบบควบคุมแกนใบพัดเคลื่อนที่ไปถึง โดยค่า Setpoint จะถูกกำหนดไว้ภายในโปรแกรม
- ในตัวอย่างโค้ดนี้ ค่า Setpoint ถูกกำหนดไว้ที่ บรรทัดที่ 35 โดยตั้งค่าไว้เท่ากับ 500
- เมื่อกำหนดค่า Setpoint = 500 ตัวควบคุม PID Controller จะคำนวณและปรับการทำงานของมอเตอร์ทั้ง 2 ตัว เพื่อให้แกนใบพัดเคลื่อนที่เข้าสู่ตำแหน่งเป้าหมาย ซึ่งในชุดทดลองนี้ ค่า 500 จะเป็นตำแหน่งที่แกนใบพัดอยู่ในแนว ขนานกับพื้น
- ระหว่างการทำงาน ระบบจะอ่านค่าตำแหน่งจริงจากสัญญาณ Feedback แล้วนำมาเปรียบเทียบกับค่า Setpoint จากนั้นตัวควบคุม PID จะปรับสัญญาณควบคุมมอเตอร์อย่างต่อเนื่อง เพื่อลดค่าความคลาดเคลื่อนและรักษาแกนใบพัดให้อยู่ใกล้ตำแหน่งที่กำหนดมากที่สุด
void loop() { Setpoint = 500; //เซตให้อยู่ตรงกลาง หากไม่ใช้ให้ใส่ // ข้างหน้า
สัญญาณป้อนกลับ (Feedback)
- สัญญาณป้อนกลับของระบบได้มาจาก ตัวต้านทานปรับค่าได้ (Potentiometer) ซึ่งเชื่อมต่อทางกลอยู่กับแกนใบพัด ดังนั้นเมื่อแกนใบพัดเปลี่ยนตำแหน่ง ค่าความต้านทานและแรงดันเอาต์พุตของ Potentiometer จะเปลี่ยนแปลงตามไปด้วย ทำให้สามารถใช้เป็นตัวตรวจวัดตำแหน่งของแกนใบพัดได้
- แรงดันเอาต์พุตจาก Potentiometer จะอยู่ในช่วงประมาณ 0–5 VDC และถูกส่งเข้าสู่ขา Analog Input ของ Arduino UNO
- ภายในไมโครคอนโทรลเลอร์ของ Arduino UNO จะมีวงจร Analog-to-Digital Converter (ADC) ความละเอียด 10 บิต ทำหน้าที่แปลงแรงดันอนาล็อก 0–5 V ให้เป็นค่าดิจิทัลในช่วง 0–1023
ดังนั้น
- 0 V จะมีค่าดิจิทัลประมาณ 0
- 2.5 V จะมีค่าดิจิทัลประมาณ 512
- 5 V จะมีค่าดิจิทัลประมาณ 1023
ค่าดิจิทัลที่ได้จาก ADC นี้จะถูกนำมาใช้เป็นค่า Feedback หรือตำแหน่งจริงของแกนใบพัด
การคำนวณ Error และการควบคุม PID
ระบบจะนำค่า Setpoint ซึ่งเป็นตำแหน่งเป้าหมาย มาเปรียบเทียบกับค่า Feedback ซึ่งเป็นตำแหน่งจริงของแกนใบพัด ความแตกต่างระหว่างค่าทั้งสองเรียกว่า Error
Error = Setpoint − Feedback
ค่า Error จะถูกส่งเข้าสู่ตัวควบคุม PID Controller เพื่อคำนวณหาค่าสัญญาณควบคุมที่เหมาะสม
เอาต์พุตจากตัวควบคุม PID จะถูกนำไปสร้างเป็นสัญญาณ PWM (Pulse Width Modulation) สำหรับส่งไปยังวงจร Motor Driver เพื่อควบคุมกำลังและการทำงานของมอเตอร์ทั้งสองตัว
เมื่อมอเตอร์หมุน ใบพัดจะสร้างแรงยกหรือแรงผลักที่แตกต่างกัน ทำให้แกนใบพัดเคลื่อนที่ขึ้นหรือลงเข้าสู่ตำแหน่งเป้าหมายที่กำหนดไว้
กระบวนการนี้จะเกิดขึ้นอย่างต่อเนื่องเป็นวงรอบดังนี้
Setpoint → Error → PID Controller → PWM → Motor Driver → Motor & Propeller → Position → Feedback → Arduino
เมื่อค่า Feedback เข้าใกล้ค่า Setpoint ค่า Error จะลดลง และตัวควบคุม PID จะปรับกำลังของมอเตอร์ให้เหมาะสม เพื่อรักษาแกนใบพัดให้อยู่ในตำแหน่งที่ต้องการ
การใช้งาน PID Library
ในปัจจุบัน การเขียนโปรแกรมควบคุมแบบ PID บน Arduino สามารถทำได้สะดวกมากขึ้น เนื่องจากมี PID Library ที่พัฒนาไว้สำหรับช่วยในการคำนวณและควบคุมระบบโดยเฉพาะ ผู้ใช้งานจึงไม่จำเป็นต้องเขียนสมการและขั้นตอนการคำนวณ PID ใหม่ทั้งหมดด้วยตนเอง
ในการใช้งาน Library จะต้องเริ่มจากการเรียก Library เข้ามาใช้งานในโปรแกรมก่อน โดยใช้คำสั่ง #include ซึ่งปกติจะอยู่บริเวณส่วนต้นของโปรแกรม เช่น บรรทัดที่ 1
ตัวอย่าง
#include <PID_v1.h>
คำสั่งนี้เป็นการเรียก PID Library เข้ามาใช้งานภายในโปรแกรม หลังจากนั้นจึงสามารถกำหนดค่า Setpoint, Feedback, Output รวมถึงค่าพารามิเตอร์ Kp, Ki และ Kd เพื่อทดลองและศึกษาผลตอบสนองของระบบ 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+

การประกาศตัวแปร ที่ใช้ในโปรแกรม
การประกาศตัวแปร พร้อมกับกำหนดค่าที่ต้องการ ในที่นี้คือตัวแปรเกี่ยวกับค่า 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 = 0 และ Kd = 0 เหลือเพียงการปรับค่า Kp เท่านั้น
- หลังจากกำหนดค่า Kp แล้ว ให้อัปโหลดโปรแกรมไปยังบอร์ด Arduino UNO และสังเกตการตอบสนองของแกนใบพัด เพื่อศึกษาผลของการเปลี่ยนแปลงค่า 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);
}






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