Quaternion là gì? Cách biểu diễn hướng không bị Gimbal Lock
Atlasbot · 17/8/2026 · 10 phút đọc
Mở bất kỳ message nav_msgs/msg/Odometry hay geometry_msgs/msg/PoseStamped nào trong ROS2, phần hướng (orientation) không lưu một góc θ quen thuộc, mà là 4 con số (x, y, z, w) — một quaternion. Đây không phải lựa chọn ngẫu nhiên: quaternion là cách biểu diễn hướng chuẩn trong toàn bộ hệ sinh thái ROS2/ROS, chính vì nó giải quyết được vấn đề gimbal lock đã nêu ở bài Rotation và Euler Angles.
Khái niệm chính
Thay vì nghĩ "xoay 30° quanh x, rồi 45° quanh y, rồi 10° quanh z" (ba bước tuần tự dễ gây gimbal lock), quaternion biểu diễn bất kỳ hướng xoay 3D nào cũng chỉ bằng một phép xoay duy nhất — quay một góc θ quanh một trục duy nhất:
q = (x, y, z, w)
= (trục_xoay × sin(θ/2), cos(θ/2))
(x, y, z) mã hoá hướng của trục xoay, w mã hoá góc xoay quanh trục đó. Với θ = 0 (không xoay gì), quaternion là (0, 0, 0, 1) — giá trị "identity".
Tóm lại: Vì một phép xoay chỉ cần đúng một trục + một góc, quaternion không có điểm kỳ dị nào trong toàn bộ không gian xoay — đây là lý do toán học chính xác vì sao nó "không bị gimbal lock".
Nguyên lý hoạt động
Một quaternion có 4 thành phần nhưng phép xoay 3D chỉ có 3 bậc tự do — sự chênh lệch này được giải quyết bằng ràng buộc: quaternion hợp lệ luôn có độ dài (norm) bằng 1:
x² + y² + z² + w² = 1
Ràng buộc "đơn vị" (unit quaternion) này giảm 4 số xuống còn đúng 3 bậc tự do độc lập. Một hệ quả thực tế: nếu tự cộng dồn quaternion qua nhiều bước (thường gặp khi tích hợp vận tốc góc từ IMU theo thời gian), sai số làm tròn có thể khiến x²+y²+z²+w² lệch dần khỏi 1 — cần chuẩn hoá (normalize) định kỳ.
Nội suy mượt giữa hai hướng xoay dùng kỹ thuật SLERP (Spherical Linear Interpolation) trên quaternion cho ra chuyển động xoay với tốc độ góc đều — nội suy trực tiếp trên góc Euler dễ tạo chuyển động không đều.
Kiến thức kỹ thuật
Công thức
Ghép 2 phép xoay liên tiếp (VD: robot đã xoay theo q1, giờ xoay thêm q2) là phép nhân quaternion (Hamilton product), không giao hoán giống ma trận — thứ tự nhân quyết định thứ tự áp dụng phép xoay:
q_tong_hop = q2 ⊗ q1 (áp dụng q1 trước, q2 sau)
Trường hợp đơn giản — 2 phép xoay quanh CÙNG 1 trục: góc cộng dồn trực tiếp
VD: xoay 30° quanh z rồi xoay thêm 45° quanh z = xoay 75° quanh z
Với 2 trục xoay khác nhau, công thức đầy đủ phức tạp hơn (nhân theo quy tắc Hamilton, không chỉ cộng góc) — hầu hết code thực tế dùng hàm có sẵn của thư viện (tf_transformations, scipy.spatial.transform) thay vì tự triển khai công thức nhân tay.
Thông số
Một số giá trị quaternion tham khảo hay gặp khi debug — nhận ra ngay các giá trị "chuẩn" này giúp xác nhận nhanh dữ liệu có hợp lý không:
| Phép xoay | Quaternion (x, y, z, w) |
|---|---|
| Không xoay (identity) | (0, 0, 0, 1) |
| Xoay 90° quanh trục z | (0, 0, 0.707, 0.707) |
| Xoay 180° quanh trục z | (0, 0, 1, 0) |
Ứng dụng thực tế
SLERP trên quaternion là kỹ thuật chuẩn để lập kế hoạch chuyển động mượt cho cơ cấu pan-tilt (camera xoay ngang-dọc) hoặc hướng end-effector của tay máy — nội suy trực tiếp giữa hướng bắt đầu và hướng kết thúc theo tốc độ góc đều, tránh hiện tượng "giật" tốc độ không đều hoặc đi vòng xa hơn cần thiết mà nội suy tuyến tính trên Euler angles dễ mắc phải (đã nói ở bài Rotation). Bất kỳ chuyển động xoay mượt nào trong robot học — không chỉ animation hiển thị mà cả quỹ đạo chuyển động thật của tay máy — đều nên dùng SLERP thay vì tự nội suy tuyến tính trên góc.
Ví dụ thực tế
from tf_transformations import euler_from_quaternion, quaternion_from_euler
import numpy as np
# Chuyển yaw = 90 độ sang quaternion
q = quaternion_from_euler(0, 0, np.radians(90))
print(f"Quaternion cho yaw=90: {[round(v, 3) for v in q]}")
# Chuyển ngược lại để kiểm tra
roll, pitch, yaw = euler_from_quaternion(q)
print(f"Yaw doc lai: {np.degrees(yaw):.1f} do")
Output:
Quaternion cho yaw=90: [0.0, 0.0, 0.707, 0.707]
Yaw doc lai: 90.0 do
Kết quả [0, 0, 0.707, 0.707] khớp đúng với bảng tham khảo ở mục Thông số — xác nhận công thức và thư viện đang hoạt động đúng, và việc chuyển đổi qua lại Euler↔quaternion không làm mất thông tin (đọc lại đúng 90°).
Lỗi thường gặp
- Quên chuẩn hoá quaternion sau khi cộng dồn nhiều bước — như đã nói ở phần Nguyên lý hoạt động, sai số tích luỹ khiến
x²+y²+z²+w²lệch khỏi 1, quaternion không còn hợp lệ, gây kết quả xoay sai dần theo thời gian. - Nhầm thứ tự
(x,y,z,w)với(w,x,y,z)giữa các thư viện — ROS2/ROS dùng thứ tự(x,y,z,w), nhưng một số thư viện toán học khác (VD: Eigen trong C++) dùng thứ tự(w,x,y,z)— copy nhầm thứ tự giữa 2 hệ sinh thái cho ra quaternion hoàn toàn khác nghĩa dù cùng 4 con số. - Không biết
qvà-qbiểu diễn cùng một phép xoay — quaternion có tính "double cover" (2 giá trị khác nhau về dấu nhưng cùng ý nghĩa hình học) — so sánh trực tiếp bằng dấu==giữa 2 quaternion có thể báo "khác nhau" dù chúng biểu diễn đúng 1 hướng xoay, cần so sánh qua tích vô hướng hoặc chuẩn hoá dấu trước khi so sánh. - Tính trung bình cộng trực tiếp các thành phần quaternion để "nội suy" — cộng rồi chia trung bình từng thành phần
(x,y,z,w)không cho ra quaternion hợp lệ (không còn chuẩn = 1) và không phải là hướng xoay trung gian đúng về mặt hình học — luôn dùng SLERP thay vì phép trung bình cộng ngây thơ.
Kết luận
Quaternion giải quyết triệt để vấn đề gimbal lock của Euler angles bằng cách biểu diễn mọi phép xoay 3D chỉ bằng 1 trục + 1 góc, đánh đổi bằng việc khó hình dung trực quan hơn — đây là lý do ROS2 chọn quaternion làm chuẩn lưu trữ hướng trong mọi message, dù code debug/hiển thị vẫn thường quy đổi tạm sang Euler cho dễ đọc. Đây cũng là bài cuối trong nhóm 3 bài về phép xoay (Matrix → Rotation → Quaternion). Bài tiếp theo trong chuyên mục nói về Transform — cách kết hợp cả xoay lẫn dịch chuyển thành một phép biến đổi toạ độ hoàn chỉnh.