Skip to content

[Plan][Robot] 机械臂/导轨解耦、点位资产化与执行安全 #12

Description

@TablewareBox

SZLab 机械臂、导轨、点位与观测解耦实施计划

状态:design_frozen(D1-D9 已冻结;只更新计划,尚未实施生产代码)
Wayfinder:LOCAL-218
父项:LOCAL-126 / Uni-Lab-Core #189
实施目标分支:SZLab main
审查基线:575ddaa81e63f2c62427140ccfc9c2c1823caa8b

一、目标

把 SZLab 当前混合在一个机器人设备中的 PLC 工位脚本、机械臂/导轨模型、库位(Site)点位、原始 Sensor 地址和遗留动作拆成可替换边界,同时满足:

  1. 同一机械臂模块既可组成单机械臂设备,也可组成导轨机械臂候选工作单元(WorkCell),不复制控制实现。
  2. 机械臂型号和导轨型号可以分别替换;更换型号只替换对应模块、部署资产和标定,不派生新的机械臂包。
  3. FE 和 Workflow 使用厂商无关的 pickplacepour,不区分 PLC、TCP/SDK 或 MoveIt。
  4. Graph 只引用部署清单/硬件配置(HardwareProfile)及其 digest,不保存关节数组、PLC 程序号、原始地址或点位。
  5. 导轨机械臂的生产运行只有一个公共复合 Device;导轨先到位并取得硬件许可后,机械臂才允许运动。
  6. Warehouse 在位、末端执行器、导轨状态和硬件安全许可使用不同观测合同,未知或过期时关闭失败。
  7. submit_*、旧工位兼容动作、旧七轴 MoveIt、legacy_runner_name 和所有机器人 SKIP_* 运行时开关在一次原子切换中删除,不保留兼容版本。
  8. MoveIt 执行只依赖 move_group、控制器和 joint_states;RViz 是可选可视化客户端,不是启动或完成判定依赖。

二、冻结决定(D1-D9)

决策 已接受结论
D1 领域包边界 领域包只保存部署 YAML、exact refs/digests、标定、点位、库位访问绑定(SiteAccessBinding)、安全参数、生成模型快照和薄 Device 组合根;不复制 Adapter 或通用协调状态机。
D2 发布方式 建立独立 Robotics monorepo,统一治理但发布多个独立 Python distribution;SZLab 等领域仓库继续承担 L3 部署资产。
D3 运行时入口 同一真实机械臂+导轨在 production profile 中只激活一个公共复合 Device;Standalone 包装只用于真正的单机械臂部署或独立维护,重复物理端点在激活阶段拒绝。
D4 硬件互锁 production 必须使用经现场验证、能在硬件侧阻止危险并发的强制链;来源可为安全 PLC、控制器原生安全功能或外部安全继电器。普通遥测只作顺序和诊断。
D5 资产所有权 机械臂/导轨模块保存型号固有模型和限制;部署包保存安装变换、标定、point/target/program set、TCP、安全姿态、容差、碰撞环境和 SiteAccessBinding;部署清单原子锁定全部 digest。
D6 观测拆分 Warehouse 在位使用传感器占用数组绑定(SensorOccupancyArrayBinding);夹爪/末端、导轨状态、硬件许可分别使用 EndEffectorObservation、RailStateObservation、SafetyInterlockObservation;原始地址只留在 Adapter 配置。
D7 遗留退场 不保留一个版本的兼容层;新路径就绪后同批删除 25 个 submit_*、3 个旧兼容动作、旧 runner、七轴资产和 SKIP_*
D8 历史处理 已完成任务和回执只读保留;可编辑旧 Workflow 迁移或归档;未结算/execution_unknown 阻止切换;冻结任务快照绝不改写。
D9 动作语义 共享合同提供 pick/place/pour;纯关节翻转默认是 RobotCommand 内部段;跨设备步骤可独立结算时使用 Workflow,必须不可分割时使用 WorkCell。禁止生产公共 execute_program,禁止用虚拟 Site 把过程动作伪装成 place

三、当前实现与风险证据

