โมดูล 3/5 · สัปดาห์ 7–9 · 27 ชม.

ตัวควบคุม PID

UAT 206 ระบบควบคุมและออโตไพลอตเบื้องต้น

เวลาเรียนประมาณ 90 นาทีร่าง รอตรวจปรับปรุงล่าสุด 28 กันยายน 2569

บทเรียน

เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ

  1. เขียนตัวควบคุม PID แบบดิจิทัลและแยกรูปแบบ parallel กับ standard
  2. ป้องกัน integral windup เมื่อสัญญาณควบคุมอิ่มตัว
  3. ใช้อนุพันธ์จากค่าวัดและตัวกรองอนุพันธ์เพื่อลดยอดสัญญาณควบคุม
  4. เลือกค่าพารามิเตอร์เริ่มต้นและอธิบายผลของ P, I และ D ต่อผลตอบสนอง

ความรู้พื้นฐานที่ควรมี: UAT 206 โมดูล 1–2 · UAT 314 โมดูล 3 และ UAT 202 โมดูล 4 (PID และ windup เบื้องต้น)

ทำไมต้องรู้

สูตร PID ในตำราสั้นมาก แต่ตัวควบคุมที่บินได้จริงต้องจัดการเรื่องที่สูตรไม่ได้บอก ได้แก่ คำสั่งที่เกินขีดจำกัดของมอเตอร์ การเปลี่ยนค่าตั้งกะทันหัน และสัญญาณรบกวนของเซนเซอร์ Åström และ Murray (2021) บทที่ 11 และ Åström กับ Hägglund (2006) อธิบายเรื่องเหล่านี้ไว้ละเอียด และ PX4 ใช้วิธีเดียวกันในลูปควบคุมของตัวเอง

สองรูปแบบของ PID

  • แบบ parallel มีค่าขยายแยกกันสามค่า
  • แบบ standard (ideal) มีค่าขยายรวม คูณทั้งสามเทอม

คู่มือจูน PID ของ PX4 อธิบายว่าลูปอัตราหมุนเลือกได้ทั้งสองแบบ ตั้ง MC_ROLLRATE_K = 1 จะเป็นแบบ parallel ส่วนตั้ง P = 1 จะเป็นแบบ standard ซึ่งแยกการปรับค่าขยายรวมออกจาก I และ D ต้องรู้ว่าใช้แบบใดก่อนนำค่าจากที่อื่นมาใช้

ผังตัวควบคุม PID กล่องซ้ายสุด r และ y แยกไปสามกล่อง P เท่ากับ Kp คูณ e, I เท่ากับ Ki อินทิเกรต e และ D เท่ากับลบ Kd คูณ dy/dt แบบกรอง ทั้งสามรวมกันที่วงกลมผลรวม เข้ากล่องจำกัดสัญญาณแล้วออกเป็น u เส้นประสีชมพูจากกล่องจำกัดสัญญาณย้อนกลับไปที่กล่อง I เขียนว่า anti-windup
ภาพที่ 1 ตัวควบคุม PID พร้อม anti-windup

Integral windup

มอเตอร์ให้แรงยกได้จำกัด เมื่อคำสั่งเกินขีดจำกัด สัญญาณจริงจะ อิ่มตัว (saturate) แต่เทอม I ยังสะสมค่าผิดพลาดต่อ เมื่อถึงเป้าแล้ว I ที่สะสมไว้มากจะดันเลยเป้าไปไกล เรียกว่า integral windup วิธีแก้ที่ใช้บ่อยมีสองแบบ

  • Clamping หยุดสะสม I เมื่ออิ่มตัวและค่าผิดพลาดยังดันไปทางเดิม PX4 ใช้วิธีนี้ในลูปความเร็ว (Controller Diagrams)
  • Back-calculation ป้อนผลต่างระหว่างคำสั่งกับค่าที่อิ่มตัวกลับไปลด I (Åström และ Murray ข้อ 11.4)

ตัวอย่างที่ 1 ตัวควบคุมความสูงเมื่อแรงยกอิ่มตัว

สั่งไต่จาก 0 ไป 10 m คำสั่งความเร่งถูกจำกัดที่ ±3 m/s² เพราะแรงยกมีจำกัด

KP, KI, KD, AMAX, DT = 1.5, 0.4, 2.0, 3.0, 0.01

