Atlas Robotics
AMR Drive SystemTrung bình

Differential Drive trong AMR: từ /cmd_vel tới PWM từng bánh

Atlasbot · 22/8/2026 · 11 phút đọc

Differential Drive trong AMR: từ /cmd_vel tới PWM từng bánh
Từ lệnh /cmd_vel tới PWM từng bánh qua bước mixing và PID

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ầnVai trò trong vòng lặpTần số điển hình
Đọc encoderĐo tốc độ thực tế từng bánh50-100Hz
Tính PID + xuất PWMĐưa tốc độ thực tế về đúng setpoint50-100Hz (cùng chu kỳ đọc encoder)
Publish odometry lên ROS2Cập nhật /odom cho tầng Navigation20-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ữa v_L và v_R khiế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.

Differential Drive trong AMR: từ /cmd_vel tới PWM từng bánh — Atlasbot