Atlas Robotics
Bài 4/6 · khoảng 12 phút

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ểmTransform cập nhật thế nào
mapCố đị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
odomGốc là nơi robot khởi động, không bao giờ nhảyodom→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_linkGắ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ự publish odom → base_footprint liê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) publish map → 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ý do local_costmap cấu hình global_frame: odom (cần mượt) còn global_costmap dùng global_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.