当前事实 文件/分支 风险
Site 运动位置、PLC Sensor 地址和 runner 混在同一绑定 szlab_poly_studio/common/site_control_bindings.py 更换传感器、PLC、机械臂或导轨会互相牵连。
RobotCommand/Adapter 携带 presence_variablelegacy_runner_name devices/szlab_mixer_robot/standard_gateway.py 厂商中立边界仍依赖 SZLab PLC 实现。
25 个 submit_* 和 3 个旧兼容动作仍为公开 @action devices/szlab_mixer_robot/device.py FE/Catalog 暴露工位/实现细节,并形成第二执行入口。
三个源码 Workflow 共七处仍调用 submit_* workflows/robot_action.pys06_robot.pys07_robot.py 删除旧动作前必须迁移或归档。
一个遗留动作使用线程池并行机械臂与 S07 旋转 devices/szlab_mixer_robot/robot_S07.py 部分成功后现场状态不确定,且绕过 WorkCell 协调。
倒料 typed façade 最终仍调用 submit_pour_from_s08 devices/szlab_mixer_robot/device.py 两个 ResourceSlot 在执行边界退化成 PLC 任务号 25。
机器人运行时读取四类 SKIP_* 环境变量 device.pyrobot_S04.py 可绕过传感器、握手或复位前置条件。
临时 MoveIt 分支把导轨棱柱轴和 CR7 六轴放入同一 planning group,并把七元点位写入 Graph origin/tmp/robot-dual-backend-moveit-20260805 导轨与机械臂冗余求解、点位不可复用、不能保证 rail-then-arm。
机器人/PLC 主体文件过深 device.py 1095 行、standard_gateway.py 1011 行、szlab_poly_plc/device.py 1273 行 继续叠加兼容层会扩大修改和审查风险。

四、目标发布结构

4.1 独立 Robotics monorepo

候选仓库名在创建时确认;逻辑结构冻结如下:

robotics/
├── pyproject.toml                         # monorepo 工具、统一测试/静态检查
├── packages/
│   ├── unilab-robot-contracts/            # L0,无 @device
│   │   └── src/unilab_robot_contracts/
│   │       ├── actions.py                 # pick/place/pour typed contracts
│   │       ├── commands.py                # RobotCommand;无 Site/Material/地址
│   │       ├── execution_backend.py       # RobotExecutionBackend 生命周期
│   │       ├── hardware_profile.py        # profile、capabilities、endpoint refs
│   │       ├── observations.py            # EndEffector/Rail/Safety observations
│   │       └── errors.py                  # reject/UNKNOWN/reconciliation 语义
│   ├── unilab-arm-cr7/                    # L1,可替换为其他 arm distribution
│   │   └── src/unilab_arm_cr7/
│   │       ├── arm_module.py              # 模块 factory;本身不是第二公共 Device
│   │       ├── standalone_device.py       # 单机械臂薄公共包装
│   │       ├── adapters/
│   │       │   ├── plc.py                 # ProgramInvocation → PLC
│   │       │   ├── tcp_sdk.py             # RobotCommand → 厂商 SDK
│   │       │   └── moveit.py              # 六轴 MotionSequence;不启动 RViz
│   │       └── models/                     # CR7 固有 URDF/SRDF/mesh/limits
│   ├── unilab-rail-<model>/               # L1,每种导轨一个独立 distribution
│   │   └── src/unilab_rail_<model>/
│   │       ├── rail_module.py              # move/home/stop/status 私有端口
│   │       ├── adapters/                   # PLC/TCP-SDK/simulation
│   │       └── models/                     # 固有 mesh/行程/轴向/速度限制
│   └── unilab-rail-mounted-arm/            # L2,无厂商模型
│       └── src/unilab_rail_mounted_arm/
│           ├── coordinator.py              # rail-then-arm 单一命令状态机
│           ├── model_compiler.py           # arm + rail + 安装变换 → 静态快照
│           ├── endpoint_guard.py           # 拒绝重复物理端点
│           └── workcell_device.py          # 唯一公共复合 Device 薄包装
└── tests/
    ├── contracts/
    ├── arm/
    ├── rail/
    └── workcell/

4.2 SZLab L3 部署包

