Action: cách ROS2 xử lý tác vụ dài mà không chặn hệ thống
Atlasbot · 16/8/2026 · 11 phút đọc
Bài "Action trong ROS2 là gì?" đã giới thiệu mô hình goal → feedback → result. Điều thú vị là Action không phải một giao thức hoàn toàn mới — nó được xây dựng bằng cách ghép lại chính những cơ chế đã học: Service và Topic.
Khái niệm chính
Nhìn dưới lớp vỏ, một Action thực chất tạo ra:
- 2 Service —
send_goal(client gửi goal, server trả về chấp nhận hay từ chối) vàget_result(client hỏi kết quả cuối, server trả về khi đã xong) - 1 Topic feedback — server liên tục publish tiến độ lên đây, client subscribe để nhận
- 1 Topic status — server publish trạng thái hiện tại của goal (đang chờ, đang chạy, đã huỷ...)
Việc đóng gói sẵn 4 kênh giao tiếp này thành một API thống nhất (ActionClient/ActionServer) giúp người dùng không phải tự ghép thủ công — chỉ cần định nghĩa một file .action duy nhất.
Máy trạng thái của một goal
Mỗi goal gửi tới action server trải qua các trạng thái rõ ràng, do action server quản lý:
Goal gửi tới
↓
Server chấp nhận? ──Không──► REJECTED
│ Có
▼
EXECUTING ──────────────► CANCELING (nếu client gọi cancel)
│ │
▼ ▼
SUCCEEDED / ABORTED CANCELED
Tóm lại: Action không phải "công nghệ mới" — nó là cách ROS2 đóng gói một mẫu thiết kế (pattern) thường gặp — tác vụ dài, có tiến độ, có thể huỷ — từ đúng những viên gạch Topic và Service đã có sẵn, cộng thêm một máy trạng thái để quản lý vòng đời goal cho gọn gàng.
Nguyên lý hoạt động
File .action định nghĩa cả 3 phần goal/result/feedback trong một file, phân tách bằng ---:
# NavigateToPose.action
geometry_msgs/PoseStamped pose # Goal
---
std_msgs/Empty result # Result
---
geometry_msgs/PoseStamped current_pose # Feedback
float32 distance_remaining
Gửi goal và huỷ giữa chừng bằng code Python:
goal_handle = await action_client.send_goal_async(goal_msg, feedback_callback=on_feedback)
# ... một lúc sau, muốn huỷ giữa chừng
if muon_huy:
await goal_handle.cancel_goal_async() # chuyển goal sang trạng thái CANCELING
Trong thực tế, NavigateToPose chính là action mà Nav2 cung cấp để nhận lệnh "di chuyển robot tới một điểm" — mỗi khi đặt goal trên RViz, đằng sau đó là đúng luồng gửi goal → nhận feedback vị trí hiện tại liên tục → nhận result khi robot tới đích.
Kiến thức kỹ thuật
Thông số
Một số action chuẩn phổ biến sẵn có trong hệ sinh thái ROS2/Nav2 — biết trước tên và kiểu giúp không phải tự định nghĩa lại action đã có:
| Action | Package | Dùng cho |
|---|---|---|
NavigateToPose | nav2_msgs | Di chuyển robot tới 1 điểm đích |
FollowWaypoints | nav2_msgs | Di chuyển qua nhiều điểm theo thứ tự |
ComputePathToPose | nav2_msgs | Chỉ tính đường đi, không thực sự di chuyển |
FollowJointTrajectory | control_msgs | Điều khiển tay máy/cánh tay theo quỹ đạo khớp |
Protocol
Trạng thái goal publish trên topic status dùng đúng bộ mã số nguyên chuẩn hoá trong action_msgs/msg/GoalStatus: STATUS_ACCEPTED=1, STATUS_EXECUTING=2, STATUS_CANCELING=3, STATUS_SUCCEEDED=4, STATUS_CANCELED=5, STATUS_ABORTED=6 — mọi action trong hệ sinh thái ROS2 (dù package nào viết) đều dùng chung bộ mã này, giúp công cụ như ros2 action info hay RViz hiển thị trạng thái nhất quán bất kể action cụ thể là gì.
Ứng dụng thực tế
Cơ chế preemption (thay thế goal đang chạy bằng goal mới) là hành vi thường thấy khi vận hành AMR thực tế — nếu người vận hành đặt một điểm đích mới trên RViz trong lúc robot đang di chuyển tới điểm cũ, Nav2 tự động huỷ goal cũ (chuyển sang CANCELED) và bắt đầu goal mới ngay lập tức, không cần đợi robot hoàn thành hành trình cũ trước. Cách thiết kế action server có preemption hay không (chỉ nhận 1 goal tại 1 thời điểm, từ chối goal mới nếu đang bận, hay tự huỷ goal cũ để nhận goal mới) là quyết định kiến trúc quan trọng tuỳ vào tác vụ — với robot AMR, preemption thường là hành vi mong muốn để phản ứng nhanh với thay đổi kế hoạch.
Ví dụ thực tế
$ ros2 action info /navigate_to_pose -t
Output:
Action: /navigate_to_pose
Action clients: 1
/rviz_navigation_dialog
Action servers: 1
/bt_navigator
Action type: nav2_msgs/action/NavigateToPose
ros2 action info -t cho biết chính xác kiểu action, cùng danh sách client/server đang kết nối — công cụ chẩn đoán đầu tiên khi 1 goal gửi từ RViz không thấy robot phản ứng gì, giúp xác định ngay là do thiếu server (chưa khởi động Nav2) hay do vấn đề khác trong logic xử lý goal.
Lỗi thường gặp
- Giả định server luôn chấp nhận goal — không kiểm tra kết quả
send_goal_asynccó bịREJECTEDhay không trước khi tiếp tục chờ feedback/result — nếu server từ chối (VD: goal nằm ngoài bản đồ đã biết), code vẫn chờ vô ích một kết quả sẽ không bao giờ tới theo đúng luồng mong đợi. - Chỉ nhìn feedback tiến triển tốt mà quên kiểm tra result cuối cùng — feedback báo tiến độ 95% không đảm bảo goal sẽ
SUCCEEDED— robot hoàn toàn có thểABORTEDngay trước khi tới đích (VD: vật cản đột ngột xuất hiện) — luôn kiểm trastatustrong result, không suy luận từ feedback. - Action server không kiểm tra cờ huỷ định kỳ trong vòng lặp thực thi — nếu code phía server không gọi kiểm tra
goal_handle.is_cancel_requestedđều đặn trong lúc xử lý goal dài, yêu cầu huỷ từ client sẽ không có tác dụng ngay lập tức, có thể trễ đáng kể hoặc bị bỏ qua hoàn toàn. - Không giải phóng/theo dõi đúng
goal_handlecũ khi gửi goal mới — giữ tham chiếu tới goal handle đã hoàn tất/huỷ mà vẫn thao tác trên nó (VD: gọicancel_goal_asynctrên goal đãSUCCEEDED) có thể gây lỗi hoặc hành vi không xác định.
Kết luận
Action là sự kết hợp có chủ đích của Service (goal, get_result) và Topic (feedback, status), đóng gói thành API thống nhất cho mẫu tác vụ "dài, có tiến độ, có thể huỷ" rất phổ biến trong robot học — điển hình nhất là Nav2. Hiểu đúng máy trạng thái goal và luôn kiểm tra kết quả cuối cùng (không chỉ tin vào feedback) là kỹ năng cần thiết khi tích hợp với bất kỳ action server nào. Bài tiếp theo trong chuyên mục nói về QoS — chính sách quyết định độ tin cậy của cả Topic, Service, lẫn Action.