ชมรมโดรน

5. ทำไมโดรนนิ่ง: การควบคุมแบบ PID

วงจรแก้ความคลาดที่โดรนทำหลายร้อยครั้งต่อวินาที อธิบายด้วยตัวอย่างและตัวเลข

โดรนที่ไม่มีระบบควบคุมจะลอยไม่ได้แม้แต่ 2 วินาที ใบพัดไม่เท่ากันนิดเดียว ลมเบาๆ แบตแรงดันตก ล้วนทำให้เอียง และเมื่อเอียงแล้วจะเอียงมากขึ้นเรื่อยๆ (เหมือนไม้บรรทัดที่ตั้งบนปลายนิ้ว) สิ่งที่ทำให้ลอยนิ่งคือ วงจรป้อนกลับ (feedback loop)

หลักการทั่วไป ไม่ใช่ค่าจริงของ RCSA

Firmware ของ FC ไม่เปิดเผย จึงไม่รู้ค่า Kp Ki Kd จริง หน้านี้อธิบายหลักการที่โดรนทุกลำใช้ ตัวเลขทุกตัวเป็นตัวอย่างสมมุติเพื่อให้เห็นภาพ

วงจรป้อนกลับ ใช้ทุกวันโดยไม่รู้ตัว

ตัวอย่างที่ 1: ปรับน้ำอาบให้อุ่น ใช้มือแตะน้ำ รู้สึกเย็นไป (วัด) เทียบกับที่ต้องการ (เป้าหมาย) หมุนก๊อกน้ำร้อนเพิ่ม (แก้) แล้วแตะใหม่ ทำซ้ำจนพอดี

ตัวอย่างที่ 2: ปั่นจักรยานให้ตรง รู้สึกว่าเอียงไปซ้าย ก็หมุนแฮนด์ไปซ้ายเพื่อประคอง ถ้าหมุนแรงเกินก็จะเอียงไปขวา แล้วต้องแก้กลับ จนกว่าจะนิ่ง

โดรนทำแบบเดียวกัน แต่เร็วกว่ามาก

  1. วัด ด้วยไจโรและมาตรความเร่ง (เอียงเท่าไร) เซ็นเซอร์ความสูง (สูงเท่าไร)
  2. เทียบ กับเป้าหมาย (ควรเอียง 0° ควรสูง 110 ซม.) ได้ ความคลาด (error)
  3. แก้ ด้วยการเพิ่มหรือลดรอบมอเตอร์ให้สมเหตุสมผล
  4. กลับไปข้อ 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 เต็มตัว แต่ใช้ความคิดเดียวกัน

  1. อ่านความสูงจริงจาก FC (read_height_cm())
  2. หาความคลาด diff = target − h
  3. ถ้าคลาดเกิน tol (ค่ายอมรับได้) ก็ขยับคำสั่งความสูงไปอีก 1 ก้าว (stepUp หรือ stepDown) ไม่กระโดดทีเดียว
  4. ทำซ้ำทุก tick_ms จนความคลาดอยู่ในช่วงยอมรับได้ ต่อเนื่องครบ stable_ms หรือหมดเวลา timeout_ms

การขยับทีละก้าวทำให้ไม่แก้แรงเกิน (คล้ายการลดค่า P) และการรอ "นิ่งครบเวลา" ก็คือการตรวจว่าไม่ส่ายแล้ว รายละเอียดอยู่ที่ คุมความสูง

ลองทำ

  1. ถ้า Kp = 0.4 โดรนต้องการกำลัง 60 หน่วยเพื่อลอยนิ่ง ถ้ามีแค่ P จะนิ่งที่ความคลาดเท่าไร (คำตอบ: 60 / 0.4 = 150 ซม. ต่ำกว่าเป้า ซึ่งไม่สมเหตุสมผล จึงต้องมี I หรือ ค่า offset ตั้งต้น)
  2. ลองสั่งโดรนในตัวจำลองให้ไปข้างหน้าแล้วหยุด ดูว่ามีช่วง "ค้างนิ่ง" ท้ายคำสั่งเท่าไร (ค่า settle 400 ms ในโค้ด)
  3. หาตัวอย่างในชีวิตประจำวัน 1 อย่างที่ใช้วงจรป้อนกลับ แล้วบอกว่าอะไรคือ "วัด", "เป้าหมาย", "แก้"

พังตรงไหนบ่อย

  • โดรนส่ายตอนลง/หยุดจากความเร็วสูง → ใส่เวลารอ (settle) หลังคำสั่งเคลื่อนที่ และอย่าสั่งคำสั่งใหม่ทันที
  • โดรนลอยแล้วเด้งขึ้นลงเป็นจังหวะ → ไม่ใช่ PID แต่เป็นเซ็นเซอร์อ่านพื้นไม่ได้ (พื้นดำล้วน/มันเงา) ดู เซ็นเซอร์

On this page