You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ROS2多机械臂系统Zenoh通信权限与路由配置技术问询

ROS2+Zenoh多机械臂通信控制问题

系统背景

我们正在开发一款搭载多台同款机械臂的ROS2机器人,机器人本体及每台机械臂均配备独立控制PC,在Docker环境中运行ROS2,所有PC通过固定IP互联。

通信需求

  • 大部分topic无需跨PC传输
  • 机器人仅需向所有机械臂统一发布少量特定topic
  • 机械臂仅需向机器人发布少量特定topic
  • 机械臂之间严禁任何topic通信

当前尝试方案

此前采用FastDDS实现通信逻辑,因可靠性问题计划切换为Zenoh,当前方案:

  • 每台控制PC运行独立Zenoh客户端路由器,统一连接至一台中央Zenoh路由器
  • 中央路由器配置过滤器仅允许/relay/*类topic通行
  • 机器人用/robot命名空间做内部通信,通过/relay命名空间与机械臂通信
  • 所有机械臂用/arm命名空间做内部通信,通过/relay命名空间与机器人通信

当前问题

该方案可实现机器人与机械臂间的通信,但机械臂发往机器人的通信可被其他机械臂发现,带来不必要的开销与混淆。

核心疑问

  1. 采用过滤路由器是否是限制通信的合理方案?
  2. 是否可将特定命名空间/topic仅发布至指定IP或客户端路由器?或仅允许特定IP地址间的通信?

当前使用的Zenoh配置文件

{
  /// Router mode configuration
  mode: "router",
  listen: {
    endpoints: [
      "tcp/[::]:7448"
    ],
    timeout_ms: 0,
    exit_on_failure: true,
    retry: {
      period_init_ms: 1000,
      period_max_ms: 4000,
      period_increase_factor: 2,
    },
  },
  /// Connect to the specified remote routers
  connect: {
    timeout_ms: {
      router: -1,
      peer: -1,
      client: 0
    },
    endpoints: [
      // Router runs on robot PC, so IP 127.0.0.1 refers to robot PC
      "tcp/127.0.0.1:7447",
      // Robot arms IP
      "tcp/192.168.2.100:7447",
      "tcp/192.168.3.100:7447",
      "tcp/192.168.4.100:7447",
      "tcp/192.168.5.100:7447"
    ],
    exit_on_failure: {
      router: false,
      peer: false,
      client: true
    },
    retry: {
      period_init_ms: 1000,
      period_max_ms: 4000,
      period_increase_factor: 1,
    },
  },
  /// Configure access control to only allow relay traffic
  access_control: {
    enabled: true,
    default_permission: "deny",
    rules: [
      {
        id: "allow_only_relay",
        permission: "allow",
        messages: [
          "put",
          "delete",
          "declare_subscriber",
          "query",
          "reply",
          "declare_queryable",
          "liveliness_token",
          "liveliness_query",
          "declare_liveliness_subscriber"
        ],
        flows: [
          "ingress",
          "egress"
        ],
        key_exprs: [
          // Make listening to relay topics possible
          "*/relay/**",
          // Make relay topics discoverable
          "@ros2_lv/**/%relay/**"
        ],
      }
    ],
    /// list of subjects:
    subjects: [
      {
        // Interface identifier
        id: "all_interfaces",
      },
    ],
    /// apply rule to subject in the policies list
    policies: [
      {
        rules: [
          "allow_only_relay"
        ],
        subjects: [
          "all_interfaces"
        ],
      },
    ],
  },
  /// Standard router configuration from defaults
  scouting: {
    timeout: 3000,
    delay: 500,
    multicast: {
      enabled: false,
      address: "224.0.0.224:7446",
      interface: "auto",
      ttl: 1,
      autoconnect: {
        router: [],
        peer: [
          "router",
          "peer"
        ],
        client: [
          "router"
        ]
      },
      autoconnect_strategy: {
        router: {
          to_router: "always",
          to_peer: "always"
        }
      },
      listen: true,
    },
    gossip: {
      enabled: true,
      multihop: false,
      target: {
        router: [
          "router",
          "peer"
        ],
        peer: [
          "router"
        ]
      },
      autoconnect: {
        router: [],
        peer: [
          "router",
          "peer"
        ]
      },
      autoconnect_strategy: {
        router: {
          to_router: "always",
          to_peer: "always"
        }
      },
    },
  },
  timestamping: {
    enabled: {
      router: true,
      peer: true,
      client: true
    },
    drop_future_timestamp: false,
  },
  queries_default_timeout: 60000,
  routing: {
    router: {
      peers_failover_brokering: false,
    },
    peer: {
      mode: "peer_to_peer",
    },
    interests: {
      timeout: 10000,
    },
  },
  transport: {
    unicast: {
      open_timeout: 60000,
      accept_timeout: 60000,
      accept_pending: 10000,
      max_sessions: 10000,
      max_links: 1,
      lowlatency: false,
      qos: {
        enabled: true,
      },
      compression: {
        enabled: false,
      },
    },
    multicast: {
      join_interval: 2500,
      max_sessions: 1000,
      qos: {
        enabled: false,
      },
      compression: {
        enabled: false,
      },
    },
    link: {
      tx: {
        sequence_number_resolution: "32bit",
        lease: 60000,
        keep_alive: 2,
      }
    }
  }
}

解答

问题1:过滤路由器是否是限制通信的合理方案?

是,但当前配置粒度不足。现有规则仅允许/relay/**相关topic通行,未区分通信的来源与目标,导致所有接入中央路由器的节点都能看到/relay下的全部数据,包括机械臂之间的交叉可见。

这种中央路由器管控流量的核心思路是正确的——避免节点间直接通信,但需要细化访问控制规则,结合来源身份或IP限制流量流向。

问题2:能否将特定命名空间/topic仅发布至指定IP或客户端路由器?

可以,通过Zenoh的访问控制规则扩展和路由策略配置实现,具体有两种方向:

方向1:基于IP的访问控制细化

修改中央路由器的access_control配置,为机器人和每个机械臂的IP创建独立subject,再针对不同subject设置差异化规则:

  1. 为机器人PC的IP(如127.0.0.1)创建subject,允许它向所有机械臂IP发送/relay/**消息,同时接收所有机械臂发往/relay/**的消息
  2. 为每个机械臂的IP创建独立subject,仅允许它们向机器人IP发送/relay/**消息,且只能接收来自机器人IP的/relay/**消息,禁止接收其他机械臂的消息

示例配置片段:

"subjects": [
  {
    "id": "robot_pc",
    "ip": "127.0.0.1"
  },
  {
    "id": "arm_1",
    "ip": "192.168.2.100"
  },
  {
    "id": "arm_2",
    "ip": "192.168.3.100"
  }
],
"rules": [
  // 机器人可向所有机械臂发消息,也能接收所有机械臂的消息
  {
    "id": "robot_relay_full",
    "permission": "allow",
    "messages": ["put", "delete", "declare_subscriber", ...],
    "flows": ["ingress", "egress"],
    "key_exprs": ["*/relay/**", "@ros2_lv/**/%relay/**"],
    "subjects": ["robot_pc"]
  },
  // 机械臂只能向机器人发消息
  {
    "id": "arm_relay_to_robot",
    "permission": "allow",
    "messages": ["put", "delete", ...],
    "flows": ["egress"],
    "key_exprs": ["*/relay/**", "@ros2_lv/**/%relay/**"],
    "subjects": ["arm_1", "arm_2"],
    "targets": ["robot_pc"]
  },
  // 机械臂只能接收机器人的消息
  {
    "id": "arm_relay_from_robot",
    "permission": "allow",
    "messages": ["declare_subscriber", ...],
    "flows": ["ingress"],
    "key_exprs": ["*/relay/**", "@ros2_lv/**/%relay/**"],
    "subjects": ["arm_1", "arm_2"],
    "sources": ["robot_pc"]
  }
],
"policies": [
  {
    "rules": ["robot_relay_full", "arm_relay_to_robot", "arm_relay_from_robot"],
    "subjects": ["robot_pc", "arm_1", "arm_2"]
  }
]

方向2:基于Zenoh路由的点对点定向转发

若不想依赖IP控制,可在中央路由器的routing配置中,设置/relay主题的定向转发规则:

  • 所有机械臂发往/relay的消息,仅转发给机器人的路由器节点
  • 机器人发往/relay的消息,转发给所有机械臂的路由器节点
  • 禁止机械臂节点之间的任何消息转发

这种方式需在中央路由器中为每个节点设置明确路由策略,确保流量仅在机器人与对应机械臂间流动,机械臂之间完全隔离。

额外优化建议

  • 关闭Zenoh的gossip功能(当前配置gossip.enabled: true),避免节点间自动发现和拓扑信息传播,减少不必要开销
  • 为每个机械臂的/relay主题添加独立子命名空间(如/relay/arm1/、/relay/arm2/),结合访问控制规则进一步细化流量隔离

内容的提问来源于stack exchange,提问作者wouterio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 11:29:51