szlab_poly_studio/
├── deployment/robot_cell/
│   ├── manifest_schema.py                 # 部署清单校验与 digest 验证
│   ├── manifests/
│   │   ├── standalone-cr7-plc.v1.yaml
│   │   ├── standalone-cr7-moveit-sim.v1.yaml
│   │   └── rail-a-cr7-plc.v1.yaml
│   ├── bindings/
│   │   └── site_access.v1.yaml            # Site+operation → profile refs;无地址
│   ├── assets/
│   │   ├── arm_point_sets/                # 安装相关六轴点位
│   │   ├── rail_target_sets/              # 安装相关单轴目标
│   │   ├── program_sets/                   # exact PLC/controller program refs
│   │   ├── calibrations/                   # 安装变换、TCP、容差
│   │   └── collision_environments/         # 部署现场碰撞环境
│   └── profiles/
│       ├── validated_hardware_interlock/
│       ├── observed_only/
│       └── simulation/
├── devices/sensor_stacks/                 # Warehouse Sensor stacks,承接 #2-#4
├── devices/szlab_mixer_robot/
│   └── device.py                           # 仅保留选择后的薄 composition root
└── workflows/                              # 只调用 pick/place/pour 或显式 WorkCell

领域包不保存通用 PLC/TCP/MoveIt Adapter,不保存 CR7/导轨固有模型,不保存通用 rail-then-arm 状态机。

五、单机械臂与导轨机械臂

项目 单机械臂部署 导轨机械臂部署
公共 Device StandaloneArmDevice RailMountedArmWorkCellDevice
ArmModule 直接使用 同一个模块,作为私有成员使用
RailModule 不加载 独立加载,可替换型号
公共动作 pick/place/pour 相同的 pick/place/pour
模型组合 world → arm_base world → rail_base → carriage → arm_base
点位资产 standalone 安装 point-set rail target-set + 当前 rail/arm 安装 point-set
安全状态 机械臂自身许可/末端观测 RAIL_MOVING → RAIL_SETTLED → ARM_MOVING → COMPLETED

同一物理机械臂不得同时被 standalone 和 WorkCell 公共 Device 引用。更换导轨只替换 RailModule、rail target-set、安装标定和组合清单;更换机械臂只替换 ArmModule、arm point-set、TCP/标定和组合清单。

六、通用动作与命令边界

6.1 公开 typed Actions

pick(resource: ResourceSlot, source_site: SiteRef)
place(resource: ResourceSlot, target_site: SiteRef)
pour(source_resource: ResourceSlot,
     target_resource: ResourceSlot,
     interaction_site: SiteRef)
  • pick/place 是库位动作(SiteAction)。
  • pour 是厂商无关的 typed 机器人过程动作;来源/目标物料和交互 Site 必须进入完整占用意图(ClaimIntent)。
  • 倾倒角度、速度、PLC 程序、TCP routine 和 MoveIt 轨迹属于部署解析或 Adapter,不进入 Workflow/FE。
  • 纯关节翻转默认是 pour 等动作内部的 RobotCommand 运动段。只有产生独立、可复用业务语义并重新审查合同后,才可新增 invert_mix 等动作。

6.2 禁止的公共动作

  • submit_pick_from_s04submit_pour_from_s08 等工位动作。
  • plc_pickmoveit_picktcp_pick 等后端动作。
  • 生产 Workflow 使用的 execute_program(program_name, arguments)
  • 以虚拟 Site 将倒料、翻转或加工伪装成 place
  • 设备包内部使用线程池同时启动两个物理设备。

6.3 组合判定

步骤可独立持久结算、失败后边界明确
    → 显式 Workflow 节点和依赖

步骤必须共同占用、不可被其他任务插入或依赖硬件强制顺序
    → 一个 WorkCell Action + 一个完整 JobExecutionClaim

七、观测与失败关闭

观测 所有者 用途
SensorOccupancyArrayBinding 独立 Warehouse Sensor stack Site presence:empty/occupied/unknown,不推断 Material identity。
EndEffectorObservation Arm/末端 Adapter 夹爪开合、负载/抓取见证。
RailStateObservation RailModule Adapter 位置、零速、稳定时间和故障状态。
SafetyInterlockObservation 经验证的硬件安全链 Adapter 是否允许危险运动;普通 PLC 遥测不能冒充硬件许可。
  • 原始 OPC/PLC/SDK 地址只存在于 Adapter 或部署 Adapter 配置。
  • SiteAccessBinding 只保存稳定 observation refs。
  • 派发前缺失、过期或 unknown:拒绝派发。
  • 派发后无法证明物理结果:作业进入 execution_unknown,保留作业执行占用(JobExecutionClaim)和栅栏(Fence),禁止盲目物理重放。

八、现有 SZLab 文件级修改与删除清单

