Differential Drive trong AMR: từ /cmd_vel tới PWM từng bánh
Atlasbot · 22/8/2026 · 11 phút đọc
Bài Động học Differential Drive ở chuyên mục Robotics Fundamentals đã giải đầy đủ công thức toán v, ω. Bài này không lặp lại phần toán đó — nó tập trung vào câu hỏi của người lắp ráp AMR thực tế: công thức đó chạy trên phần cứng nào, thành code gì, và những quyết định cơ khí nào đi kèm.
Khái niệm chính
Một AMR differential drive hoàn chỉnh cần 3 khối phần cứng phối hợp, đúng như đã nêu ở bài Kiến trúc phần cứng:
- 2 bộ động cơ + driver (trái/phải) — đã học ở bài Động cơ và Motor Driver
- 2 encoder (một mỗi bánh) — phản hồi tốc độ thực tế cho vòng điều khiển
- 1 bánh đỡ (caster wheel) — không chủ động, chỉ giữ thăng bằng cho khung robot 3 điểm tựa
Nguyên lý hoạt động
Firmware nhận lệnh /cmd_vel (chứa v, ω mong muốn) từ tầng ROS2 phía trên, thực hiện 2 bước liên tiếp:
Bước 1 — Mixing: chuyển v, ω thành vận tốc mong muốn từng bánh
v_L = v − ω×L/2
v_R = v + ω×L/2
Bước 2 — Vòng điều khiển PID riêng cho từng bánh:
encoder đo v_L_thực_tế, v_R_thực_tế → so sánh với v_L, v_R mong muốn
→ PID tính PWM cần xuất cho từng driver động cơ
Điểm quan trọng dễ bị bỏ sót: bước Mixing chỉ tính ra tốc độ mong muốn, không trực tiếp ra PWM — nếu code xuất thẳng PWM tỉ lệ thuận với v_L/v_R mà bỏ qua vòng PID phản hồi từ encoder, robot sẽ chạy sai tốc độ thực tế bất cứ khi nào có ma sát không đều, pin yếu dần, hoặc tải lệch giữa 2 bên — đúng vấn đề closed-loop vs open-loop đã học ở bài PID (chuyên mục Lập trình nhúng), áp dụng cụ thể vào đây.
Kiến thức kỹ thuật
Công thức
Tần số vòng lặp điều khiển ảnh hưởng trực tiếp độ mượt và độ trễ đáp ứng — vòng lặp quá chậm khiến robot phản ứng giật cục với lệnh vận tốc thay đổi:
Chu_kỳ_vòng_lặp = 1 / Tần_số_vòng_lặp
VD: vòng lặp chạy ở 50Hz → chu kỳ = 1/50 = 20ms giữa mỗi lần
đọc encoder → tính PID → xuất PWM mới
Tần số quá thấp (VD: 5Hz, chu kỳ 200ms) khiến robot "giật" rõ rệt khi
đổi lệnh vận tốc đột ngột — vòng lặp không đủ nhanh để bám theo setpoint
Thông số
| Thành phần | Vai trò trong vòng lặp | Tần số điển hình |
|---|---|---|
| Đọc encoder | Đo tốc độ thực tế từng bánh | 50-100Hz |
| Tính PID + xuất PWM | Đưa tốc độ thực tế về đúng setpoint | 50-100Hz (cùng chu kỳ đọc encoder) |
| Publish odometry lên ROS2 | Cập nhật /odom cho tầng Navigation | 20-50Hz (có thể thấp hơn vòng PID) |
Ứng dụng thực tế
Trong kiến trúc thực tế (đã nêu ở bài Kiến trúc AMR), toàn bộ vòng lặp mixing + PID + đọc encoder chạy trên MCU (ESP32/STM32) thuộc Driver Layer — không chạy trên MPU qua ROS2, vì độ trễ mạng/lịch trình của ROS2 không đảm bảo đủ nhanh và ổn định cho vòng điều khiển tốc độ cao tần số 50-100Hz. MPU chỉ gửi xuống /cmd_vel mới mỗi khi Nav2 tính lại đường đi (tần số thấp hơn nhiều), còn vòng PID tốc độ cao chạy độc lập hoàn toàn trên MCU giữa các lần cập nhật đó.
Ví dụ thực tế
L = 0.35 # khoang cach 2 banh (m)
def mixing(v, omega):
v_L = v - omega * L / 2
v_R = v + omega * L / 2
return v_L, v_R
# Lenh: di thang 0.5 m/s, xoay nhe 0.3 rad/s
v_L, v_R = mixing(v=0.5, omega=0.3)
print(f"v_L={v_L:.3f} m/s, v_R={v_R:.3f} m/s")
# Vong PID (moi banh mot bo gain rieng, chay moi 20ms)
def pid_step(setpoint, measured, integral, prev_error, Kp=2.0, Ki=0.5, Kd=0.1, dt=0.02):
error = setpoint - measured
integral += error * dt
derivative = (error - prev_error) / dt
output = Kp*error + Ki*integral + Kd*derivative
return output, integral, error
Output:
v_L=0.448 m/s, v_R=0.553 m/s
Bánh trái chậm hơn bánh phải đúng như dự đoán khi xoay dương (theo quy ước ω dương là xoay trái) — mỗi bánh sau đó có một bộ PID riêng biệt điều chỉnh PWM để bám đúng setpoint này.
Lỗi thường gặp
- Bỏ qua vòng PID, xuất PWM tỉ lệ thuận trực tiếp với
v_L/v_R— như đã nêu ở phần Nguyên lý, đây là điều khiển open-loop, tốc độ thực tế sẽ trôi theo tải/pin/ma sát mà không có cơ chế tự điều chỉnh. - Chạy vòng PID với tần số quá thấp — như tính ở mục Công thức, robot phản ứng giật cục, đặc biệt rõ khi Nav2 gửi lệnh vận tốc thay đổi liên tục.
- Dùng chung 1 bộ gain PID cho cả 2 bánh dù cơ khí không hoàn toàn đối xứng — ma sát/tải thực tế 2 bên hiếm khi giống hệt nhau, gain PID nên được tinh chỉnh riêng hoặc ít nhất kiểm tra riêng cho từng bánh.
- Không kiểm tra dấu (chiều) khi mixing — nhầm dấu
+/−giữav_Lvàv_Rkhiến robot xoay ngược hướng lệnh yêu cầu dù độ lớn tính đúng, lỗi giống hệt đã cảnh báo ở bài Động học Differential Drive.
Kết luận
Công thức v_L = v − ωL/2, v_R = v + ωL/2 chỉ là bước đầu — biến nó thành chuyển động thực tế đáng tin cậy cần thêm vòng PID phản hồi từ encoder chạy đúng tần số trên đúng lớp phần cứng (MCU, không phải qua ROS2). Bài tiếp theo trong chuyên mục đi vào Mecanum Drive — mở rộng bài toán mixing này lên 4 bánh để đạt khả năng đi ngang.