返回专辑
·Johan·3 分钟阅读

命名空间与 Remap:可复制的图,而不是全局话题平原

节点内相对名,launch 推前缀;绝对名白名单;remap 是适配器不是架构。

命名空间与 Remap:可复制的图,而不是全局话题平原

1. 第二台机器人到来时,平原崩溃

第一台车代码里全是 /cmd_vel/scan——单实例能跑。加第二台实例后,两台订阅同一个 /cmd_vel,遥控信号随机喂给某一台;或 launch 里临时 remap 狂欢,文档没有「裸名→全名」表,现场每人一套口头约定。Namespace 与 remapping 是构图工具:决定图能否复制、能否多实例、能否与第三方包对接。设计时把实例前缀(/robot1)当一等公民,不是上线前夕补丁。

2. 规则

节点内用相对名 cmd_vel,由 launch 推命名空间:

python
GroupAction([
    PushRosNamespace('robot1'),
    Node(package='teleop', executable='joy_node',
         remappings=[('cmd_vel', 'cmd_vel')]),  # → /robot1/cmd_vel
])

绝对名以 / 开头,刺穿当前 namespace,落到图根——只留给真全局资源。TF 策略里 /tf/tf_static 是否全局必须团队书面约定;其余绝对名默认禁止。私有 topic 用相对名即可表达「仅本节点关心」,不必为了「显得正式」加绝对路径。

调试必用:

bash
ros2 node info /robot1/joy_node
ros2 topic list | grep cmd_vel

看解析后的 fully qualified name,而不是猜 launch 字符串。

3. Remap 是适配器,不是架构

第三方驱动硬编码 publish scan(相对)还好;若硬编码 /scan(绝对),只能用 remapping 或 fork 适配:

python
Node(package='vendor_lidar', executable='driver',
     remappings=[('/scan', 'scan')])  # 绝对→相对,再被 namespace 推前缀

超过三处 remap 指向同一逻辑话题,说明接口未对齐——应回到驱动包装节点统一出口,而不是 launch 里再加第四行。Remap 适合桥接 legacy,不适合表达系统架构。__node:=__ns:= 替换规则在 Humble 后更严格——旧教程里的匿名 remap 在新版可能 silently 失效,要以 ros2 node info 为准。

4. 多实例与 composition

多机启动两份相同 launch,各自 PushRosNamespace;CI 门禁跑「双实例串话测试」:robot1 发 cmd,robot2 的 odom 不应动。容器内 component 的 namespace 在 LoadNode 时确定:

bash
ros2 component load /Container \
  my_pkg LaserDriver -n robot1/lidar

热加载缺省 namespace 的组件会污染根图——代码 review 必查 create_publisher 是否用相对名。参数也受 namespace 影响:ros2 param set /robot1/lidar frame_id 与根下 /lidar 不是同一节点——ros2 param list 按全名操作,调试时别漏前缀。

5. 全局名白名单与静态扫描

允许全局的话题/service 列白名单(通常仅 TF 相关 + 少数 fleet 广播)。CI 用脚本扫源码与 launch 里的 '/' 字符串,新增绝对名 MR 必须解释。第三方不得不用时,集中在一个 adapter.launch.py 并注释原因——比散落十个 launch 可审计。

6. 与 DDS 域、发现策略

Namespace 是 ROS 图逻辑;DDS ROS_DOMAIN_ID 是传输隔离。多机器人同域不同 namespace 仍可能带宽互扰;仿真与真机同域误连是另一类灾难。文档写清:domain 隔离机群,namespace 隔离实例

ROS_LOCALHOST_ONLY=1 适合单机多实例调试,但不能替代 namespace——它只限本机 loopback,不解决同名 topic 冲突。fleet 里每台车固定 (domain_id, namespace) 二元组写进资产台账,现场扫码贴号与 launch 参数一致,减少手工改域。

7. 文档与测试验收

  • README 有「裸名 → 全名」表(teleop、nav、perception 各一行示例)。
  • 双实例测试自动化,合并前必绿。
  • 故意去掉 PushRosNamespace:测试应捕获 cross-talk 或断言失败。
  • ros2 doctor 无 unexpected duplicate node name。

8. 案例:绝对 /scan 刺穿 namespace

fleet 调度给 robot2 起导航,RViz 却显示 robot1 的激光——vendor 驱动 publish /scan 绝对名,robot2 的 remap 只改了相对订阅。修复:包装节点 re-publish 到相对名,或 fork 驱动。事后 CI 禁止新增绝对话题 publish。

9. 参数与节点的 namespace 联动

ros2 param load 的目标节点名含 namespace:/robot1/lidar。launch 里 PushRosNamespace 后,Nodename 是相对节点名,param 文件键无需重复前缀——但 CLI 操作必须带全名。文档示例命令与 launch 片段并列,减少现场手滑改错节点。

相对名 + launch 前缀;remap 当适配器;双实例测试当门禁。图可复制,运维才能复制。命名策略写进接口设计文档的第一页,而不是运维手册附录——第二台机器人到来时再补,成本最高。

← 全部文章

johan's blog