PID là gì? Bộ điều khiển kinh điển đứng sau mọi vòng lặp ổn định
Atlasbot · 16/8/2026 · 11 phút đọc
Biết tốc độ động cơ hiện tại (nhờ encoder) là chưa đủ — cần một bộ điều khiển tự động quyết định phải điều chỉnh PWM bao nhiêu để tốc độ thực tế tiến sát tốc độ mong muốn, kể cả khi tải thay đổi liên tục. PID (Proportional–Integral–Derivative) là bộ điều khiển kinh điển và phổ biến nhất cho bài toán này — đơn giản để hiểu, hiệu quả trong hầu hết ứng dụng thực tế.
Khái niệm chính
Ý tưởng cốt lõi của mọi vòng điều khiển: liên tục tính sai số (error) giữa giá trị mong muốn (setpoint) và giá trị đo được thực tế, rồi dùng sai số đó để quyết định tín hiệu điều khiển tiếp theo.
error = setpoint - giá_trị_đo_được
PID kết hợp ba thành phần, mỗi thành phần phản ứng với sai số theo một cách khác nhau:
- P (Proportional) — tỷ lệ thuận với sai số hiện tại: sai số càng lớn, phản ứng càng mạnh. Đơn giản nhưng dùng một mình thường để lại sai số dư (steady-state error) — không bao giờ về đúng chính xác setpoint.
- I (Integral) — cộng dồn sai số theo thời gian: nếu sai số nhỏ nhưng kéo dài (P một mình không đủ mạnh để triệt tiêu hẳn), phần I sẽ tích luỹ dần và đẩy hệ thống tới đúng setpoint.
- D (Derivative) — phản ứng theo tốc độ thay đổi của sai số: nếu sai số đang giảm rất nhanh (sắp vọt qua setpoint), D sẽ "phanh" bớt để tránh dao động quá đà (overshoot).
Tóm lại: P kéo nhanh về đích nhưng để lại sai số dư · I triệt tiêu sai số dư nhưng phản ứng chậm và dễ gây dao động nếu quá mạnh · D làm mượt, chống vọt lố nhưng nhạy với nhiễu đo lường.
Nguyên lý hoạt động
setpoint ──►(+) ┌─── P: Kp × error ───┐
│ error │ │
đo được ──►(-)┴──────────►├─── I: Ki × Σerror ──┼──► (+) ──► PWM ──► Động cơ
│ │ │
└─── D: Kd × Δerror ──┘ │
│
◄──────────── Encoder đo tốc độ thực ─────────────┘
Công thức tính đầu ra PID mỗi chu kỳ (thường chạy trong ngắt Timer, tần số cố định như 100Hz hoặc 1kHz):
float error = setpoint - measured_speed;
integral += error * dt;
float derivative = (error - previous_error) / dt;
float output = Kp * error + Ki * integral + Kd * derivative;
previous_error = error;
set_motor_pwm(output); // Áp giá trị vừa tính ra động cơ
Ba hằng số Kp, Ki, Kd phải được chỉnh (tuning) cho từng hệ thống cụ thể — không có bộ số chung cho mọi động cơ. Cách chỉnh phổ biến nhất là tăng dần Kp cho tới khi hệ thống dao động nhẹ, giảm lại một chút, rồi thêm Ki để triệt tiêu sai số dư, cuối cùng thêm Kd nếu cần giảm dao động — quá trình này thường mất nhiều lần thử-sai trên phần cứng thật, vì mô phỏng lý thuyết hiếm khi khớp hoàn toàn với ma sát và quán tính thực tế của động cơ.
Kiến thức kỹ thuật
Công thức
Áp dụng đúng công thức PID ở trên với số liệu cụ thể để thấy rõ từng thành phần đóng góp bao nhiêu vào đầu ra cuối cùng:
output = Kp×error + Ki×integral + Kd×derivative
VD: Kp=2.0, Ki=0.5, Kd=0.1
setpoint = 100 RPM, đo được = 85 RPM → error = 15
integral (tích luỹ từ trước) = 40
derivative (error thay đổi -5 so với chu kỳ trước, dt=0.01s) = (15-20)/0.01 = -500
output = 2.0×15 + 0.5×40 + 0.1×(-500)
= 30 + 20 - 50 = 0
Ví dụ này cho thấy thành phần D có thể triệt tiêu gần hết đóng góp của P và I khi sai số đang giảm rất nhanh — đúng vai trò "phanh" chống vọt lố đã nói ở phần Khái niệm chính, dù nhìn qua có vẻ ngược đời (sai số vẫn dương 15 mà output lại gần 0).
Thông số
Tần số chạy vòng lặp PID (sample rate) cần đủ nhanh so với đặc tính động học của hệ thống đang điều khiển — chạy quá chậm khiến bộ điều khiển "phản ứng trễ" với thay đổi thực tế:
| Loại vòng điều khiển | Tần số PID điển hình |
|---|---|
| Tốc độ động cơ DC (dùng encoder) | 100Hz – 1kHz |
| Vị trí/góc (VD: cân bằng robot 2 bánh) | 100 – 500Hz |
| Nhiệt độ (hệ nhiệt, thay đổi chậm) | 1 – 10Hz đã đủ |
Phương pháp chỉnh Kp/Ki/Kd có hệ thống hơn cách thử-sai đã nói ở trên là Ziegler-Nichols — tăng Kp (Ki=Kd=0) tới khi hệ dao động ổn định liên tục, ghi lại "Kp tới hạn" và chu kỳ dao động, rồi tính Kp/Ki/Kd theo bảng công thức chuẩn hoá dựa trên 2 giá trị đó.
Ứng dụng thực tế
Ngoài giữ tốc độ động cơ đã nói xuyên suốt bài, PID còn dùng phổ biến để giữ hướng đi (heading) của robot bám thẳng theo la bàn/IMU — setpoint là góc hướng mong muốn, giá trị đo được là góc thực tế từ IMU, đầu ra PID là chênh lệch tốc độ giữa 2 bánh (bánh nào cần quay nhanh hơn để robot tự chỉnh về đúng hướng). Trong robot 2 bánh vi sai phức tạp hơn, thường dùng PID lồng (cascade): 1 vòng PID vị trí (setpoint là quãng đường/điểm đến) tạo ra setpoint tốc độ cho 1 vòng PID tốc độ bên trong — mỗi vòng chỉ giải quyết đúng 1 bài toán, dễ chỉnh hơn nhiều so với gộp chung thành 1 bộ PID duy nhất.
Ví dụ thực tế
#include <stdio.h>
int main() {
float Kp = 2.0, Ki = 0.5, Kd = 0.1;
float setpoint = 100.0;
float measured = 85.0;
float integral = 40.0;
float previous_error = 20.0;
float dt = 0.01;
float error = setpoint - measured;
integral += error * dt;
float derivative = (error - previous_error) / dt;
float output = Kp*error + Ki*integral + Kd*derivative;
printf("error = %.1f\n", error);
printf("P = %.1f, I = %.1f, D = %.1f\n", Kp*error, Ki*integral, Kd*derivative);
printf("output = %.1f\n", output);
return 0;
}
Output:
error = 15.0
P = 30.0, I = 20.2, D = -500.0
output = -449.8
Kết quả output âm lớn (dù error vẫn dương) minh hoạ rõ rủi ro thực tế của thành phần D khi derivative quá lớn — nếu không giới hạn (clamp) giá trị output về đúng khoảng PWM hợp lệ trước khi áp vào động cơ, động cơ có thể bị ra lệnh đảo chiều đột ngột dù đang đúng hướng cần đi, một lỗi khó chẩn đoán nếu không in ra từng thành phần P/I/D riêng biệt để debug như ví dụ này.
Lỗi thường gặp
- Tích luỹ tràn (integral windup) — khi động cơ đã đạt giới hạn PWM tối đa nhưng vẫn chưa đuổi kịp setpoint, phần I tiếp tục cộng dồn không giới hạn, tới khi sai số đảo chiều, hệ thống mất một khoảng thời gian dài mới "xả" hết phần tích luỹ dư thừa này, gây vọt lố nghiêm trọng — cần giới hạn (clamp) giá trị integral trong một khoảng hợp lý.
- "Derivative kick" khi đổi setpoint đột ngột — thay đổi setpoint tức thời (VD: từ 0 lên 100 RPM ngay lập tức) khiến
errornhảy vọt trong 1 chu kỳ, thành phần D tính theo đạo hàm của error cũng nhảy vọt theo, tạo một xung điều khiển bất thường — giải pháp phổ biến là tính đạo hàm theo giá trị đo được thay vì theo error. - Quên giới hạn (clamp) đầu ra về đúng khoảng PWM hợp lệ — như minh hoạ ở ví dụ trên, output tính ra có thể vượt xa khoảng giá trị PWM hợp lệ (0-100% hoặc âm/dương cho chiều quay) — luôn kiểm tra và giới hạn output trước khi áp vào driver động cơ.
dtkhông cố định giữa các lần tính — nếu vòng lặp PID không chạy ở tần số cố định (VD: đặt trongloop()thay vì ngắt Timer),dtthực tế dao động theo thời gian xử lý các việc khác, khiến hành vi hệ thống không nhất quán giữa các lần chạy dù cùng bộ Kp/Ki/Kd.
Kết luận
PID là bộ điều khiển đơn giản nhưng đủ mạnh cho phần lớn nhu cầu ổn định trong robot — từ giữ tốc độ động cơ, giữ hướng đi, tới các vòng lồng phức tạp hơn cho vị trí. Hiểu đúng vai trò từng thành phần P/I/D và các bẫy kinh điển (integral windup, derivative kick) giúp tránh phần lớn hành vi khó hiểu khi mới chỉnh PID trên phần cứng thật. Đây cũng là bài áp chót trong chuyên mục Điều khiển động cơ — bài cuối sẽ tổng hợp so sánh các phương pháp điều khiển tốc độ động cơ đã học.