当前文件 目标动作 原因
common/site_control_bindings.py 由新的 deployment/robot_cell/bindings 替换后删除;不保留旧名 alias 消除 Site、Sensor 地址、控制位置和 runner 的混合权威。
devices/szlab_mixer_robot/standard_gateway.py 命令合同、账本、Backend 生命周期迁入 Robotics distributions 后删除或缩减为纯 composition 调用 SZLab 不再拥有通用执行机制。
devices/szlab_mixer_robot/device.py 缩成选择 standalone/WorkCell 的薄根;仅公开 pick/place/pour 删除 25 个 submit_*、3 个兼容动作和可绕过入口。
devices/szlab_mixer_robot/robot_tasks.py PLC program-set 资产和 PLC Adapter 就绪后删除 任务号和变量构造不再是公共动作代码。
devices/szlab_mixer_robot/robot_S01.pyrobot_S11.py 新 PLC Backend 覆盖全部语义且零引用后同批删除 不保留 legacy_runner_name 或私有遗留 runner。
devices/szlab_poly_plc/device.py 移出 Warehouse Sensor 与机器人特化职责;保留其真正拥有的通用 PLC gateway 能力 防止中心 PLC Device 成为第二观测/业务权威。
common/stack_status.py 状态投影迁入独立 sensor stack/规范观测后删除或收窄 避免自定义状态与规范观测并存。
各工位 sensors.py / 当前内嵌 Sensor 常量 按 Warehouse 归入独立 Sensor stack Sensor 更换不修改机械臂包。
workflows/robot_action.py 改用 typed pick/place 或作为旧调试 Workflow 归档 移除两处 submit_*
workflows/s06_robot.py 改用带 ResourceSlot/SiteRef 的转运 Workflow 或归档 移除两处 submit_*
workflows/s07_robot.py 改用 typed Actions/显式依赖或归档 移除三处 submit_*
workflows/single_sample_atomic_material.pysingle_sample_atomic_attachment_flow.py pour_beaker_into_vial 改为通用 pour 倒料不再退化为 task 25 旧入口。
deployment/graphs/*.json 只保留 manifest/profile ref + digest Graph 不保存点位、程序和地址。
tests/test_assemble_driver_parity.py 与旧动作测试 用新合同/删除门禁测试替换;不保留旧动作运行断言 D7 要求零遗留可执行入口。
tests/test_robot_standard_gateway.py 拆为 contracts/backend/workcell/observation 测试 固化新模块边界和 UNKNOWN 行为。

九、实施顺序

所有步骤在未发布的迁移分支中完成;D7 的“立即删除”表示同一发布原子切换,不允许中间兼容版本进入生产。

P0:切换前审计

  1. 导出可编辑 Workflow、已应用 Workflow、Graph、PackageCatalog 和本地运行数据库中的旧 action refs。
  2. 阻止新旧动作继续产生新的生产任务。
  3. 等待或人工处置所有旧 dispatched/running/cancel_requested/execution_unknown 命令,完成物理结算。
  4. 已完成任务保留只读审计,不改写。

P1:Robotics L0 合同

  1. 建立独立 monorepo 和多 distribution 构建。
  2. 定义 pick/place/pour、RobotCommand、RobotExecutionBackend、HardwareProfile 和观测合同。
  3. 固化 command identity、UNKNOWN、cancel/reconciliation 和 capability 行为。

P2:可替换 Arm/Rail 模块

  1. 从 SZLab 拆出 CR7 固有模型和三类 Adapter。
  2. 建立可替换 RailModule distribution。
  3. MoveIt 只保留六轴 planning group;导轨轴由 RailModule PLC/SDK/simulation Adapter 控制。
  4. MoveIt launch 将 RViz 作为独立可选进程;headless 模式必须通过相同执行测试。

P3:WorkCell 与硬件互锁

  1. 实现 endpoint duplicate guard。
  2. 实现 rail-then-arm 状态机和完整命令账本。
  3. 接入 validated_hardware_interlockobserved_only 不得标记 production。
  4. 对未知位置、零速、grant、末端状态统一关闭失败。

P4:SZLab 部署资产与 Sensor stacks

  1. 建立 manifest schema、exact refs/digests 和 profile guard。
  2. 从 Graph/Python 常量迁出 arm point-set、rail target-set、program-set、标定和碰撞环境。
  3. 拆分 SiteAccessBinding 与四类 observation refs。
  4. 将 Warehouse Sensor 从机器人/中心 PLC 包移入独立 Sensor stack。

P5:Workflow 迁移与遗留原子删除

  1. 迁移或归档三个仍使用 submit_* 的源码 Workflow。
  2. 迁移两个仍使用旧倒料链的 Workflow 到通用 pour
  3. 迁移所有可编辑/已应用旧 Workflow;冻结历史不改写。
  4. 替换 legacy_runner_name 后删除旧动作、runner、七轴资产、迁移映射和 SKIP_*
  5. 重建 PackageCatalog,确认 FE 只观察到通用动作。

P6:分层验收与切换

  1. 单机械臂分别验证 PLC、TCP/SDK、MoveIt headless。
  2. 导轨机械臂验证导轨先到位、硬件 grant、禁止同时运动和端点冲突。
  3. 验证缺失/过期/unknown observation 与派发歧义。
  4. 验证 Graph 零点位、零地址、digest 漂移拒绝。
  5. 通过切换门禁后一次性启用新 physical profile;不发布中间兼容版本。

十、跨仓依赖与范围

  • 本计划不修改 Backend 和 FE。FE 继续消费动作目录,动作名保持厂商无关。
  • OS 的持久作业执行占用(JobExecutionClaim)、栅栏(Fence)和候选工作单元(WorkCell)权威依赖 Uni-Lab-Core #189。
  • Warehouse 传感器占用投影依赖 OS Add single sample atomic attachment flow and update related configura… #10;传感器事实不覆盖库存权威(Inventory Authority)。
  • Robotics monorepo 是新增共享实现仓库;SZLab [Plan][Robot] 机械臂/导轨解耦、点位资产化与执行安全 #12 负责拆包、部署资产、Workflow 迁移和最终集成,不把 OS/Core 未完成能力伪装为本仓库已实现。
  • 软件顺序与普通遥测不能替代安全 PLC、控制器安全功能或外部安全继电器。

十一、验收门槛

  1. 零遗留执行面:目标源码、PackageCatalog、Graph、profile 和可执行 Workflow 中不存在 25 个 submit_*、3 个旧兼容动作、legacy_runner_name、旧七轴加载能力或机器人 SKIP_*
  2. 历史不可执行:已完成旧任务仅可读取;未物理结算或 execution_unknown 的旧命令阻止切换;任何冻结快照未被改写。
  3. 动作一致:StandaloneArmDevice 与 RailMountedArmWorkCellDevice 对 FE/Workflow 提供相同 pick/place/pour 语义;无 PLC/MoveIt/TCP 动作名。
  4. 唯一入口:同一物理端点不能同时由 standalone、rail 或 WorkCell 公共 Device 激活。
  5. 导轨顺序:没有有效 RAIL_SETTLED 和硬件 grant 时,任何机械臂命令都不能派发;测试证明不存在导轨/机械臂危险并发。
  6. 资产可替换:更换导轨或机械臂只替换对应 module ref、部署资产和标定,不复制另一模块或修改 Workflow。
  7. Graph 轻量:所有受管 Graph 不含 joint_targetssite_targetsstandard_moveit_site_targets、PLC 程序号或原始地址。
  8. 观测分权:SiteAccessBinding 和 RobotCommand 不含 presence_variable;每类观测缺失、过期或 unknown 均关闭失败。
  9. UNKNOWN 安全:派发歧义保留 Claim/Fence,禁止自动执行重试或盲目物理重放。
  10. MoveIt headless:不启动 RViz 时,MoveIt 仿真仍可启动、派发、观测和完成;RViz 退出不影响执行。
  11. 测试门禁:contracts、PLC、TCP/SDK、MoveIt、standalone、WorkCell、Sensor、资产、Workflow 迁移 E2E 和 git diff --check 全部通过。

十二、明确不做

  • 不把旧七轴点位自动转换成新的物理六轴/导轨点位;必须重新标定并发布 exact assets。
  • 不保留 @legacy_action、隐藏旧动作或一个版本的物理兼容桥。
  • 不删除已完成实验的审计事实,也不把旧冻结任务伪装成由新合同执行。
  • 不让领域包重新拥有 PLC/TCP/MoveIt Adapter 或公共 rail-then-arm 状态机。
  • 不以 RViz、普通位置遥测或配置布尔值充当硬件安全证据。
  • 不在本计划中宣称 Backend/FE、Core #189 或 OS Add single sample atomic attachment flow and update related configura… #10 已完成。

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions