Files
bj_power/bj_power_mes/docs/superpowers/specs/2026-05-12-washer-batch-load-unload-design.md
T

7.2 KiB
Raw Blame History

高压清洗机批量上料/下料/换料设计

背景

高压清洗机(设备ID=5WASHER_HP)是2槽位 batch 设备。当前实现是"单次 Load + StartupWasher"模式,每次只上1个工件就启动清洗。

新需求:灵活策略 — 有2个待清洗工件就上满2个再启动,只有1个就上1个启动。批量完成后逐槽位判断卸载/换料,有 Exchange 或 Load 就追加 StartupWasher。

核心决策

  1. 启动策略:灵活 — 有2个待清洗就上满2个再启动,只有1个就上1个启动
  2. 完成信号:保持 batch 机制,一个信号 = 所有在加工槽位同时完成
  3. 上料方式:连续上料,中间无需等待
  4. 换料策略:逐槽位判断 — 有排队就 Exchange,没有就只卸载
  5. 启动判断actions 中包含 Exchange 或 Load → 追加 StartupWasher;纯 Unload 不启动

方案选择

方案 A:调度器层面批量编排(已确认)

trySchedule dispatch 阶段,当发现 WASHER_HP 相关候选时,查询槽位状态和配对情况,编排 []RobotAction 数组一次性 dispatch。

理由:

  • 符合现有架构(调度器驱动,EventLoop 串行处理)
  • 不修改 Station 接口或 MockPLC 核心逻辑
  • handleMachineDone 保持只改状态不编排

设计细节

1. RobotAction 数组

HardwareWorker.Execute 接口变更

Execute(ctx, RobotAction) 改为 Execute(ctx, []RobotAction)

Worker 串行执行数组中的每个 action,任一失败则中止后续 action,返回结果。

RobotWorker 适配

func (w *RobotWorker) Execute(ctx context.Context, actions []action.RobotAction) error {
    for _, act := range actions {
        if err := w.executeSingle(ctx, act); err != nil {
            return err
        }
    }
    return nil
}

2. StartupWasher 作为 RobotAction

新增 StartupWasher 类型,与 Load/Unload/Exchange 同级。Worker 执行时调用 PLC 启动信号。

// action.RobotAction 中 Kind 字段新增值
case "startup_washer":
    // 调用 robotCtrl.StartupWasher(ctx)

3. 上料编排

trySchedule dispatch 阶段新增逻辑

