Robotics
Kết nối ROS 2 Humble giữa hai mạng LAN bằng Tailscale và Fast DDS Discovery Server

Kết nối ROS 2 Humble giữa hai mạng LAN bằng Tailscale và Fast DDS Discovery Server

Khi hai node ROS 2 nằm trong cùng một mạng LAN, việc truyền topic thường diễn ra khá tự nhiên. Một máy chạy publisher, máy khác chạy subscriber, hai bên tự tìm thấy nhau qua DDS discovery. Vấn đề bắt đầu xuất hiện khi robot ở một mạng LAN, còn laptop điều khiển hoặc máy xử lý nằm ở mạng khác.

Tailscale giúp hai thiết bị nhìn thấy nhau bằng IP riêng trong cùng một tailnet. Ví dụ, máy chạy robot có thể có địa chỉ 100.89.17.36, còn laptop ở nơi khác có một địa chỉ 100.x.x.x. Hai máy có thể ping nhau qua Tailscale, nhưng ROS 2 vẫn chưa chắc tự thấy node của nhau. Lý do là DDS discovery mặc định thường dựa nhiều vào multicast trong mạng cục bộ, trong khi kết nối qua Tailscale không hành xử như một LAN quảng bá multicast thông thường.

Fast DDS Discovery Server giải quyết đúng phần này. Thay vì để các node tự tìm nhau bằng multicast, ta đặt một server discovery cố định. Các node ROS 2 ở hai phía cùng khai báo server này. Khi cần tìm publisher, subscriber, service hoặc action, chúng trao đổi thông tin discovery qua địa chỉ server bằng unicast. Sau khi discovery xong, dữ liệu DDS thực tế có thể truyền qua đường Tailscale giữa các máy.

Trong bài này, cấu hình minh họa dùng:

  • ROS 2 Humble
  • Fast DDS qua rmw_fastrtps_cpp
  • Discovery Server tại 100.89.17.36:11811
  • ROS_DOMAIN_ID=10
  • Workspace ROS 2 tại ~/ros_ws

Luồng kết nối

Ta có ba lớp cần tách rõ.

Lớp đầu tiên là kết nối mạng. Tailscale tạo một đường IP riêng giữa hai thiết bị, dù chúng không nằm chung LAN vật lý. Nếu tầng này lỗi, ROS 2 không có cơ hội hoạt động. Vì vậy, trước khi nhìn vào topic, cần chắc chắn hai máy thấy nhau qua Tailscale.

Lớp thứ hai là DDS discovery. Đây là bước các ROS 2 node công bố “tôi có topic này”, “tôi muốn subscribe topic kia”, “tôi có service này”. Trong LAN, multicast thường giúp bước này diễn ra tự động. Qua hai mạng khác nhau, ta chuyển sang Fast DDS Discovery Server để discovery đi qua một điểm hẹn rõ ràng.

Lớp thứ ba là dữ liệu ROS 2 thật: /scan, /odom, /tf, /cmd_vel, /map, hoặc các topic custom. Discovery Server không nén dữ liệu và không làm topic nhẹ hơn. Nó chỉ giúp các endpoint tìm thấy nhau. Nếu topic quá nặng hoặc firewall chặn user data, discovery có thể đúng nhưng dữ liệu vẫn không chạy như mong muốn.

Điều kiện ban đầu

Hai máy cần cùng một nền cấu hình trước khi thử ROS 2 qua Tailscale:

  • Đã cài ROS 2 Humble.
  • Đã đăng nhập Tailscale và cùng có quyền truy cập trong tailnet.
  • Dùng Fast DDS RMW.
  • Dùng cùng ROS_DOMAIN_ID.
  • Nếu topic dùng custom message, cả hai máy đều phải có package chứa message đó.

Kiểm tra Tailscale:

tailscale status
tailscale ip -4

Từ máy client, kiểm tra tới máy sẽ chạy Discovery Server:

tailscale ping 100.89.17.36
ping -c 4 100.89.17.36

Nếu bước này chưa thành công, chưa nên debug ROS 2. Cần xử lý Tailscale trước: thiết bị có online không, tailnet policy có cho phép hai máy nói chuyện không, IP có đúng không.

Gói cần cài

Trên cả hai máy, cài Fast DDS RMW, demo node và công cụ fastdds:

sudo apt update
 
sudo apt install -y \
  ros-humble-rmw-fastrtps-cpp \
  ros-humble-demo-nodes-cpp \
  fastdds-tools

Source ROS 2:

source /opt/ros/humble/setup.bash

Nếu dùng workspace riêng:

source ~/ros_ws/install/setup.bash

Kiểm tra middleware và Fast DDS CLI:

ros2 doctor --report | grep -i middleware
fastdds --help

Ở giai đoạn này, mục tiêu chưa phải là chạy topic ngay. Mục tiêu chỉ là chắc chắn hai máy có cùng nền ROS 2 và cùng công cụ Fast DDS.