def climb(anti_windup):
    z = v = integ = 0.0
    zs = []
    for _ in range(int(40 / DT)):
        e = 10 - z
        a_cmd = KP * e + KI * integ - KD * v
        a = max(-AMAX, min(AMAX, a_cmd))
        pushing_further = (a_cmd > AMAX and e > 0) or (a_cmd < -AMAX and e < 0)
        if not (anti_windup and pushing_further):
            integ += e * DT
        v += a * DT
        z += v * DT
        zs.append(z)
    settle = next(i * DT for i in range(len(zs)) if all(abs(x - 10) <= 0.2 for x in zs[i:]))
    return max(zs) - 10, settle

for label, flag in (("without anti-windup", False), ("with clamping", True)):
    over, ts = climb(flag)
    print(f"{label:<20} overshoot {over:.2f} m, within 0.2 m after {ts:.1f} s")
without anti-windup  overshoot 4.14 m, within 0.2 m after 11.0 s
with clamping        overshoot 1.58 m, within 0.2 m after 9.8 s

Clamping ลด overshoot ลงมากกว่าครึ่ง ส่วน overshoot ที่เหลือเกิดจากความเร็วที่สะสมระหว่างไต่ด้วยความเร่งเต็มที่ ซึ่งแก้ด้วยการจำกัดความเร็วไต่ในลูปนอก

กราฟความสูงตามเวลา 0 ถึง 25 วินาที เส้นประแนวนอนที่ 10 เมตร เส้นประสีชมพูไม่มี anti-windup ขึ้นไปสูงราว 14 เมตรก่อนลดลงมา เส้นทึบสีฟ้ามี anti-windup ขึ้นไปราว 11.6 เมตรแล้วเข้าที่
ภาพที่ 2 ผลตอบสนองความสูงเมื่อแรงยกอิ่มตัว

อนุพันธ์จากค่าวัดและตัวกรอง

ถ้าคิดเทอม D จาก ค่าผิดพลาด การเปลี่ยนค่าตั้งแบบขั้นจะทำให้อนุพันธ์พุ่งสูงชั่วขณะ Åström และ Murray แนะนำให้ D (และอาจรวม P) ทำงานบน ค่าวัด แทน เรียกว่า setpoint weighting อีกเรื่องคืออนุพันธ์ขยายสัญญาณรบกวนความถี่สูง จึงต้องกรอง โดย และ อยู่ราว 5–20 PX4 ใช้ตัวกรองความถี่ต่ำกับเทอม D ของลูปอัตราหมุน

ตัวอย่างที่ 2 ยอดสัญญาณควบคุมเมื่อเปลี่ยนค่าตั้ง

ค่าตั้งเปลี่ยนแบบขั้นจาก 0 เป็น 10 ขณะค่าวัดยังเป็น 0 ขั้นเวลา 10 ms ดูเฉพาะเทอม D

KP, KD, DT, N = 1.5, 2.0, 0.01, 10
TF = (KD / KP) / N                     # s ค่าคงตัวเวลาของตัวกรองอนุพันธ์

steps = [0.0, 10.0, 10.0, 10.0]        # ค่าตั้งที่แต่ละขั้นเวลา
meas = [0.0, 0.0, 0.02, 0.08]          # ค่าวัด (เพิ่งเริ่มขยับ)

def d_term(signal, sign, filtered):
    d, peak = 0.0, 0.0
    for k in range(1, len(signal)):
        raw = sign * KD * (signal[k] - signal[k - 1]) / DT
        d = d + DT / (TF + DT) * (raw - d) if filtered else raw
        peak = max(peak, abs(d))
    return peak

err = [r - y for r, y in zip(steps, meas)]
print(f"D on error, unfiltered:   peak {d_term(err, 1, False):7.1f}")
print(f"D on error, filtered N={N}: peak {d_term(err, 1, True):7.1f}")
print(f"D on measurement, filtered: peak {d_term(meas, -1, True):7.1f}")
D on error, unfiltered:   peak  2000.0
D on error, filtered N=10: peak   139.5
D on measurement, filtered: peak     1.1

อนุพันธ์ของค่าผิดพลาดพุ่งถึง 2,000 ตัวกรองลดเหลือราว 140 แต่อนุพันธ์จากค่าวัดเหลือราว 1 จึงตัดปัญหาที่ต้นเหตุ เพราะค่าวัดไม่กระโดดตามค่าตั้ง

ลำดับการปรับค่า

