Inverse Kinematics: biết muốn đi đâu, cần đặt khớp/bánh xe thế nào
Atlasbot · 17/8/2026 · 11 phút đọc
Bài Forward Kinematics trả lời "biết góc khớp, vị trí ở đâu?" — một phép tính lượng giác trực tiếp, luôn ra đúng một kết quả. Inverse Kinematics (động học nghịch) hỏi ngược lại: "muốn đầu tay máy/robot tới đúng vị trí này, cần đặt góc khớp/tốc độ bánh bao nhiêu?" — và câu trả lời không phải lúc nào cũng đơn giản, thậm chí không phải lúc nào cũng tồn tại.
Khái niệm chính
Tiếp tục ví dụ tay máy 2 đoạn ở bài trước — biết vị trí đích (x, y) mong muốn, cần tìm θ1, θ2. Dùng định lý hàm cos (law of cosines) trên tam giác tạo bởi hai đoạn tay và đường thẳng tới đích:
r² = x² + y²
cos(θ2) = (r² − L1² − L2²) / (2·L1·L2)
θ2 = ± arccos(...) ← dấu ± cho 2 lời giải khác nhau
Dấu ± phản ánh một sự thật vật lý: có hai cách đặt khớp khác nhau để đầu tay máy chạm đúng cùng một điểm (x, y) — gọi là cấu hình "elbow-up" và "elbow-down". Cả hai đều đúng về mặt toán học; chọn cái nào phụ thuộc ràng buộc thực tế (tránh va chạm, hoặc gần vị trí hiện tại hơn).
Tóm lại: Forward Kinematics luôn cho đúng 1 kết quả. Inverse Kinematics có thể cho nhiều lời giải, đúng 1 lời giải (robot vi sai), hoặc không lời giải nào (nếu điểm đích nằm ngoài tầm với vật lý).
Nguyên lý hoạt động
Bài Differential Drive thực chất đã dùng đến inverse kinematics mà không gọi tên: biết v, ω mong muốn, suy ngược ra v_L, v_R — chỉ cần đảo ngược đại số hai phương trình tuyến tính, cho ra đúng một lời giải duy nhất:
v_L = v − ω·L/2
v_R = v + ω·L/2
Sự khác biệt căn bản: hệ phương trình của robot vi sai là tuyến tính, trong khi hệ phương trình của tay máy nhiều khớp thường phi tuyến (sin/cos lồng nhau) — độ khó của inverse kinematics phụ thuộc trực tiếp vào số khớp và độ phức tạp hình học.
Với tay máy nhiều khớp hơn (5-6 bậc tự do trở lên), giải trực tiếp bằng đại số trở nên rất phức tạp hoặc bất khả thi. Cách tiếp cận thực tế: dùng thuật toán số lặp dần (Jacobian-based, bắt đầu từ một cấu hình khớp bất kỳ, chỉnh dần theo hướng giảm sai lệch) — đánh đổi lời giải "đúng tuyệt đối" lấy lời giải "đủ gần đích, tính được trong thời gian thực".
Kiến thức kỹ thuật
Công thức
Công thức θ2 ở trên chưa đủ — cần thêm θ1 để có lời giải hoàn chỉnh cho tay máy 2 khớp:
θ1 = atan2(y, x) − atan2(L2·sin(θ2), L1 + L2·cos(θ2))
VD: đích (x,y) = (0.279, 0.443), L1=0.3, L2=0.25 (đảo ngược ví dụ Forward Kinematics)
r² = 0.279² + 0.443² ≈ 0.274
cos(θ2) = (0.274 − 0.09 − 0.0625) / (2×0.3×0.25) ≈ 0.5 → θ2 ≈ 30° (hoặc −30°, elbow-up/down)
θ1 tính theo công thức trên ≈ 45° (khớp lời giải elbow-up trùng đúng bài Forward Kinematics)
Thông số
Điều kiện để inverse kinematics có lời giải — đích phải nằm trong "vùng với tới" (workspace) của tay máy, giới hạn bởi cả biên ngoài lẫn biên trong:
| Điều kiện | Ý nghĩa |
|---|---|
r > L1 + L2 | Đích quá xa, tay máy "duỗi thẳng" cũng không tới — không có lời giải |
r < |L1 − L2| | Đích quá gần, ngay cả gập hết cỡ cũng không thu ngắn đủ — không có lời giải |
|L1−L2| ≤ r ≤ L1+L2 | Có lời giải, thường là 2 lời giải (elbow-up/down) |
Ứng dụng thực tế
Trong hệ sinh thái ROS2, MoveIt là framework hoạch định chuyển động chuẩn cho tay máy, dùng đúng cách tiếp cận số lặp dần đã nói ở phần Nguyên lý hoạt động để giải inverse kinematics cho tay máy 6+ DOF theo thời gian thực — người dùng chỉ cần khai vị trí/hướng đích mong muốn cho end-effector, MoveIt tự tính ra quỹ đạo góc khớp khả thi, tránh va chạm với chính thân robot hoặc vật cản đã biết trong scene. Ngược lại, inverse kinematics của robot AMR vi sai/mecanum (chuyển cmd_vel thành tốc độ từng bánh) đơn giản hơn nhiều vì là hệ tuyến tính có lời giải đóng (closed-form) tức thời — đây là lý do mọi driver động cơ AMR đều tự tính được ngay trên MCU mà không cần thuật toán số lặp dần như tay máy.
Ví dụ thực tế
import math
def inverse_kinematics(x, y, L1, L2, elbow_up=True):
r2 = x**2 + y**2
cos_theta2 = (r2 - L1**2 - L2**2) / (2 * L1 * L2)
theta2 = math.acos(cos_theta2) if elbow_up else -math.acos(cos_theta2)
theta1 = math.atan2(y, x) - math.atan2(L2*math.sin(theta2), L1 + L2*math.cos(theta2))
return math.degrees(theta1), math.degrees(theta2)
theta1, theta2 = inverse_kinematics(0.279, 0.443, 0.3, 0.25, elbow_up=True)
print(f"theta1={theta1:.1f} do, theta2={theta2:.1f} do")
Output:
theta1=45.0 do, theta2=30.0 do
Kết quả khớp chính xác với giá trị đầu vào gốc của ví dụ Forward Kinematics ở bài trước (θ1=45°, θ2=30°) — xác nhận IK và FK là 2 chiều nghịch đảo đúng của nhau: đưa vị trí ra từ FK, đưa ngược lại vào IK, ra đúng góc khớp ban đầu.
Lỗi thường gặp
- Đích nằm ngoài workspace nhưng không kiểm tra trước — như đã nói ở mục Thông số,
rphải nằm trong khoảng[|L1-L2|, L1+L2]— không kiểm tra trước khi tínharccosgây lỗi domain error (input ngoài khoảng[-1, 1]) vìcos(θ2)tính ra ngoài khoảng hợp lệ. - Chọn nhầm nhánh lời giải (elbow-up/down) — cả 2 đều đúng toán học nhưng có thể dẫn tới va chạm vật lý với chướng ngại vật hoặc chính thân robot — luôn kiểm tra ràng buộc thực tế trước khi chọn nhánh, không mặc định lấy nhánh đầu tiên tính được.
- IK số (numerical) không hội tụ gần điểm kỳ dị (singularity) — khi tay máy gần duỗi thẳng hết cỡ, thuật toán lặp dần có thể dao động không hội tụ về lời giải, tương tự vấn đề gimbal lock đã học ở bài Rotation — cần xử lý riêng các trường hợp gần biên workspace.
- Bỏ qua giới hạn góc khớp vật lý — lời giải toán học hợp lệ nhưng vượt quá giới hạn xoay thực tế của khớp cơ khí (VD: khớp chỉ xoay được 0-180° nhưng lời giải yêu cầu 200°) — luôn kiểm tra và giới hạn (clamp) kết quả IK theo đúng giới hạn cơ khí thật của robot trước khi gửi lệnh.
Kết luận
Inverse kinematics là bài toán "chiều khó" của động học robot — có thể nhiều lời giải, một lời giải, hoặc vô nghiệm tuỳ hình học cơ cấu, đối lập với forward kinematics luôn có đúng 1 kết quả dễ tính. Với hệ tuyến tính đơn giản (robot vi sai), giải bằng đại số trực tiếp; với hệ phi tuyến phức tạp (tay máy nhiều khớp), cần phương pháp số như MoveIt sử dụng. Bài tiếp theo trong chuyên mục nói về động học robot Mecanum — một cấu hình bánh xe phức tạp hơn differential drive, cho phép di chuyển ngang (strafe) mà không cần xoay thân robot.