Discovery Server

Chọn một máy làm Discovery Server. Trong ví dụ này, máy đó có IP Tailscale:

100.89.17.36

Trên máy này, mở một terminal riêng và chạy:

source /opt/ros/humble/setup.bash
 
fastdds discovery \
  -i 0 \
  -l 100.89.17.36 \
  -p 11811

Các tham số chính:

Tham sốVai trò
-i 0ID của Discovery Server
-l 100.89.17.36IP Tailscale mà server lắng nghe
-p 11811Cổng UDP cho discovery

Nếu chạy đúng, terminal sẽ báo server đang hoạt động và lắng nghe ở UDPv4:[100.89.17.36]:11811. Giữ terminal này mở trong suốt quá trình test.

Kiểm tra cổng:

ss -lunp | grep 11811

Một lỗi hay gặp là bind nhầm IP. Tham số -l phải là IP Tailscale của chính máy đang chạy server, không phải IP của máy client.

Môi trường ROS 2

Trên mỗi terminal chạy ROS 2 node, cần khai báo cùng một bộ biến môi trường. Không dùng terminal đang chạy Discovery Server để chạy node; mở terminal mới.

Trên máy server:

source /opt/ros/humble/setup.bash
source ~/ros_ws/install/setup.bash
 
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DOMAIN_ID=10
export ROS_LOCALHOST_ONLY=0
export ROS_DISCOVERY_SERVER=100.89.17.36:11811
 
ros2 daemon stop

Trên máy client:

source /opt/ros/humble/setup.bash
source ~/ros_ws/install/setup.bash
 
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DOMAIN_ID=10
export ROS_LOCALHOST_ONLY=0
export ROS_DISCOVERY_SERVER=100.89.17.36:11811
 
ros2 daemon stop

Bốn biến này là lõi của cấu hình:

RMW_IMPLEMENTATION=rmw_fastrtps_cpp
ROS_DOMAIN_ID=10
ROS_LOCALHOST_ONLY=0
ROS_DISCOVERY_SERVER=100.89.17.36:11811

RMW_IMPLEMENTATION buộc ROS 2 dùng Fast DDS RMW. ROS_DOMAIN_ID tách graph ROS 2 theo domain; hai máy muốn thấy nhau phải cùng domain. ROS_LOCALHOST_ONLY=0 cho phép ROS 2 dùng giao tiếp ngoài localhost. ROS_DISCOVERY_SERVER chỉ node tới server discovery đã chạy qua Tailscale.

Sau khi đổi các biến liên quan tới discovery, nên dừng ROS daemon cũ. Nếu daemon được tạo từ cấu hình cũ, các lệnh CLI có thể cho kết quả gây nhiễu.

Talker và listener

Kiểm tra bằng demo node trước khi đưa topic robot thật vào. Trên máy server:

ros2 run demo_nodes_cpp talker

Kết quả sẽ có dạng:

Publishing: 'Hello World: 1'
Publishing: 'Hello World: 2'

Trên máy client:

ros2 run demo_nodes_cpp listener

Nếu listener nhận được:

I heard: [Hello World: 1]
I heard: [Hello World: 2]

thì ba tầng cơ bản đã chạy: Tailscale routing hoạt động, Discovery Server hoạt động, và dữ liệu DDS có thể đi giữa hai máy.

Nếu talker/listener chưa chạy, chưa nên kiểm tra /scan, /map hay /tf. Demo node là bài test nhỏ nhất để cô lập lỗi.

ROS 2 CLI

Fast DDS Discovery Server có thể làm các lệnh quan sát graph như ros2 topic list hoặc ros2 node list không luôn hiển thị giống multicast discovery trong LAN. Một node thường chỉ cần biết những endpoint liên quan tới nó, còn CLI introspection lại muốn nhìn toàn bộ graph.

Cách kiểm tra đơn giản là dùng --no-daemon:

ros2 topic list --no-daemon
ros2 node list --no-daemon
ros2 topic info /chatter --verbose --no-daemon

Một số lệnh cần thêm thời gian discovery:

ros2 node info /talker --no-daemon --spin-time 3

Với terminal dùng để giám sát graph, có thể bật Super Client:

export ROS_SUPER_CLIENT=TRUE
ros2 daemon stop

Sau đó thử:

ros2 topic list
ros2 node list

Không nhất thiết bật ROS_SUPER_CLIENT=TRUE cho mọi node vận hành. Nó phù hợp hơn với terminal quản trị vì nhận nhiều thông tin discovery hơn client thông thường.

Topic robot

Khi demo node đã chạy, mới chuyển sang topic robot thật. Với mỗi topic, cần kiểm tra ba thứ: topic có xuất hiện không, QoS có tương thích không, và dữ liệu có thật sự chảy không.

Với LaserScan:

