Files
bj_power/bj_power_mes/docs/superpowers/specs/2026-05-20-scan-failure-waste-flow-design.md
T

115 lines
4.4 KiB
Markdown
Raw Normal View History

# 扫码失败废料搬运流程
**日期**: 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,搬运不会触发(硬件层保证)