5. ทำไมโดรนนิ่ง: การควบคุมแบบ PID
วงจรแก้ความคลาดที่โดรนทำหลายร้อยครั้งต่อวินาที อธิบายด้วยตัวอย่างและตัวเลข
โดรนที่ไม่มีระบบควบคุมจะลอยไม่ได้แม้แต่ 2 วินาที ใบพัดไม่เท่ากันนิดเดียว ลมเบาๆ แบตแรงดันตก ล้วนทำให้เอียง และเมื่อเอียงแล้วจะเอียงมากขึ้นเรื่อยๆ (เหมือนไม้บรรทัดที่ตั้งบนปลายนิ้ว) สิ่งที่ทำให้ลอยนิ่งคือ วงจรป้อนกลับ (feedback loop)
หลักการทั่วไป ไม่ใช่ค่าจริงของ RCSA
Firmware ของ FC ไม่เปิดเผย จึงไม่รู้ค่า Kp Ki Kd จริง หน้านี้อธิบายหลักการที่โดรนทุกลำใช้ ตัวเลขทุกตัวเป็นตัวอย่างสมมุติเพื่อให้เห็นภาพ
วงจรป้อนกลับ ใช้ทุกวันโดยไม่รู้ตัว
ตัวอย่างที่ 1: ปรับน้ำอาบให้อุ่น ใช้มือแตะน้ำ รู้สึกเย็นไป (วัด) เทียบกับที่ต้องการ (เป้าหมาย) หมุนก๊อกน้ำร้อนเพิ่ม (แก้) แล้วแตะใหม่ ทำซ้ำจนพอดี
ตัวอย่างที่ 2: ปั่นจักรยานให้ตรง รู้สึกว่าเอียงไปซ้าย ก็หมุนแฮนด์ไปซ้ายเพื่อประคอง ถ้าหมุนแรงเกินก็จะเอียงไปขวา แล้วต้องแก้กลับ จนกว่าจะนิ่ง
โดรนทำแบบเดียวกัน แต่เร็วกว่ามาก
- วัด ด้วยไจโรและมาตรความเร่ง (เอียงเท่าไร) เซ็นเซอร์ความสูง (สูงเท่าไร)
- เทียบ กับเป้าหมาย (ควรเอียง 0° ควรสูง 110 ซม.) ได้ ความคลาด (error)
- แก้ ด้วยการเพิ่มหรือลดรอบมอเตอร์ให้สมเหตุสมผล
- กลับไปข้อ 1 ภายในเสี้ยววินาที ทำซ้ำเป็นร้อยๆ ครั้งต่อวินาที
P I D สามส่วนของ "วิธีแก้"
สมมุติโดรนต้องรักษาความสูง 110 ซม. แต่ตอนนี้อยู่ที่ 80 ซม. ความคลาด e = 110 − 80 = 30 ซม. ต้องตัดสินใจว่าจะเร่งมอเตอร์มากแค่ไหน มีสามความคิด
P: แก้ตามความคลาดตอนนี้
ยิ่งคลาดมาก ยิ่งแก้แรง ยิ่งคลาดน้อย ยิ่งแก้เบา
ออก = Kp × eถ้า Kp = 0.5 และ e = 30 → ออก = 15 หน่วย ถ้า e เหลือ 6 → ออก = 3 หน่วย เหมือนเรามองเห็นว่าคลาดเท่าไรแล้วแก้เท่านั้น ใช้เองได้โดยไม่ต้องรู้อดีต
ข้อเสียของ P อย่างเดียว: ถ้า Kp ใหญ่เกินจะแก้แรงจนเลยเป้า ต้องแก้กลับ ส่ายไปมา ถ้า Kp เล็กเกินจะช้า และมีอีกปัญหาที่ละเอียดกว่านั้น: คลาดคงที่ที่ไม่หายไปไหน อธิบายด้านล่าง
I: แก้ตามความคลาดที่สะสม
ลอยนิ่งต้องใช้กำลังมอเตอร์ระดับหนึ่งเสมอ (เพื่อต้านน้ำหนัก) สมมุติต้องใช้ 50 หน่วย ถ้ามีแค่ P: ออก = Kp × e ต้องเท่ากับ 50 ถึงจะนิ่ง ถ้า Kp = 2 จะนิ่งเมื่อ e = 25 นั่นคือ ลอยนิ่งอยู่ต่ำกว่าเป้า 25 ซม. ตลอดไป เพราะถ้าคลาดหายเป็น 0 ก็ไม่มีแรงเหลือต้านน้ำหนัก
ส่วน I แก้โดย "จำ" ว่าคลาดค้างมานานแค่ไหนแล้ว
ออก = Ki × (ผลรวมของ e ตลอดเวลาที่ผ่านมา)ตราบใดที่ยังคลาดค้างอยู่ ผลรวมจะโตขึ้นเรื่อยๆ จนดันโดรนให้ขึ้นมาถึงเป้า (เหมือนเปิดก๊อกน้ำร้อนทีละนิดจนกว่าจะอุ่นจริง)
ข้อเสียของ I: ถ้าใหญ่เกินจะ "สะสมเกิน" แล้วพุ่งเลยเป้า
D: แก้ตามความเร็วที่ความคลาดกำลังเปลี่ยน
ส่วน D มองไปข้างหน้า ถ้าโดรนกำลังพุ่งเข้าหาเป้าเร็วมาก ก็เบรกไว้ก่อนจะถึง
ออก = Kd × (ความคลาดเปลี่ยนไปกี่หน่วยต่อวินาที)เหมือนเห็นรถคันหน้ากำลังจะหยุด เราปล่อยคันเร่งก่อนที่จะชน D ช่วยลดอาการส่ายเลยเป้า ข้อเสียของ D: ไวต่อสัญญาณรบกวนจากเซ็นเซอร์ ถ้าใหญ่เกินจะสั่นถี่ๆ
รวมกัน
ออก = Kp × e + Ki × ∫e + Kd × (de/dt)เมื่อโดรนโดนลมกดให้ตก แต่ละแบบตอบต่างกัน
| ถ้าตั้งผิดแบบนี้ | อาการที่เห็น |
|---|---|
| Kp ใหญ่เกิน | ส่ายไปมาเรื่อยๆ ไม่ยอมนิ่ง |
| Kp เล็กเกิน | ตอบสนองช้า โดนลมแล้วค่อยๆ กลับ |
| Ki ใหญ่เกิน | พุ่งเลยเป้าแล้วค่อยๆ กลับมา (overshoot) |
| Ki เล็กเกิน | ค้างต่ำกว่าเป้าตลอด |
| Kd ใหญ่เกิน | สั่นถี่ มอเตอร์ร้อน เสียงแหลม |
| Kd เล็กเกิน | ส่ายเลยเป้าหลายรอบก่อนนิ่ง |
แล้วเราจูนได้ไหม
บนโดรน RCSA EDU ที่ใช้ในแข่ง เราไม่ได้จูนค่าเหล่านี้ ผู้ผลิตตั้งไว้ในตัวควบคุมการบินแล้ว สิ่งที่เราเข้าไปแก้ได้มีแค่ระดับสูง เช่น ความเร็วบินและเวลารอ แต่การเข้าใจ PID ช่วยให้อ่านอาการของโดรนออก เช่นถ้าโดรนส่ายหลังหยุดจากบินไปหน้า แปลว่าค่าความหน่วงสู้แรงเฉื่อยไม่พอ ให้เพิ่ม settle (เวลารอหลังหยุด) แทนการดันให้เร็วขึ้น
ในโค้ดชมรมมี "วงจรป้อนกลับ" ของเราเองด้วย
ฟังก์ชัน goto_height_smooth ใน poke_controls.ino เป็นตัวอย่างที่อ่านง่าย มันไม่ใช่ PID เต็มตัว แต่ใช้ความคิดเดียวกัน
- อ่านความสูงจริงจาก FC (
read_height_cm()) - หาความคลาด
diff = target − h - ถ้าคลาดเกิน
tol(ค่ายอมรับได้) ก็ขยับคำสั่งความสูงไปอีก 1 ก้าว (stepUpหรือstepDown) ไม่กระโดดทีเดียว - ทำซ้ำทุก
tick_msจนความคลาดอยู่ในช่วงยอมรับได้ ต่อเนื่องครบstable_msหรือหมดเวลาtimeout_ms
การขยับทีละก้าวทำให้ไม่แก้แรงเกิน (คล้ายการลดค่า P) และการรอ "นิ่งครบเวลา" ก็คือการตรวจว่าไม่ส่ายแล้ว รายละเอียดอยู่ที่ คุมความสูง
ลองทำ
- ถ้า Kp = 0.4 โดรนต้องการกำลัง 60 หน่วยเพื่อลอยนิ่ง ถ้ามีแค่ P จะนิ่งที่ความคลาดเท่าไร (คำตอบ: 60 / 0.4 = 150 ซม. ต่ำกว่าเป้า ซึ่งไม่สมเหตุสมผล จึงต้องมี I หรือ ค่า offset ตั้งต้น)
- ลองสั่งโดรนในตัวจำลองให้ไปข้างหน้าแล้วหยุด ดูว่ามีช่วง "ค้างนิ่ง" ท้ายคำสั่งเท่าไร (ค่า
settle400 ms ในโค้ด) - หาตัวอย่างในชีวิตประจำวัน 1 อย่างที่ใช้วงจรป้อนกลับ แล้วบอกว่าอะไรคือ "วัด", "เป้าหมาย", "แก้"
พังตรงไหนบ่อย
- โดรนส่ายตอนลง/หยุดจากความเร็วสูง → ใส่เวลารอ (
settle) หลังคำสั่งเคลื่อนที่ และอย่าสั่งคำสั่งใหม่ทันที - โดรนลอยแล้วเด้งขึ้นลงเป็นจังหวะ → ไม่ใช่ PID แต่เป็นเซ็นเซอร์อ่านพื้นไม่ได้ (พื้นดำล้วน/มันเงา) ดู เซ็นเซอร์