คู่มือ PX4 ให้ปรับ ลูปอัตราหมุนก่อน เพราะลูปนี้มีผลต่อทุกโหมดการบิน แล้วจึงปรับลูปท่าทาง ลูปความเร็ว และตำแหน่ง ทดสอบด้วยการสั่งแบบขั้นขณะลอยตัว ซึ่งคู่มือบอกว่าโดรนที่จูนดีต้องตามทันทีโดยไม่แกว่งและไม่เกินเป้า แนวทางทั่วไปคือ

  • P เพิ่มความเร็วตอบสนอง แต่มากเกินจะแกว่ง
  • I แก้ค่าผิดพลาดคงที่ เช่น จุดศูนย์ถ่วงเยื้อง แต่มากเกินจะเกินเป้าช้า ๆ
  • D หน่วงการแกว่ง แต่ขยายสัญญาณรบกวน จึงต้องกรองและดูอุณหภูมิมอเตอร์

ปฏิบัติการประจำโมดูล

ปฏิบัติการ: PID ของความสูงในแบบจำลอง

  1. รันโค้ดตัวอย่างที่ 1 เปลี่ยน KP, KI, KD ทีละค่า บันทึก overshoot และเวลาเข้าที่ลงตาราง
  2. เพิ่มการจำกัดความเร็วไต่ 2 m/s ในลูปนอก เทียบ overshoot กับเดิม
  3. ใช้โค้ดตัวอย่างที่ 2 เปลี่ยน N ระหว่าง 5 ถึง 20 ดูยอดของเทอม D
  4. เปิดคู่มือ PX4 หรือ ArduPilot ระบุว่าพารามิเตอร์ใดเป็น P, I, D และตัวกรองของลูปอัตราหมุน
  5. สรุปลำดับการจูนที่จะใช้ใน SITL ในโมดูล 5

ข้อผิดพลาดที่พบบ่อย

ระวัง

  • นำค่าจากแบบ standard ไปใส่แบบ parallel โดยไม่แปลง
  • ไม่มี anti-windup เมื่อสัญญาณควบคุมอิ่มตัวได้
  • คิด D จากค่าผิดพลาด แล้วแปลกใจที่มอเตอร์กระตุกเมื่อเปลี่ยนค่าตั้ง
  • เพิ่ม D โดยไม่กรอง จนมอเตอร์ร้อน
  • จูนลูปนอกก่อนลูปใน

สรุป

  • PID มีแบบ parallel และแบบ standard ต้องรู้ว่าออโตไพลอตใช้แบบใด
  • anti-windup แบบ clamping หรือ back-calculation ลด overshoot เมื่ออิ่มตัว
  • ใช้อนุพันธ์จากค่าวัดและตัวกรอง ( = 5–20)
  • จูนลูปอัตราหมุนก่อน แล้วจึงลูปนอก

แบบฝึกตรวจความเข้าใจ

  1. PID แบบ standard มี , s ได้ ในแบบ parallel เท่าใด
  2. integral windup เกิดเมื่อใด
  3. , , ได้ เท่าใด
  4. ทำไมจึงคิดเทอม D จากค่าวัดแทนค่าผิดพลาด
  5. คู่มือ PX4 ให้ปรับลูปใดก่อน
เฉลย
  1. เมื่อสัญญาณควบคุมอิ่มตัวแต่เทอม I ยังสะสมค่าผิดพลาดต่อ
  2. s จึงได้ s
  3. ค่าวัดไม่กระโดดตามค่าตั้ง จึงไม่เกิดยอดสัญญาณควบคุม
  4. ลูปอัตราหมุน

สรุปสูตรสำคัญ

PID แบบ parallel
PID แบบ standard (ideal)
ตัวกรองอนุพันธ์

แหล่งอ้างอิงหลัก

  1. Åström, K. J., & Murray, R. M. (2021). Feedback systems: An introduction for scientists and engineers (2nd ed.). Princeton University Press. link
  2. Åström, K. J., & Hägglund, T. (2006). Advanced PID control. ISA–The Instrumentation, Systems, and Automation Society.
  3. PX4 Autopilot. Multicopter PID tuning guide. PX4 guide (main). link
  4. PX4 Autopilot. Controller diagrams. PX4 user guide (main). link

อ่านเพิ่มเติม

ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล

ในชั้นเรียน / ภาคสนาม

ปฏิบัติการในห้องแล็บหรือภาคสนามตามใบงาน พร้อม checklist ความปลอดภัย

หลักฐานการเรียนรู้: ใบงานที่ผ่านการตรวจและผล quiz

แบบทดสอบประจำโมดูล

แบบทดสอบนี้ใช้ตรวจความเข้าใจ (formative) ไม่ใช่การสอบเก็บคะแนน

โดเมนความรู้: การควบคุม ออโตไพลอต และการนำทาง · การวางแผนภารกิจ การบิน และการจำลอง