REP-103 & REP-105 — quy ước chuẩn của ROS
REP (ROS Enhancement Proposal) là tài liệu quy ước chính thức của ROS. REP-103 quy định đơn vị và chiều trục. REP-105 quy định tên và quan hệ của các frame chuẩn mà mọi package ROS (Nav2, robot_state_publisher, slam_toolbox...) đều giả định có sẵn.
Không tuân theo 2 quy ước này không làm chương trình báo lỗi ngay — mọi thứ vẫn "chạy", chỉ là các package phối hợp sai với nhau theo cách rất khó phát hiện (ví dụ Nav2 hiểu nhầm đơn vị cm thành mét, robot "dạy" đi xa gấp 100 lần dự kiến).
REP-103: đơn vị và trục
Đơn vị luôn là mét / giây / radian — không phải cm, không phải độ. Chiều trục theo quy tắc bàn tay phải: X hướng tới trước, Y hướng sang trái, Z hướng lên trên. Quaternion (0,0,0,1) nghĩa là "không xoay".
REP-105: map → odom → base_link
| Frame | Đặc điểm | Transform cập nhật thế nào |
|---|---|---|
map | Cố định tuyệt đối, gốc tại 1 điểm trên bản đồ | map→odom: rời rạc, nhảy bậc — mỗi khi AMCL/SLAM sửa lại ước lượng vị trí toàn cục |
odom | Gốc là nơi robot khởi động, không bao giờ nhảy | odom→base_link: liên tục, mượt (vd 50 Hz, tính từ encoder bánh xe) nhưng trôi dần — sai số cộng dồn, không có gì tự sửa |
base_link | Gắn cứng vào chính robot | — |
Xem độ trôi và cú nhảy, trực tiếp trên biểu đồ
Đường xám đứt là vị trí thật của robot. Đường cam (odom) trôi dần khỏi đường thật — không có gì tự sửa. Đường xanh (vị trí trong frame map) bám theo odom nhưng được "sửa" định kỳ — mỗi lần sửa là một cú nhảy trong transform map→odom.
Vì sao tách riêng thay vì gộp 1 frame map→base_link?
Bộ điều khiển vận động (local controller, Module 10) cần dữ liệu mượt, không nhảy để tính lệnh vận tốc. Nếu dùng thẳng map→base_link (có thể nhảy bậc mỗi lần AMCL sửa), robot sẽ giật cục theo mỗi lần sửa lỗi định vị. Tách odom ra làm frame trung gian luôn mượt để điều khiển cục bộ dùng, còn map→odom chỉ ảnh hưởng tới hiểu biết "toàn cục" (global planning), không ảnh hưởng chuyển động tức thời.
Thử ngay
Kiểm tra đơn vị thật trên dữ liệu thật — cần 2 terminal (đã source install/setup.bash, xem Module 0):
# Terminal 1 — để chạy, đừng tắt
ros2 run ros2_basics tf_broadcaster
# Terminal 2 — Ctrl+C để dừng
ros2 run tf2_ros tf2_echo world moving_frame
Translation in ra đơn vị mét, Rotation (RPY) in ra radian — đúng REP-103, không phải cm/độ.
Ví dụ trong dự án Atlas
diff_drive_controller(Module 5) tự publishodom→base_footprintliên tục từ encoder bánh xe — dữ liệu này trôi dần theo quãng đường đi.amcl(Module 9) publishmap→odom— chỉ cập nhật khi có ước lượng mới, không liên tục nhưodom→base_link. Đúng lý dolocal_costmapcấu hìnhglobal_frame: odom(cần mượt) cònglobal_costmapdùngglobal_frame: map(cần đúng vị trí tuyệt đối) — hai lựa chọn khác nhau, không phải ngẫu nhiên.