ros2 topic info /scan --verbose
ros2 topic hz /scan
ros2 topic echo /scan --qos-reliability best_effort

Nhiều driver cảm biến phát với QoS BEST_EFFORT. Nếu subscriber yêu cầu RELIABLE, hai bên có thể không match.

Với map:

ros2 topic info /map --verbose
ros2 topic echo /map

Với odometry:

ros2 topic echo /odom

Với TF:

ros2 topic hz /tf
ros2 topic hz /tf_static
ros2 run tf2_tools view_frames

Với điều khiển vận tốc:

ros2 topic pub -r 5 /cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.1}, angular: {z: 0.0}}"

Không gửi /cmd_vel tới robot thật khi chưa có giới hạn vận tốc và cơ chế dừng khẩn cấp. Kết nối mạng chạy được không đồng nghĩa hệ điều khiển đã an toàn.

Custom message

Nếu publisher dùng custom message, máy nhận cũng phải có cùng định nghĩa message. Ví dụ topic dùng:

my_robot_msgs/msg/RobotState

Máy client cũng cần build hoặc cài package chứa interface đó:

cd ~/ros_ws
colcon build --symlink-install
source install/setup.bash

Kiểm tra:

ros2 interface show my_robot_msgs/msg/RobotState

Nếu thiếu interface, discovery có thể vẫn thấy topic nhưng subscriber hoặc ROS CLI không giải mã được dữ liệu. Đây là lỗi dễ nhầm với lỗi mạng, nhưng bản chất là hai workspace không cùng định nghĩa message.

Cấu hình dùng lại

Để không phải export thủ công ở mỗi terminal, tạo file:

nano ~/ros2_tailscale_env.sh

Nội dung:

#!/usr/bin/env bash
 
source /opt/ros/humble/setup.bash
 
if [ -f "$HOME/ros_ws/install/setup.bash" ]; then
    source "$HOME/ros_ws/install/setup.bash"
fi
 
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DOMAIN_ID=10
export ROS_LOCALHOST_ONLY=0
export ROS_DISCOVERY_SERVER=100.89.17.36:11811

Cấp quyền:

chmod +x ~/ros2_tailscale_env.sh

Mỗi lần mở terminal:

source ~/ros2_tailscale_env.sh
ros2 daemon stop

Nếu muốn tự động source trong .bashrc:

echo 'source "$HOME/ros2_tailscale_env.sh"' >> ~/.bashrc
source ~/.bashrc

Systemd cho Discovery Server

Nếu Discovery Server cần chạy ổn định sau mỗi lần khởi động máy, dùng systemd trên máy 100.89.17.36.

Kiểm tra đường dẫn fastdds:

which fastdds

Tạo service:

sudo nano /etc/systemd/system/ros2-discovery-server.service

Nội dung:

[Unit]
Description=ROS 2 Fast DDS Discovery Server over Tailscale
Wants=network-online.target tailscaled.service
After=network-online.target tailscaled.service
 
[Service]
Type=simple
User=dhcn-1
WorkingDirectory=/home/dhcn-1
 
ExecStartPre=/bin/bash -lc 'until ip -4 addr show tailscale0 | grep -q "100.89.17.36"; do sleep 1; done'
ExecStart=/bin/bash -lc 'source /opt/ros/humble/setup.bash && exec fastdds discovery -i 0 -l 100.89.17.36 -p 11811'
 
Restart=on-failure
RestartSec=3
 
[Install]
WantedBy=multi-user.target

Nếu username không phải dhcn-1, thay User và WorkingDirectory theo tài khoản thực tế.

Kích hoạt service:

sudo systemctl daemon-reload
sudo systemctl enable --now ros2-discovery-server.service

Kiểm tra:

systemctl status ros2-discovery-server.service
journalctl -u ros2-discovery-server.service -f
ss -lunp | grep 11811

Khởi động lại khi cần:

sudo systemctl restart ros2-discovery-server.service

Cấu hình cốt lõi

Trên máy chạy Discovery Server:

source /opt/ros/humble/setup.bash
 
fastdds discovery \
  -i 0 \
  -l 100.89.17.36 \
  -p 11811

Trên mọi terminal chạy node ROS 2:

source /opt/ros/humble/setup.bash
source ~/ros_ws/install/setup.bash
 
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export ROS_DOMAIN_ID=10
export ROS_LOCALHOST_ONLY=0
export ROS_DISCOVERY_SERVER=100.89.17.36:11811
 
ros2 daemon stop

Test nhỏ nhất vẫn là:

# Máy server
ros2 run demo_nodes_cpp talker
 
# Máy client
ros2 run demo_nodes_cpp listener

Khi test này chạy ổn, các vấn đề còn lại thường nằm ở QoS, custom message, firewall, băng thông hoặc cấu hình riêng của topic robot.

Bình luận & Cảm xúc