DDS là gì? Nền tảng giao tiếp phía sau ROS2
Atlasbot · 16/8/2026 · 11 phút đọc
Những bài trước đã nhắc nhiều lần: ROS2 không cần roscore, hỗ trợ QoS linh hoạt, các node tự tìm thấy nhau. Toàn bộ những khả năng này không phải ROS2 tự phát minh — chúng đến từ DDS (Data Distribution Service), một chuẩn middleware pub/sub công nghiệp đã tồn tại từ trước ROS2 rất lâu, dùng trong hàng không, quốc phòng, tài chính.
Khái niệm chính
Thay vì tự viết một giao thức mạng riêng (như ROS1 từng làm với TCPROS), nhóm phát triển ROS2 chọn xây dựng trên nền DDS có sẵn — thừa hưởng luôn hai đặc tính cốt lõi:
- Discovery phân tán — mỗi tiến trình DDS tự quảng bá sự hiện diện của mình lên mạng (qua multicast), các bên tự tìm thấy nhau mà không cần một "danh bạ trung tâm" nào — chính là lý do ROS2 không cần
roscore - QoS có thể cấu hình — DDS định nghĩa sẵn hàng chục chính sách QoS (Reliability, Durability, History...), ROS2 chỉ expose lại một tập con dễ dùng qua API của mình (xem bài QoS)
RMW — lớp trừu tượng cho phép đổi DDS
ROS2 không khoá cứng vào một hãng DDS cụ thể. Lớp RMW (ROS Middleware interface) đứng giữa thư viện client (rclcpp/rclpy) và DDS thực tế bên dưới, cho phép cắm thay đổi giữa nhiều triển khai khác nhau (Fast DDS, Cyclone DDS, Connext...) mà code ứng dụng không cần sửa gì — chỉ cần đổi biến môi trường RMW_IMPLEMENTATION.
Tóm lại: ROS2 = thư viện client (
rclpy/rclcpp) + RMW (lớp trừu tượng) + một triển khai DDS cụ thể chạy bên dưới. Hiểu DDS giải thích được vì sao ROS2 không cần trạm trung tâm, và vì sao QoS lại linh hoạt tới vậy — cả hai đều là đặc tính vốn có của DDS, không phải ROS2 tự chế.
Nguyên lý hoạt động
Code ứng dụng (node của bạn)
│
rclpy / rclcpp
│
RMW ← lớp trừu tượng, có thể đổi triển khai
│
┌──────────┼──────────┐
Fast DDS Cyclone DDS Connext DDS ← chọn 1 trong nhiều triển khai
Kiểm tra và đổi triển khai DDS đang dùng:
echo $RMW_IMPLEMENTATION # xem đang dùng triển khai nào (mặc định thường là Fast DDS)
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # đổi sang Cyclone DDS
Một khái niệm thực tế hay gặp: ROS_DOMAIN_ID — số hiệu "kênh" cô lập các mạng ROS2 khác nhau đang chạy chung một mạng vật lý (ví dụ hai robot trong cùng phòng thí nghiệm, mỗi robot một domain ID riêng để không "nhìn thấy" node của nhau, tránh xung đột hoặc tự động tương tác không mong muốn) — đây trực tiếp là một cơ chế của DDS, ROS2 chỉ expose lại qua biến môi trường.
Kiến thức kỹ thuật
Công thức
ROS_DOMAIN_ID không chỉ là một con số trừu tượng — chuẩn RTPS (giao thức wire-level của DDS) quy đổi nó thành cổng UDP thực tế dùng cho discovery, theo công thức cố định:
Cổng discovery cơ bản = 7400 + 250 × domain_id
VD: ROS_DOMAIN_ID = 0 (mặc định)
Cổng = 7400 + 250 × 0 = 7400
VD: ROS_DOMAIN_ID = 5
Cổng = 7400 + 250 × 5 = 8650
Đây là lý do 2 domain ID khác nhau thực sự dùng dải cổng mạng khác nhau hoàn toàn — không chỉ là quy ước phần mềm, mà là cô lập thực sự ở tầng mạng, giải thích tại sao 2 robot khác domain ID không bao giờ vô tình "thấy" nhau dù cùng chung 1 mạng WiFi.
Thông số
| Thông số | Giá trị |
|---|---|
Dải ROS_DOMAIN_ID hợp lệ thực tế | 0 – 101 (một số hệ thống hỗ trợ tới 232) |
| Giá trị mặc định nếu không đặt | 0 |
| DDS mặc định của ROS2 (Humble/Jazzy) | Fast DDS (eProsima) |
| DDS nhẹ hơn, phổ biến cho thiết bị nhúng tài nguyên hạn chế | Cyclone DDS |
Protocol
Giao thức thực sự chạy trên dây mạng mà mọi triển khai DDS (Fast DDS, Cyclone DDS, Connext...) đều phải tuân theo là RTPS (Real-Time Publish-Subscribe Protocol) — một chuẩn OMG riêng biệt với DDS API, quy định chính xác định dạng byte gửi qua UDP để discovery và truyền dữ liệu. Nhờ cùng tuân theo RTPS, về lý thuyết node dùng Fast DDS vẫn có thể giao tiếp với node dùng Cyclone DDS — dù trong thực tế một số phần mở rộng riêng của từng hãng có thể gây khác biệt nhỏ, nên thực hành tốt nhất vẫn là đồng bộ cùng 1 triển khai DDS trên toàn hệ thống.
Ứng dụng thực tế
Trên Jetson hoặc các máy tính nhúng tài nguyên hạn chế trong AMR, nhiều đội kỹ thuật chọn chuyển từ Fast DDS (mặc định) sang Cyclone DDS vì footprint bộ nhớ/CPU nhẹ hơn khi số lượng node và topic tăng lên — chỉ cần đổi biến môi trường RMW_IMPLEMENTATION, không cần sửa 1 dòng code ứng dụng nào, minh chứng trực tiếp cho giá trị của lớp trừu tượng RMW đã nói ở trên. Khi vận hành nhiều robot AMR trong cùng một nhà xưởng, gán ROS_DOMAIN_ID riêng biệt cho từng robot (VD: robot 1 dùng domain 1, robot 2 dùng domain 2) là bước thiết lập mạng bắt buộc để tránh các robot vô tình nhận lệnh điều khiển của nhau.
Ví dụ thực tế
$ export ROS_DOMAIN_ID=5
$ ros2 daemon stop && ros2 daemon start # khởi động lại daemon để áp dụng domain mới
$ ros2 topic list
Output:
/parameter_events
/rosout
(chỉ thấy các topic của node cùng domain 5, không thấy node ở domain khác dù cùng mạng)
Nếu đổi ROS_DOMAIN_ID mà vẫn thấy node ở "domain khác" xuất hiện trong ros2 topic list, kiểm tra lại xem tất cả terminal/node liên quan đã thực sự được source đúng biến môi trường mới hay chưa — quên export ở dù chỉ 1 terminal là nguyên nhân phổ biến của hiện tượng "domain ID không cô lập như mong đợi".
Lỗi thường gặp
- Domain ID trùng nhau giữa nhiều robot trên cùng mạng — như đã nói ở phần Ứng dụng thực tế, gây node của robot khác nhau vô tình "thấy" và tương tác nhầm với nhau — luôn kiểm tra
echo $ROS_DOMAIN_IDkhớp đúng kế hoạch trước khi vận hành nhiều robot. - Đổi
RMW_IMPLEMENTATIONkhông đồng bộ trên toàn hệ thống — một máy dùng Fast DDS, máy khác dùng Cyclone DDS có thể gặp vấn đề tương thích tinh vi dù cả hai đều tuân theo RTPS — nên thống nhất 1 triển khai DDS cho toàn bộ hệ thống robot. - Firewall chặn multicast/UDP khiến discovery không hoạt động — cơ chế discovery mặc định của DDS dựa trên multicast UDP, một số mạng doanh nghiệp/router chặn loại traffic này — biểu hiện thành các node không bao giờ "thấy" nhau dù cùng domain ID và cùng mạng vật lý.
- Quá nhiều node/participant vượt giới hạn tài nguyên trên thiết bị nhúng yếu — mỗi node DDS chiếm dụng tài nguyên hệ thống (file descriptor, bộ nhớ) nhất định, chạy quá nhiều node nhỏ trên một board nhúng RAM hạn chế có thể gây lỗi khởi tạo DDS — cân nhắc dùng Composition (node đa thành phần, xem chuyên mục ROS2 nâng cao) để gộp nhiều thành phần vào ít tiến trình hơn.
Kết luận
DDS là nền tảng thực sự đứng sau hầu hết đặc tính "thần kỳ" của ROS2 — discovery phân tán không cần trạm trung tâm, QoS linh hoạt, và khả năng đổi triển khai middleware mà không sửa code ứng dụng nhờ lớp RMW. Hiểu công thức cổng UDP theo domain ID và vai trò của RTPS giúp debug chính xác các vấn đề mạng ở tầng sâu nhất khi các cách khắc phục thông thường không hiệu quả. Bài tiếp theo trong chuyên mục nói về TF/TF2 — hệ thống quản lý các hệ toạ độ trong robot, một trong những package dùng DDS/Topic nhiều nhất trong toàn bộ hệ sinh thái ROS2.