Node trong ROS2 là gì?
Atlasbot · 16/8/2026 · 10 phút đọc
Nếu package là "đơn vị đóng gói mã nguồn" thì node là "đơn vị đang chạy" — một tiến trình thực thi cụ thể, làm đúng một nhiệm vụ trong toàn hệ thống robot: đọc dữ liệu từ một cảm biến, chạy thuật toán SLAM, hay gửi lệnh xuống động cơ.
Khái niệm chính
Một node là một chương trình (thường viết bằng Python hoặc C++) khởi tạo kết nối với ROS2, đăng ký các publisher/subscriber/service mà nó cần, rồi chạy vòng lặp chờ sự kiện (spin) để xử lý dữ liệu đến. Triết lý thiết kế ROS2 khuyến khích mỗi node chỉ làm một việc (Unix philosophy: "do one thing well") — thay vì viết một chương trình khổng lồ làm tất cả, tách thành nhiều node nhỏ, dễ debug, dễ thay thế độc lập, và có thể tái sử dụng ở dự án khác.
Một robot AMR thực tế có thể chạy đồng thời: node driver LiDAR, node driver IMU, node tính odometry, node SLAM, node Nav2 (thực ra tự nó cũng là nhiều node con), node điều khiển động cơ — mỗi node là một tiến trình riêng biệt, có thể restart node này mà không ảnh hưởng node khác.
Tóm lại: Node không "chứa" ROS2 — nó chỉ dùng thư viện client ROS2 (
rclpy/rclcpp) để tham gia vào ROS graph, giống như một chương trình bình thường import một thư viện để dùng.
Nguyên lý hoạt động
Một node Python tối thiểu — chỉ khởi tạo và "sống" cho tới khi bị dừng (Ctrl+C):
import rclpy
from rclpy.node import Node
class MinimalNode(Node):
def __init__(self):
super().__init__('minimal_node') # tên node hiển thị trong ROS graph
self.get_logger().info('Node đã khởi động')
def main():
rclpy.init()
node = MinimalNode()
rclpy.spin(node) # vòng lặp chính — chờ và xử lý sự kiện (message đến, timer...)
rclpy.shutdown()
if __name__ == '__main__':
main()
rclpy.spin(node) là dòng quan trọng nhất — nó giữ tiến trình sống và liên tục kiểm tra có sự kiện nào cần xử lý không (message mới trên topic đã subscribe, timer tới hạn, request service đến...). Không gọi spin() thì node khởi tạo xong sẽ thoát ngay lập tức, không kịp nhận bất kỳ dữ liệu nào.
Kiến thức kỹ thuật
Thông số
Quy tắc đặt tên node và namespace hợp lệ trong ROS2:
| Quy tắc | Yêu cầu |
|---|---|
| Ký tự cho phép | Chữ, số, dấu gạch dưới — không bắt đầu bằng số |
| Namespace | Tiền tố phân cấp, VD: /robot1/lidar_node — dùng dấu / để phân tầng |
| Đổi tên lúc chạy (remap) | ros2 run pkg node_exe --ros-args -r __node:=ten_moi — không cần sửa code |
Namespace là công cụ quan trọng để chạy nhiều bản sao của cùng 1 loại node (VD: cùng code driver LiDAR) mà không xung đột tên — mỗi bản sao chỉ cần khác namespace.
Ứng dụng thực tế
Trong hệ thống quản lý nhiều robot AMR (fleet), cùng một package driver/node được deploy lên nhiều robot, nhưng mỗi robot chạy trong namespace riêng (VD: /robot_01/, /robot_02/) — cùng 1 dòng code self.get_logger().info(...) nhưng khi xem trên trạm giám sát trung tâm, dữ liệu và log của từng robot tách biệt hoàn toàn nhờ namespace, không cần viết code phân biệt robot nào đang chạy ngay trong logic node.
Ví dụ thực tế
$ ros2 node list
Output:
/lidar_driver
/imu_driver
/odometry_publisher
/nav2_controller_server
$ ros2 node info /lidar_driver
Output:
/lidar_driver
Subscribers:
Publishers:
/scan: sensor_msgs/msg/LaserScan
/diagnostics: diagnostic_msgs/msg/DiagnosticArray
Service Servers:
/lidar_driver/get_parameters: rcl_interfaces/srv/GetParameters
Service Clients:
Action Servers:
Action Clients:
ros2 node info là công cụ chẩn đoán đầu tiên khi nghi ngờ 1 node không hoạt động đúng — cho biết chính xác node đang publish/subscribe topic nào, có service nào, giúp xác định nhanh vấn đề nằm ở node này hay ở node khác đang chờ nhận dữ liệu từ nó.
Lỗi thường gặp
- Quên gọi
rclpy.spin(node)— như đã nói ở phần Nguyên lý hoạt động, node khởi tạo xong thoát ngay lập tức, không kịp xử lý bất kỳ message/timer nào — nếu node "biến mất" ngay sau khi chạy, kiểm tra dòng này trước tiên. - Trùng tên node khi chạy nhiều instance cùng loại — 2 node cùng tên trên cùng hệ thống gây nhầm lẫn khi debug qua
ros2 node info(không rõ đang xem instance nào) — luôn dùng namespace hoặc remap tên khi chạy nhiều bản sao. - Không gọi
rclpy.shutdown()khi kết thúc, đặc biệt trong test/script ngắn hạn — có thể gây rò rỉ tài nguyên (resource leak) nếu script khởi tạo/huỷ node nhiều lần trong cùng 1 tiến trình. - Code chặn (blocking) bên trong callback — mặc định
rclpy.spin()chạy đơn luồng (single-threaded executor), một callback bị block (VD:time.sleep()dài hoặc chờ I/O) sẽ làm toàn bộ node "đứng hình", không xử lý được message/timer khác cho tới khi callback đó xong — cần dùng multi-threading hoặc callback group (xem bài riêng trong chuyên mục ROS2 nâng cao) nếu có tác vụ chạy lâu.
Kết luận
Node là đơn vị thực thi cơ bản của mọi hệ thống ROS2 — nắm vững vòng đời khởi tạo/spin/shutdown và cách đặt tên/namespace đúng cách là nền tảng trước khi viết bất kỳ publisher/subscriber nào. Bài tiếp theo trong chuyên mục nói về Topic — kênh giao tiếp phổ biến nhất mà các node dùng để trao đổi dữ liệu với nhau.