Map trong ROS2: Occupancy Grid lưu bản đồ dưới dạng ảnh xám
Atlasbot · 17/8/2026 · 11 phút đọc
Bài Navigation là gì? đặt Map là mảnh ghép đầu tiên. Định dạng bản đồ chuẩn trong ROS2 — Occupancy Grid — đơn giản hơn nhiều so với "bản đồ" theo nghĩa thông thường: chỉ là một lưới ô vuông, mỗi ô mang một giá trị xác suất.
Khái niệm chính
Mỗi ô (cell) trong grid mang một trong ba trạng thái:
0 → free (trống, robot đi qua được)
100 → occupied (có vật cản)
-1 → unknown (chưa quét tới, không rõ)
Toàn bộ bản đồ chẳng qua là một mảng 2D các số nguyên này — publish trên topic /map với message type nav_msgs/msg/OccupancyGrid, kèm theo resolution (kích thước thật của mỗi ô, ví dụ 0.05m = 5cm/ô) và origin (toạ độ thực của góc bản đồ, để chuyển đổi giữa chỉ số ô và toạ độ thế giới thực trong hệ map, đã nói ở bài Hệ toạ độ trong Robot).
Nguyên lý hoạt động
Trên đĩa, bản đồ được lưu thành 2 file: my_map.pgm — ảnh xám (grayscale) thực sự, trắng=free, đen=occupied, xám=unknown; và my_map.yaml — metadata gồm resolution, origin, ngưỡng free/occupied. .pgm (Portable GrayMap) là định dạng ảnh xám cực đơn giản, mở được bằng bất kỳ trình xem ảnh nào — đây là lý do bạn có thể mở bản đồ robot bằng Paint hoặc GIMP để sửa tay (xoá nhiễu, vẽ thêm tường ảo) trước khi nạp lại vào robot, không cần công cụ chuyên dụng.
Sau khi SLAM (chuyên mục riêng) đã dựng và lưu xong bản đồ, map_server là node đọc file .yaml/.pgm này và publish lại lên topic /map — đây là bước chuyển từ "đang dựng bản đồ" (SLAM) sang "dùng bản đồ đã có" (AMCL + Nav2), đúng ranh giới đã nói ở bài AMCL là gì?.
Tóm lại: Occupancy Grid cố tình đơn giản — chỉ 3 trạng thái mỗi ô, lưu dưới dạng ảnh xám phổ thông — đổi lại sự đơn giản đó là khả năng tương thích rộng: mọi công cụ SLAM, mọi thuật toán path planning, mọi phần mềm chỉnh sửa ảnh thông thường đều đọc/ghi được cùng một định dạng.
Kiến thức kỹ thuật
Công thức
Độ phân giải (resolution) — đánh đổi giữa chi tiết bản đồ và dung lượng/tốc độ tính toán:
resolution càng nhỏ (ô càng nhỏ) → bản đồ chi tiết hơn, phát hiện vật cản nhỏ tốt hơn
→ file lớn hơn, tính toán costmap chậm hơn
resolution càng lớn (ô càng to) → nhẹ, nhanh, nhưng bỏ sót vật cản nhỏ
Số ô grid = (Chiều_rộng_thực / resolution) × (Chiều_cao_thực / resolution)
VD: bản đồ kho hàng 40m × 30m, resolution 0.05m
Số ô = (40/0.05) × (30/0.05) = 800 × 600 = 480,000 ô
Thông số
| resolution | Phù hợp |
|---|---|
| 0.02-0.03m | Không gian nhỏ, cần chi tiết cao (phòng thí nghiệm, khu vực hẹp) |
| 0.05m | Phổ biến cho AMR trong nhà — cân bằng chi tiết và hiệu năng |
| 0.1m trở lên | Không gian lớn (nhà kho rộng, ngoài trời), ưu tiên tốc độ tính costmap |
Ứng dụng thực tế
Giá trị phổ biến cho AMR trong nhà: 0.05m (5cm/ô) — đủ chi tiết để phân biệt chân bàn, cột nhỏ, mà vẫn giữ kích thước file và tốc độ tính toán costmap hợp lý trên phần cứng nhúng như Raspberry Pi 4 hay Jetson Orin Nano (đã học ở bài Chọn Computer cho AMR). Với kho hàng lớn (hàng trăm mét vuông), việc chọn resolution quá nhỏ có thể khiến số ô grid tăng vọt, làm chậm đáng kể việc tính costmap ở mỗi chu kỳ — cần cân bằng giữa nhu cầu chi tiết thực tế và giới hạn phần cứng đang có.
Ví dụ thực tế
# Lưu bản đồ đã dựng từ SLAM ra 2 file .pgm + .yaml
ros2 run nav2_map_server map_saver_cli -f my_map
# Đọc lại bản đồ đã lưu, publish lên topic /map
ros2 run nav2_map_server map_server --ros-args -p yaml_filename:=my_map.yaml
# Kiểm tra bản đồ đang publish đúng chưa
ros2 topic echo /map --once
Nội dung my_map.yaml điển hình:
image: my_map.pgm
resolution: 0.05
origin: [-10.0, -8.0, 0.0]
occupied_thresh: 0.65
free_thresh: 0.25
negate: 0
origin ở đây nghĩa là góc dưới-trái của ảnh .pgm tương ứng với toạ độ (-10.0, -8.0) trong hệ map — mọi phép chuyển đổi giữa chỉ số pixel và toạ độ thực tế robot dùng đều dựa trên 2 con số resolution và origin này.
Lỗi thường gặp
- Chọn resolution quá nhỏ cho không gian lớn — như tính ở mục Công thức, số ô grid tăng theo bình phương khi giảm resolution, dễ khiến costmap tính toán chậm không cần thiết trên phần cứng nhúng.
- Sửa tay file .pgm mà quên cập nhật ngưỡng occupied_thresh/free_thresh phù hợp — vẽ thêm tường ảo bằng màu đen tuyệt đối (0) nhưng ngưỡng occupied lại đặt cao hơn giá trị đó khiến ô vừa vẽ không được nhận diện là occupied.
- Nhầm lẫn giữa origin của bản đồ và origin của robot khi debug toạ độ — origin trong file
.yamllà góc bản đồ, không phải vị trí khởi động robot, hai khái niệm hoàn toàn khác nhau dễ gây nhầm lẫn khi mới học. - Không kiểm tra
/mapđã publish đúng trước khi nghi ngờ AMCL/Path Planning — nếu bản đồ chưa publish hoặc publish sai, mọi tầng phía sau (Localization, Path Planning) đều thất bại theo, đây nên là bước debug đầu tiên.
Kết luận
Occupancy Grid là định dạng bản đồ cố tình đơn giản — 3 trạng thái mỗi ô, lưu dưới dạng ảnh xám phổ thông — đánh đổi lấy khả năng tương thích rộng với mọi công cụ SLAM, path planning, và cả phần mềm chỉnh sửa ảnh thông thường. Chọn đúng resolution theo quy mô không gian và phần cứng sẵn có là quyết định thiết kế quan trọng, ảnh hưởng trực tiếp hiệu năng của mọi tầng phía sau. Bài tiếp theo trong chuyên mục đi vào Localization — cách robot tự định vị trên chính bản đồ vừa học ở đây.