你的工作站能通过隧道连上 ROS 1 的 master,话题列表却依然是空的。这种情形很常见,因为 master 注册和话题传输是两场不同的对话,只有第一场经过 master。下面的清单走的是第二场:发布者通告的端点、订阅者必须能到达的地址,以及让这一对能够通话的放行规则。这里的一切只针对旧版 ROS 1,它的 Noetic 支持窗口已于 2025 年五月结束。

第 1 步:证明 master 连接不等于话题连接

先把能用的和不能用的分开。rostopic list 成功只证明你的 shell 能到达 master 的 XMLRPC 端口、master 知道话题的存在;它并不能说明订阅者能否到达发布者。下面三条命令让这个区别显形,而且全部是只读操作。

echo "$ROS_MASTER_URI"
rostopic list
rostopic info /chatter

rostopic info 的输出会给出发布者的节点 URI,也就是发布者主机上的一个 XMLRPC 地址。订阅者下一步要调用的就是那个地址,所以它必须在订阅者运行的地方都能到达。如果它指向只在机器人自身局域网里存在的接口,master 查询会成功,数据却永远不会到达。

第 2 步:从节点本身读取通告的端点

当 ROS_IP 或 ROS_HOSTNAME 其中之一被设置时,ROS 1 用它来决定通告的主机身份;两者都没设时,退回主机自身的名字解析。要检查真正被启动的那个进程的环境,因为 systemd 单元、容器或第二个终端可能带着与测试所用 shell 不同的值。

echo "$ROS_IP" "$ROS_HOSTNAME"
rosnode info /talker
getent hosts robot-host

主机名通告只有在对端都能把该名字解析成预期的可达地址时才成立。如果这个名字只在机器人自己的网络内可解析,隧道另一侧的工作站就无法使用它;而一个不下发 DNS 后缀的 VPN 会让这种错配更糟。在拓扑已经路由的情况下,把 ROS_IP 设成隧道地址是更小的改动。无论选哪种,都要为两端记录下来,因为对身份认知不一致的发布者和订阅者会完成协商,然后连不上。

如果通告的 URI 使用了没有任何对端能路由到的地址,就停在这里。再多的防火墙操作也修不好一个解析到错误接口的名字。

第 3 步:让通告的地址可解析、可路由

拿到 URI 之后,要从订阅者主机而不是从机器人去测可达性。TCPROS 端口是在协商过程中才选定的,所以早期有用的测试是 XMLRPC 端口,后期有用的测试是已建立的套接字。只在一个方向上存在的路由是路由型 VPN 的常见故障,回程与去程同样重要。

ip route get 10.70.0.2
nc -vz 10.70.0.2 33911
ss -tnp dst 10.70.0.2

路由型 TUN 接口承载这些 IP 对话,又不必扩展机器人的以太网段,这通常正是远程操作者想要的。如果协议栈里某样东西依赖的是广播或 multicast,那条需求必须单独评估;为了让一个工具满意而把隧道改成 TAP,会为所有参与者扩大网络。

如果路由或回程缺失,就停在这里。能应答自己的主机、却从工作站无法到达的发布者,是路由问题,不是 ROS 问题。

第 4 步:放行对端对话并观察一个话题

只打开协商出来的对话需要的端口,并把每条规则限定在已声明的参与者上。master 的监听器不是话题负载的中继,所以只放行它,发布者的端点仍然是关闭的。把 ROS 的监听器留在私有 VPN 边界内,而不是暴露到公网。

rostopic hz /chatter
rostopic echo -n1 /chatter
rosnode ping /talker

从真实发布者到真实订阅者观察一个无害话题,同时确认通告的端点和回程路径。一条消息就证明路径通了;稳定速率则证明它一直通着。把执行器控制与安全检查排除在这次纯网络测试之外,因为话题能用并不等于机器人能用。记录你观察到的 ROS 版本和端点对,好让下一个人能区分拓扑变化和功能回退。

当通告的 URI 从订阅者可达、协商端口只对该对端开放、一个已声明话题在流动,并且两台主机的环境值都已写下,清单才算完成。旧版 ROS 1 不会在这个方向上再修补,所以记录才是人换了以后仍然起作用的部分。

相关文章