# 扫码失败废料搬运流程 **日期**: 2026-05-20 **状态**: 已确认 **类型**: 新功能 ## 1. 概述 从接驳台取料扫码后,如果扫码失败,工件放到暂存台(状态 `WAITING_WASTE`),等 `WasteReady` 信号为 true 时搬运到废料台,释放暂存台槽位,Job 标记为 `SCRAPPED`。 ### 流程 ``` 接驳台取料 → 扫码失败 → 放入暂存台(WAITING_WASTE) → 等待 WasteReady → 搬运至废料台 → 释放暂存台槽位 → Job SCRAPPED ``` ## 2. 涉及模块 | 模块 | 改动 | |------|------| | `constants/constants.go` | 新增 `JobStatus_WaitingWaste` | | `schema/job.go` | ent 枚举更新(先改,再 `go generate`) | | `internal/processor/replenisher.go` | 扫码失败时写 `WAITING_WASTE` + alarm | | `internal/processor/scheduler/types.go` | `SystemState` 新增 `WasteReady bool` | | `internal/processor/eventloop/scheduler_bridge.go` | 快照读取 WasteReady 信号 | | `internal/processor/scheduler/generator.go` | 为 WAITING_WASTE job 生成废料搬运任务 | | `internal/processor/robot_worker.go` | 新增 `executeLoadToWaste` 分发 | | `internal/robot/dock.go` | 新增 `PlaceWorkpieceToWasteStation`(M1140) | | `internal/processor/eventloop/worker_dispatch.go` | 废料搬运完成后 ScrapJob + ReleaseSlot | ## 3. 详细设计 ### 3.1 Job 状态 新增 `JobStatus_WaitingWaste = "WAITING_WASTE"`。 - **PositionType**: `ON_BUFFER`(工件物理占用暂存台槽位) - **SuspendedReason**: `"SCAN_FAILED"` - 调度器 `JobSuspended` filter 需要同步排除此状态(WAITING_WASTE 不应被常规调度选中) ### 3.2 Replenisher 扫码失败逻辑 `replenishOne` 方法中,扫码失败后: 1. 工件物理已在暂存台(机器人已放置) 2. 写 DB:`SetStatus(WAITING_WASTE)` + `SetPositionType(ON_BUFFER)` + `SetSuspendedReason("SCAN_FAILED")` 3. DockSlot 清空(status=0),可继续接收新料 4. 创建 alarm(`alarm_code: SCAN_FAILED`),供追溯 5. 不阻塞后续补料(continue 下一个 dock item) ### 3.3 WasteReady 信号 - 信号已定义:`WasteReady` = `M1150.1`(`doc/signal.csv` 行 19) - 通过 `preload.GetMAddress("WasteReady")` 获取地址,在 `trySchedule` 时读取 PLC 当前值 - `SystemState.WasteReady bool` — 调度快照中携带,供 Generator 判断 ### 3.4 调度 **Generator**: 遍历 `RuntimeSnapshot` 中 `Status == WAITING_WASTE` 的 job,若 `WasteReady == true`,生成: ``` CandidateTask{ Action: ActionLoadWaste, // 已在 types.go 中定义 TargetID: tempSlotNo, Priority: PriorityHigh, } ``` **SchedulerBridge**: 映射 `ActionLoadWaste` → `RobotAction{Kind: "load_to_waste", SrcSlot: tempSlotNo}`。 **优先级**: `PriorityHigh`,释放暂存台资源不应被普通装料阻塞。 ### 3.5 RobotWorker 新增 `executeLoadToWaste`: ```go // 暂存台取料 → 放入废料台 func (w *RobotWorker) executeLoadToWaste(ctx context.Context, action action.RobotAction) error { // 1. 从暂存台取料 if err := w.robotCtrl.FetchWorkpieceFromTempStation(ctx, ...); err != nil { return fmt.Errorf("fetch from temp station: %w", err) } // 2. 放入废料台 (M1140) if err := w.robotCtrl.PlaceWorkpieceToWasteStation(ctx, ...); err != nil { return fmt.Errorf("place to waste station: %w", err) } return nil } ``` ### 3.6 Robot Controller `internal/robot/dock.go` 新增: ```go func (c *Controller) PlaceWorkpieceToWasteStation(ctx context.Context, ...) error { // 发送 M1140 信号 } ``` ### 3.7 EventLoop 完成处理 废料搬运成功后: 1. `TempStoreActor.ReleaseSlot(slotNo)` — 释放暂存台槽位 2. `DBState.ScrapJob(jobID)` — Job 标记 SCRAPPED(终态) ### 3.8 启动恢复 `RecoverOnStartup` 中:`WAITING_WASTE` 状态的 job 视为已正确放置在暂存台,**不**转为 PAUSED。等待下次 `trySchedule` 时 `WasteReady` 信号触发搬运。 ## 4. 边缘情况 - **多个 WAITING_WASTE job**: Generator 一次生成多个候选任务,由 PriorityPolicy 按优先级排序后依次执行 - **WasteReady 长时间为 false**: job 留在暂存台,占用槽位,不阻塞其他正常 job 调度(JobSuspended filter 排除) - **暂存台满**: replenisher 的 `reserveFreeTempSlot` 分配失败会正常停止补料,不会抢占废料等待工件的槽位 - **废料台满**: PLC 不会设置 WasteReady=true,搬运不会触发(硬件层保证)