当候选任务包含 WASHER_HP Load 时:

  1. 查询 WASHER_HP 槽位状态(空槽位数量)
  2. 检查是否有第二个待清洗工件(jobRuntimesStepType_Load + ResourceType=WASHER_HP + OnBuffer
  3. 编排 []RobotAction
条件 actions
1个空槽位 + 1个候选 Load + StartupWasher
2个空槽位 + 2个候选 Load1 + Load2 + StartupWasher
2个空槽位 + 1个候选 Load + StartupWasher

4. 卸载/换料编排

trySchedule dispatch 阶段新增逻辑

当 dispatch 一个 WASHER_HP Unload 或 Exchange 时:

  1. 检查 batchMachines[machineID] 是否为 true
  2. 是 → 查询同设备另一个槽位状态
    • 另一个槽位有 Done 工件 + 有配对 → 追加 Exchange
    • 另一个槽位有 Done 工件 + 无配对 → 追加 Unload
    • 另一个槽位空 + 有待上料工件 → 追加 Load
    • 另一个槽位空 + 无待上料工件 → 不追加
  3. 否 → 正常单 action

完整场景表

场景 actions 启动?
2个 Done0个配对 Unload + Unload
2个 Done1个配对 Exchange + Unload + StartupWasher
2个 Done2个配对 Exchange + Exchange + StartupWasher
1个 Done0个配对 Unload
1个 Done1个配对 Exchange + Load + StartupWasher

启动判断规则actions 中包含 Exchange 或 Load → 追加 StartupWasher。纯 Unload 不追加。

5. handleWorkerResult 适配

Worker 返回结果后,handleWorkerResult 需要处理多 action 的结果:

  • 每个 action 的状态变更(位置更新、步骤推进)按顺序处理
  • Exchange 成功 → Done 工件放暂存台 + 新工件上料到槽位
  • Unload 成功 → Done 工件放暂存台 + 释放槽位
  • Load 成功 → 新工件上料到槽位
  • StartupWasher 成功 → 无状态变更(仅 PLC 信号)
  • 任一 action 失败 → 中止后续,已成功的 action 状态保留不变(不回滚),失败的 Job 标记为 ERROR

EquipmentSlot 一致性:每个 action 成功后立即更新 equipment_slot 表状态(通过 DBState),确保 DB SSOT 与实际状态一致。后续 action 失败时,已更新的槽位状态反映真实物理状态(工件已在槽位中或已离开)。

6. 时序保证

不存在"等第二个工件"的中间态。编排时已确定 Load 数量:

  • 1个候选 → Load + StartupWasher(上1个就启动,不等第二个)
  • 2个候选 → Load1 + Load2 + StartupWasher(上满2个再启动)

Worker 串行执行,Load1 完成后立即执行 Load2,中间无等待。不存在"上了1个但还没启动,等第二个候选出现"的状态。

7. 卸载优先级

trySchedule 发现 WASHER_HP 有 Done 槽位时,立即处理,不等待更多 Done 槽位出现。1个 Done 就 dispatch 对应的 Unload/Exchange2个 Done 就一起编排。batch 信号保证所有 Occupied 槽位同时变为 Done,不会出现"先1个 Done,稍后另1个 Done"的情况。

8. MarkAllOccupiedDone 对单槽位的正确性

MarkAllOccupiedDone() 将所有 Occupied 槽位标记为 Done。当只有1个 Occupied 槽位时,只标记那1个,空槽位不受影响。这与"1个 Done"场景一致,无需特殊处理。

9. MockPLC 适配

当前 MockPLC 的 washerDone atomic 标志是"首个上料触发计时"。新逻辑下:

  • StartupWasher 作为独立 RobotAction,调用 robotCtrl.StartupWasher(ctx) 触发 PLC 启动信号
  • MockPLC 收到启动信号后开始 4s 计时,到期后触发 WasherDone
  • MockPLC 核心逻辑不变:triggerMachineDonecase 5washerDone atomic 防重复触发逻辑保留
  • executeLoadToMachinemachineID == 5 时调用 StartupWasher 的逻辑移除,改为由 []RobotAction 编排决定何时调用

10. batch_unload 移除

当前 candidateToRobotAction 中有 batch_unload 逻辑(检查 FindAllDoneJobsOnMachine > 1 时批量卸载)。新逻辑下:

  • 卸载/换料由 trySchedule dispatch 阶段逐槽位编排
  • batch_unload 逻辑移除
  • executeBatchUnload 方法保留(用于 Worker 串行执行多个 Unload action

改动文件清单

文件 改动
internal/eventloop/worker.go Execute 接口改为接收 []RobotAction
internal/processor/robot_worker.go 适配新接口,串行执行 action 数组
internal/eventloop/loop.go trySchedule dispatch 阶段新增 WASHER_HP 槽位查询 + 批量编排逻辑
internal/eventloop/loop.go handleWorkerResult 适配多 action 结果处理
internal/processor/robot_worker.go 移除 executeLoadToMachinemachineID==5StartupWasher 调用
internal/robot/washer.go 新增 StartupWasher RobotAction 执行逻辑
internal/action/ RobotAction Kind 新增 "startup_washer"

不改动的部分

  • handleMachineDone — 只改状态,不编排
  • WasherStation — 槽位管理逻辑不变
  • MockPLC 核心逻辑 — 不变
  • 调度器 Generator/Filter/Policy — 候选任务生成逻辑不变