618 lines
40 KiB
Markdown
618 lines
40 KiB
Markdown
# 完整工单流转手册(信号级)
|
||
|
||
> 本文档按 **信号 → 执行单元 → 状态变化** 的粒度,完整描述一个工单从建单到
|
||
> 全部工件下线的全过程:每一步"发生了什么、执行哪个最小单元、结果状态是什么
|
||
> (job 在哪/什么步骤、槽位谁占用、锁谁持有)"。
|
||
>
|
||
> 对应实现:`internal/line/executor.go`(任务→PLC 动作映射)、`internal/plcactions/executor.go`
|
||
> (信号序列)、`internal/device/*.go`(各设备模块状态推进)、`internal/robot/`
|
||
> (任务队列/优先级仲裁/预约制)、`internal/line/priority.go`(优先级配置加载)、
|
||
> `doc/signals.sql`(信号表)。
|
||
|
||
---
|
||
|
||
## 一、产线拓扑与资源
|
||
|
||
| 设备 | 类型码 | 槽位 | 说明 |
|
||
|------|--------|------|------|
|
||
| 接驳台 ×2 | DOCK | 各 42 槽 | 毛坯入口/成品出口;工件绑定取料槽位 |
|
||
| 磨床 | GRINDER | 1 槽 | 配油盘,M3600 加工完成 |
|
||
| 换向机构 | TURN_TABLE | 1 槽 | 方形件换向(PLC 自动旋转) |
|
||
| 气吹清洗 | AIR_BLOW | 1 槽 | 持料模型:机器人夹持吹洗,吹洗位不持工件 |
|
||
| 全检台 | FULL_CHECK | 6 槽 | 人工检验,批次检测(M2098 广播) |
|
||
| 缓存台 | CACHE | 1 槽 | 全检满时暂存待检件 |
|
||
| 机器人 | TEMP_SLOT(夹爪) | — | 全厂唯一共享资源,持料锁 |
|
||
|
||
**资源锁(resource_lock)**:
|
||
- `robot`:任务派发时持有、完成时释放(单在途任务互斥)
|
||
- `temp_slot`(夹爪):取料完成后归取料 job;放料完成释放;换料交接转移给前任
|
||
|
||
---
|
||
|
||
## 二、PLC 信号体系(M 区地址)
|
||
|
||
约定:**PC→PLC** 为软件触发信号(置 1 后 PLC 自复位);**PLC→PC** 为完成/状态通知
|
||
(信号轮询器每 1 秒读一遍全部状态信号、上升沿触发,speedFactor 加速时最快 50ms)。
|
||
每组操作前必须先写 **M2022 工件类型**。
|
||
|
||
> 地址均为当前 DB signal 表种子配置(`doc/signals.sql`),程序启动时加载,
|
||
> 代码只写信号名、不写地址(详见 4.0)。
|
||
|
||
### 接驳台(M2000-M2019)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2000 | DockFetchReq | PC→PLC | 取料请求(byte,触发) |
|
||
| M2001 | DockFetchPos | PC→PLC | 取位置号(1-42) |
|
||
| M2002 | DockFetchTray | PC→PLC | 取料台号(1/2) |
|
||
| M2009 | DockFetchDone | PLC→PC | 取料完成 |
|
||
| M2010 | DockPlaceReq | PC→PLC | 放料请求(byte,触发) |
|
||
| M2011 | DockPlacePos | PC→PLC | 放位置号(1-42) |
|
||
| M2012 | DockPlaceTray | PC→PLC | 放料台号(1/2) |
|
||
| M2019 | DockPlaceDone | PLC→PC | 放料完成 |
|
||
|
||
### 相机(M2020-M2029)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2022 | CameraWorkType | PC→PLC | 工件类型(每组操作前必写) |
|
||
| M2027 | CameraShootResult | PLC→PC | 拍照结果(1=有料,0=无料) |
|
||
| M2029 | CameraShootDone | PLC→PC | 拍照完成 |
|
||
|
||
### 磨床(M2030-M2059)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2030 | GrinderFetchReq | PC→PLC | 取料请求 |
|
||
| M2039 | GrinderFetchDone | PLC→PC | 取料完成 |
|
||
| M2040 | GrinderPlaceReq | PC→PLC | 放料请求 |
|
||
| M2049 | GrinderPlaceDone | PLC→PC | 放料完成 |
|
||
| M2050 | GrinderExchangeReq | PC→PLC | 换料请求 |
|
||
| M2059 | GrinderExchangeDone | PLC→PC | 换料完成 |
|
||
|
||
### 换向机构(M2060-M2079)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2060 | TurnTableFetchReq | PC→PLC | 取料请求 |
|
||
| M2069 | TurnTableFetchDone | PLC→PC | 取料完成 |
|
||
| M2070 | TurnTablePlaceReq | PC→PLC | 放料请求 |
|
||
| M2079 | TurnTablePlaceDone | PLC→PC | 放料完成 |
|
||
| M3601.0/1 | TurnTableClamped/Released | PLC→PC | 夹紧/松开到位 |
|
||
|
||
### 全检换料(M2080-M2089)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2081 | FullCheckExchangeFetchPos | PC→PLC | 换料取位置号 |
|
||
| M2082 | FullCheckExchangePlacePos | PC→PLC | 换料放位置号 |
|
||
| M2080 | FullCheckExchangeReq | PC→PLC | 换料请求 |
|
||
| M2089 | FullCheckExchangeDone | PLC→PC | 换料完成 |
|
||
|
||
### 全检台(M2090-M2109)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2091 | FullCheckFetchPos | PC→PLC | 取位置号 |
|
||
| M2090 | FullCheckFetchReq | PC→PLC | 取料请求 |
|
||
| M2099 | FullCheckFetchDone | PLC→PC | 取料完成 |
|
||
| M2101 | FullCheckPlacePos | PC→PLC | 放位置号 |
|
||
| M2100 | FullCheckPlaceReq | PC→PLC | 放料请求 |
|
||
| M2109 | FullCheckPlaceDone | PLC→PC | 放料完成 |
|
||
| M2102 | FullCheckPlaceDoneRequestInspect | PC→PLC | 放料完成请求检验(纯脉冲不等) |
|
||
| M2098 | FullCheckInspectDone | PLC→PC | 检测完成(批次广播,全槽转 DONE) |
|
||
| M2108 | FullCheckDetecting | PLC→PC | 人工检验中 |
|
||
|
||
### 缓存台(M2110-M2129)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2111 | CacheFetchPos | PC→PLC | 取料位置号 |
|
||
| M2110 | CacheFetchReq | PC→PLC | 取料请求 |
|
||
| M2119 | CacheFetchDone | PLC→PC | 取料完成 |
|
||
| M2121 | CachePlacePos | PC→PLC | 放料位置号 |
|
||
| M2120 | CachePlaceReq | PC→PLC | 放料请求 |
|
||
| M2129 | CachePlaceDone | PLC→PC | 放料完成 |
|
||
|
||
### 清洗(M2130-M2139)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M2130 | WashStartReq | PC→PLC | 清洗请求(写 1 触发) |
|
||
| M2139 | AirBlowCompleteDone | PLC→PC | 清洗完成(**byte 型**) |
|
||
|
||
### 设备状态位(M3600.x)
|
||
| 地址 | 名称 | 方向 | 含义 |
|
||
|------|------|------|------|
|
||
| M3600.0 | GrinderMachiningDone | PLC→PC | 磨床加工完成 |
|
||
| M3600.1 | GrinderAllowEntry | PLC→PC | 磨床允许进入 |
|
||
| M3604.0/1 | Dock1Present/Dock2Present | PLC→PC | 接驳台在位 |
|
||
|
||
---
|
||
|
||
## 三、状态机总览
|
||
|
||
### job 状态(status)
|
||
`CREATED(建单)` → `IN_HANDLING/PROCESSING/WAITING_UNLOAD/WAITING_DECISION`(流转中)
|
||
→ `COMPLETED(收尾)`;`SCRAPPED(报废)/SUSPENDED(暂停)` 为终态/挂起。
|
||
|
||
### job 步骤(current_step_id,圆形件主线)
|
||
```
|
||
OP10_LOAD(接驳台取料) → OP15_DECIDE(持毛坯等磨床) → OP20_LOAD/EXCHANGE(上磨床)
|
||
→ OP20_WAIT(等M3600) → OP30_LOAD(成品入夹爪待清洗) → OP35_DECIDE(清洗完成持料)
|
||
→ OP40_LOAD/EXCHANGE(放全检/换料) → OP40_BATCH_DECIDE(批次决策) → OP40_REQ(已发M2102)
|
||
→ OP40_WAIT(待检) → OP40_UNLOAD(检测完成待取) → OP60_LOAD(下料接驳台) → COMPLETED
|
||
```
|
||
方形件在 OP10 后先走 `OP25_TURN_LOAD → OP25_TURN_UNLOAD`(换向)再进磨床。
|
||
|
||
### 槽位状态(equipment_slot.status)
|
||
`EMPTY` →(预约)→ `PROCESSING` →(落料完成)→ `OCCUPIED` →(M3600/M2098)→ `DONE`
|
||
→(取走)→ `EMPTY`。换料任务预约 **DONE** 槽位(取成品放毛坯一步完成)。
|
||
|
||
### 夹爪锁(temp_slot)
|
||
`free` →(取料完成 acquire)→ `held_by_job` →(放料完成 release / 换料交接 handover)→ ...
|
||
|
||
---
|
||
|
||
## 四、最小执行单元全集(信号级)
|
||
|
||
### 4.0 通用骨架:一次 PLC 握手到底发生了什么
|
||
|
||
机器人单爪串行作业:一个最小执行单元 = 一个搬运任务 =
|
||
"从 A 点取件(装载)→ 机器人物理搬运(代码不参与)→ 放到 B 点(卸载)",
|
||
或**换料(交换式)**:到 A 点把设备里的**加工完成品**取走、同时把夹爪里
|
||
持着的工件放进 A 点——一个 Req 同时完成取+放(U11 磨床 / U12 全检 /
|
||
二次换料)。**注意夹爪里的工件不一定是毛坯**:磨床换料时是毛坯,全检
|
||
换料与二次换料时是成品(待检成品/缓存暂存成品),链式连续换料见 4.2。
|
||
**代码只负责两端与 PLC 的信号握手**,中间的物理搬运由机器人自行完成,
|
||
软件以 done 信号到达作为任务完成标志。
|
||
|
||
一次完整握手的六步(代码 `signalActionWithParams`,约束见 agent约束 6.4.1),
|
||
以 U1 接驳台取料为例逐步拆解:
|
||
|
||
| 步 | 代码动作 | U1 实例 | 为什么这么做 |
|
||
|----|---------|---------|-------------|
|
||
| 1 | 写工件类型 | 写 `CameraWorkType` = 产品配方 ID | PLC 按工件类型切换抓手/程序参数,每组动作前必须告知 |
|
||
| 2 | 连续写参数 | 写 `DockFetchPos`=槽号、`DockFetchTray`=台号 | 两个值是给同一个取料动作用的数据,**参数之间不停顿、连续写** |
|
||
| 3 | 空 1 秒 | `sleep(1s)` | 给 PLC 一个扫描周期消化参数(S7 通信异步),否则 Req 到了参数还没生效 |
|
||
| 4 | 写 Req=1 | 写 `DockFetchReq`=1 | 触发 PLC 执行取料。**只写 1 不写 0**:动作完成后 PLC 自行复位 |
|
||
| 5 | 空 1 秒 | `sleep(1s)` | 防止紧接着的下一次写操作覆盖本次写入 |
|
||
| 6 | 等 done | 等 `DockFetchDone` 上升沿 | 见下方"done 怎么等" |
|
||
|
||
**done 怎么等(不是轮询)**:派车时先把 done 信号名登记进 `doneWaits` 表
|
||
(在发 Req **之前**登记——因为第 5 步的 1 秒间隔里 PLC 往往已干完并回了
|
||
done,后登记会错过上升沿导致任务永久等待)。此后完全事件驱动:
|
||
PLC done 信号上升沿 → 信号轮询器 → `onSignal` → 匹配 `doneWaits` →
|
||
`OnTaskDone` 广播任务完成。**没有 300ms 轮询**。
|
||
|
||
**M 地址从哪来?配置粒度分两层,如实说明**:
|
||
|
||
1. **地址层(M2000/M2009…)已配置化**:地址存在 **DB signal 表**(种子数据
|
||
`doc/signals.sql`,id=1 行即 DockFetchReq → M2000)。程序启动时 preload
|
||
全量加载进内存,执行时按信号名查地址,查不到直接报错"信号地址未配置,
|
||
请检查DB signal表"。**改地址只改 DB,不用改代码**。
|
||
2. **名称层(`DockFetchReq`…)仍是代码硬编码**:所有信号名集中定义在
|
||
`constants` 包 `Sig*` 常量(一处定义,执行器全部引用常量,不再散落
|
||
魔法字符串)。**改信号名仍需同步改 constants + DB**——"只改 DB"只对
|
||
地址层成立。
|
||
3. **动作→信号组映射**(如 DockFetch 动作 = Req+Done+Pos+Tray 一组)也
|
||
硬编码在 `plcactions` 方法内;如需现场按动作配置信号组,需给 signal 表
|
||
增加动作维度(架构级改造,未做)。
|
||
|
||
下文每个单元的序列按 `信号名(当前配置地址)` 书写:括号内地址是当前种子
|
||
配置值,现场可调(改 DB);信号名对应 constants 常量(改代码)。
|
||
|
||
### 4.1 前置条件:生成 vs 预约(两层,缺一不可)
|
||
|
||
每个单元的"前置"分两层,全部满足任务才会真正派车执行:
|
||
|
||
**第一层 · 生成条件**:设备模块周期巡检(`Evaluate`)时,按槽位状态 +
|
||
job 步骤判断"现在该干什么",生成任务**入队**。此时槽位状态没有任何变化。
|
||
|
||
**第二层 · 预约通过**:机器人仲裁器从队头取任务,派车前调用 `line.reserve`:
|
||
- 目的=夹爪(一切取料类任务):查 `temp_slot` 锁。锁被**其他 job** 持有 →
|
||
预约失败,任务留队等下一轮(单爪防覆盖);free 或本人持 → 通过。
|
||
- 目的=设备槽位(放料/换料/清洗类):开事务 `SELECT ... FOR UPDATE` 锁住
|
||
槽位行(防并发抢占)→ 校验槽位状态符合预期(**换料预约 DONE**,其余
|
||
预约 EMPTY)→ 通过则写 **EMPTY/DONE → PROCESSING** + `current_job_id`
|
||
=本 job → 提交。状态不符 → 预约失败留队。
|
||
**槽位归属就是这一步写下的**,任务 done 时再由模块推进到 OCCUPIED。
|
||
- job 已终态(COMPLETED/SCRAPPED/CANCELLED)→ 任务直接作废丢弃。
|
||
|
||
**重点**:取料类任务**不会**把源槽位预约为 PROCESSING——源槽位只是任务
|
||
生成的依据(OCCUPIED/DONE),任务 done 时由模块直接写回 EMPTY。
|
||
下文每个单元按 `生成:…;预约:…` 两行书写前置。
|
||
|
||
### 4.2 换料与连续换料链(U11 / U12 / U15 的关系)
|
||
|
||
**一次换料 = 取成品 + 放夹爪工件同步完成**:一个 Req(磨床 M2050 /
|
||
全检 M2080)让 PLC 同时完成"取出设备里的加工完成品 + 把夹爪工件放进
|
||
空出的位置",夹爪工件随即变成设备里取出的成品(temp_slot 交接给成品
|
||
job)。三种换料的夹爪持件不同:
|
||
|
||
| 换料 | 夹爪持 | 设备槽 | 完成效果 |
|
||
|------|--------|--------|---------|
|
||
| U11 磨床换料 | **毛坯**(本 job) | 磨床 DONE 成品 | 毛坯开磨;成品入夹爪(交接给前任) |
|
||
| U12 全检换料 | **待检成品**(本 job,清洗完) | 全检 DONE 成品 | 待检件落全检;done 成品入夹爪(交接给前任) |
|
||
| 二次换料(U12 同序列) | **缓存暂存成品**(代做链 job) | 全检 DONE 成品 | 缓存件落全检;done 成品入夹爪(交接给 ProxyJobID 成品 job) |
|
||
|
||
**连续换料链(continuous_exchange)**:换料任务把 done 槽的成品带进夹爪
|
||
后,链 job 不是直接放全检,而是**代下料 → 回链决策点 → 再换**——每轮把
|
||
一件成品从全检 done 槽(或缓存)"换"出并下料,磨床不停机、全检不空闲:
|
||
|
||
```
|
||
链首 job(B):U12 换料(B 待检件→全检槽,A 成品入夹爪)
|
||
→ U9 代下料 A → 链决策点 OP61_DECIDE
|
||
→ 缓存有件:U15 代取缓存成品 C → 二次换料(C 落全检槽,D 成品入夹爪)
|
||
→ U9 代下料 D → 回 OP61_DECIDE,循环
|
||
→ 缓存无件 或 全检已满 2 件:链结束 → 批次决策(M2102)
|
||
```
|
||
|
||
全检模块每轮评估的决策优先级(evaluateTx,从上到下命中即止):
|
||
1. done 槽 + 持待检件 → **U12 换料**(最高优先,成品 carry 下料)
|
||
2. done 槽 + 二次换料等待 job(proxy 标记)→ 补发二次换料
|
||
3. 代做链 OP61_DECIDE:全检已满 2 件 → 批次决策;done 槽 + 缓存有件 →
|
||
U15 代取;缓存无件 → 链结束回批次决策;无 done → 等待(幂等重评),
|
||
**但本工单最后一件除外:回批次决策触发 M2102 收尾**(2026-08-17 修复:
|
||
最后一件无后续换料/取料事件可等,原逻辑待检件永久等待)
|
||
4. done 槽 + **无换料链活跃** → U4 自取(链活跃时抑制自取,防止 done 槽
|
||
被抢走导致二次换料链断裂;链 job 离开换料步骤后恢复自取)
|
||
5. 空位 → U7 放料;全满 → U10 缓存暂存
|
||
|
||
### 4.3 任务队列与优先级仲裁(谁先派车)
|
||
|
||
**队列模型**:全部设备模块(接驳台/磨床/转台/全检/缓存)生成的任务进入**同一个**
|
||
机器人任务队列(`robot.Queue`),仲裁器(`robot.Arbiter`)从队头取任务 →
|
||
预约目的地成功 → 派车。机器人单爪,**同一时刻至多一个在途任务**;预约失败的
|
||
任务留队下一轮、让位队尾(`EnqueueBack`),保证每轮扫描覆盖全队不饿死新任务。
|
||
|
||
**优先级规则**(`robot_task_priority` 表,数据驱动;数值越小越优先,改表重启即生效):
|
||
|
||
**组合优先级(2026-08-17 定稿)**:优先级语义为「任务类型 + 搬运源设备 + 目标设备」
|
||
三要素组合——一条搬运路径(如换向台→磨床链)是否优先由组合决定,任何设备组合
|
||
可单独配置,无需发明新任务类型。配置行 `from_type`/`to_type` 为 NULL 表示通配;
|
||
查找顺序(最具体优先):精确 (kind,from,to) → (kind,from) → (kind,to) → kind-only → 内置默认。
|
||
|
||
| 组合键(kind, from, to) | 默认优先级 | 典型任务 | 业务含义 |
|
||
|---------|-----------|---------|---------|
|
||
| EXCHANGE | 0 | U11 磨床换料 / U12 全检换料 | 磨床不停机、全检链不断,最高 |
|
||
| **(UNLOAD, TURN_TABLE)** | **5** | **U3 换向取料** | **换向机构与磨床同链:换向件优先取走供磨床,磨床空时优先供料(组合优先)** |
|
||
| LOAD | 10 | U6 磨床放料 / U7 全检放料 / U8 转台放料 / U9 接驳台放料 | 上料类 |
|
||
| UNLOAD | 10 | U1 接驳台取料 / U2 磨床取料 / U4 全检取料 / U5 缓存取料 | 卸料类 |
|
||
| WASH | 10 | U13 清洗 | 持料模型 |
|
||
| RELOAD | 20 | U14 缓存回流 | 回流 |
|
||
| TRANSFER | 30 | U15 代取缓存件 | 普通转运 |
|
||
|
||
**同优先级 FIFO**:相同优先级的任务按入队时间先进先出(先入队先派车)。
|
||
|
||
**计数老化防饿死(确定性,非墙钟时间)**:任务每预约失败让位一次(`YieldCount` +1),
|
||
有效优先级提升一级(下限 0 与最高优先级平齐)——让位次数是**事件序**而非时间:
|
||
同样的状态序列必然产生同样的让位次数,调度结果可复现(正向状态机语义),
|
||
同时低优先级任务最终必然被调度,不会无限排队。
|
||
|
||
**持料隐式优先级**:夹爪被某 job 持有时,其他取料类任务(目的=夹爪)预约失败
|
||
→ 让位队尾;持料 job 的下一步任务(放料/换料/清洗)反而畅通——持料模型天然
|
||
把机器人让给"已持有工件"的 job 优先走完,这是优先级之外的隐式排序。
|
||
|
||
**换向取料组合优先级(业务硬规则,2026-08-17 修复)**:
|
||
- 换向台有换向件(转台槽 DONE)时,**必须先取走换向件供磨床**
|
||
(组合行 `('UNLOAD','TURN_TABLE',NULL)`=5),不能先派接驳台取毛坯
|
||
(UNLOAD 通配=10)——换向机构与磨床同属磨床链,磨床空转等待会拖慢整线节拍。
|
||
- 历史缺陷:换向取料原与接驳台取料同为 UNLOAD(10),FIFO 下换向件排队滞留
|
||
转台、磨床空等(实测:TURN-FETCH 入队排第 6 位,DOCK-FETCH 先执行)。
|
||
- 修复演进:先新增 TURN_FETCH 任务类型(优先级 5)应急 → 被否(组合语义压扁成
|
||
单模块语义,无法覆盖"换向+其他设备"组合)→ 定稿为组合优先级:UNLOAD 类型
|
||
不变,换向取料优先由组合行表达,任意设备组合可配,不再发明新类型。
|
||
|
||
---
|
||
|
||
### U1 接驳台取料(DOCK→夹爪,毛坯上线)
|
||
- **生成**:job 停在首道工序 OP10_LOAD(StepDockFetch)且已绑定接驳台槽位
|
||
(AGV/人工放毛坯后槽位 OCCUPIED);未绑槽则静默跳过等送料
|
||
- **预约**:目的=夹爪 → `temp_slot` 必须 free(或本 job 已持);
|
||
**源槽位不预约**(仍是 OCCUPIED,不是 PROCESSING)
|
||
- **序列**:`CameraWorkType`(M2022)=配方ID → `DockFetchPos`(M2001)=槽号 →
|
||
`DockFetchTray`(M2002)=台号 → 1s → `DockFetchReq`(M2000)=1 → 1s →
|
||
等 `DockFetchDone`(M2009)
|
||
- **结果**:接驳台槽→EMPTY;夹爪→持本 job 毛坯(temp_slot 上锁);job→
|
||
OP15_DECIDE(圆形件,持毛坯等磨床)/ OP25_TURN_LOAD(方形件,先去换向)
|
||
|
||
### U2 磨床取料(GRINDER→夹爪,断料收尾专用)
|
||
- **生成**(磨床模块三条同时成立):
|
||
1. 磨床槽 **DONE**——M3600.0 上升沿(磨削完成)时模块把槽 OCCUPIED→DONE,
|
||
成品仍挂在原 job 名下(current_job_id),job 停在 OP20_WAIT;
|
||
2. **没有待磨件**(无 job 停在 OP15_DECIDE 持毛坯等磨床);
|
||
3. **没有在途磨床任务**(防重复评估重复生成)。
|
||
含义:磨完这一件后没有下一件毛坯可换,成品自己取走去清洗(断料收尾)。
|
||
- **预约**:目的=夹爪 → `temp_slot` 必须 free
|
||
- **序列**:`CameraWorkType`(M2022) → `GrinderFetchReq`(M2030)=1 → 1s →
|
||
等 `GrinderFetchDone`(M2039)
|
||
- **结果**:磨床槽→EMPTY;夹爪→持本 job 成品;job→OP30_LOAD(持成品待清洗)
|
||
- **对比**:有毛坯待磨时磨床 DONE **不走本单元**,走 U11 换料(毛坯进、
|
||
成品出、磨床不停机)
|
||
|
||
### U3 转台取料(TURN_TABLE→夹爪,方形件换向后取回)
|
||
- **生成**:转台槽 **DONE** 且 job 在 OP25_TURN_UNLOAD——放料任务 done 时
|
||
槽位直接 OCCUPIED→DONE(TurnTablePlaceDone 到达即放料+换向完成),
|
||
模块随即生成取料任务
|
||
- **任务类型**:UNLOAD(组合优先级 `(UNLOAD, TURN_TABLE)`=5,配置表驱动)——
|
||
换向机构与磨床同链,换向件优先取走供磨床,高于普通卸料(UNLOAD 通配=10),
|
||
规则详见 4.3
|
||
- **预约**:目的=夹爪 → `temp_slot` 必须 free
|
||
- **序列**:`CameraWorkType`(M2022) → `TurnTableFetchReq`(M2060)=1 → 1s →
|
||
等 `TurnTableFetchDone`(M2069)
|
||
- **结果**:转台槽→EMPTY;夹爪→持本 job 毛坯;job→OP15_DECIDE(继续去磨床)
|
||
|
||
### U4 全检取料(FULL_CHECK→夹爪,成品出全检)
|
||
- **生成**:全检槽 DONE(M2098 批次检测完成时 OCCUPIED→DONE)且 job 在
|
||
OP40_UNLOAD;且**无换料链活跃**(有链 job 时成品由换料带走,不单独取料)
|
||
- **预约**:目的=夹爪 → `temp_slot` 必须 free
|
||
- **序列**:`CameraWorkType`(M2022) → `FullCheckFetchPos`(M2091)=槽号 → 1s →
|
||
`FullCheckFetchReq`(M2090)=1 → 1s → 等 `FullCheckFetchDone`(M2099)
|
||
- **结果**:全检槽→EMPTY;夹爪→持本 job 成品;job→OP60_LOAD(待下料)
|
||
|
||
### U5 缓存取料(CACHE→夹爪,回流第一步)
|
||
- **生成**:缓存槽 OCCUPIED(全检满时暂存的待检件)且 job 在 OP50_UNLOAD
|
||
(待回流)
|
||
- **预约**:目的=夹爪 → `temp_slot` 必须 free
|
||
- **序列**:`CameraWorkType`(M2022) → `CacheFetchPos`(M2111)=槽号 → 1s →
|
||
`CacheFetchReq`(M2110)=1 → 1s → 等 `CacheFetchDone`(M2119)
|
||
- **结果**:缓存槽→EMPTY;夹爪→持本 job 待检件;job→OP40_LOAD(待放全检)
|
||
|
||
### U6 磨床放料(夹爪→GRINDER,毛坯上磨床)
|
||
- **生成**:磨床槽 EMPTY 且 job 持毛坯在 OP15_DECIDE
|
||
- **预约**:目的=磨床槽 → FOR UPDATE 锁行 → **EMPTY→PROCESSING(owner=job)**
|
||
- **序列**:`CameraWorkType`(M2022) → `GrinderPlaceReq`(M2040)=1 → 1s →
|
||
等 `GrinderPlaceDone`(M2049)
|
||
- **结果**:磨床槽→OCCUPIED(owner=job,磨削开始);夹爪释放;job→OP20_WAIT
|
||
(等 M3600)
|
||
|
||
### U7 全检放料(夹爪→FULL_CHECK,成品送检)
|
||
- **生成**:全检有空槽 EMPTY 且 job 持成品在 OP35_DECIDE(清洗完持料等容量)
|
||
- **预约**:目的=全检空槽 → **EMPTY→PROCESSING(owner=job)**
|
||
- **序列**:`CameraWorkType`(M2022) → `FullCheckPlacePos`(M2101)=槽号 → 1s →
|
||
`FullCheckPlaceReq`(M2100)=1 → 1s → 等 `FullCheckPlaceDone`(M2109)
|
||
- **结果**:全检槽→OCCUPIED(owner=job);夹爪释放;job→OP40_BATCH_DECIDE:
|
||
批次已满 2 件或工单最后一件 → 立即发 `FullCheckPlaceDoneRequestInspect`
|
||
(M2102)=1 脉冲请求检验 → job→OP40_REQ;否则→OP40_WAIT 等下一件凑批
|
||
|
||
### U8 转台放料(夹爪→TURN_TABLE,方形件换向)
|
||
- **生成**:转台槽 EMPTY 且 job 持毛坯在 OP25_TURN_LOAD
|
||
- **预约**:目的=转台槽 → **EMPTY→PROCESSING(owner=job)**
|
||
- **序列**:`CameraWorkType`(M2022) → `TurnTablePlaceReq`(M2070)=1 → 1s →
|
||
等 `TurnTablePlaceDone`(M2079)
|
||
- **结果**:转台槽→**DONE**(放料协议含 PLC 自动旋转,done 即换向完成);
|
||
夹爪释放;job→OP25_TURN_UNLOAD(随后立即生成 U3 取回)
|
||
|
||
### U9 接驳台放料(夹爪→DOCK,成品下线)
|
||
- **生成**:接驳台有 EMPTY 槽且 job 持成品在 OP60_LOAD
|
||
- **预约**:目的=接驳台槽 → **EMPTY→PROCESSING**;代下料场景槽位归属
|
||
PrevJobID(成品是谁的就归谁),自行下料归本人
|
||
- **序列**:`CameraWorkType`(M2022) → `DockPlacePos`(M2011)=槽号 →
|
||
`DockPlaceTray`(M2012)=台号 → 1s → `DockPlaceReq`(M2010)=1 → 1s →
|
||
等 `DockPlaceDone`(M2019)
|
||
- **结果**:接驳台槽→OCCUPIED;夹爪释放;job→**COMPLETED**
|
||
(FinishJob:finished_num+1,全部完成则工单 COMPLETED)
|
||
|
||
### U10 缓存放料(夹爪→CACHE,全检满暂存)
|
||
- **生成**:全检 6 槽全满且缓存有空槽;job 持成品在 OP35_DECIDE
|
||
- **预约**:目的=缓存槽 → **EMPTY→PROCESSING(owner=job)**
|
||
- **序列**:`CameraWorkType`(M2022) → `CachePlacePos`(M2121)=槽号 → 1s →
|
||
`CachePlaceReq`(M2120)=1 → 1s → 等 `CachePlaceDone`(M2129)
|
||
- **结果**:缓存槽→OCCUPIED;`job.temp_slot_no` 记录暂存槽;夹爪释放;
|
||
job→OP50_UNLOAD(待回流,全检出空后走 U5+U7 回流)
|
||
|
||
### U11 磨床换料(夹爪毛坯 ↔ GRINDER 成品,磨床不停机)
|
||
- **生成**:磨床槽 DONE 且**有**待磨件(job 持毛坯在 OP15_DECIDE)
|
||
——与 U2 互斥:有待磨件走换料,无待磨件走取料
|
||
- **预约**:目的=磨床槽 → FOR UPDATE 锁行 → **DONE→PROCESSING(owner=本
|
||
job)**;派车时校正 PrevJobID=槽位原主人(成品 job)
|
||
- **序列**:`CameraWorkType`(M2022) → `GrinderExchangeReq`(M2050)=1 → 1s →
|
||
等 `GrinderExchangeDone`(M2059)
|
||
- **结果**:磨床槽→OCCUPIED(owner=本 job,新毛坯开磨);**夹爪交接**:本 job
|
||
毛坯已放进磨床,夹爪转为持 PrevJobID 成品(temp_slot 锁转移);本 job→
|
||
OP20_WAIT;PrevJobID→OP30_LOAD(持成品待清洗)
|
||
|
||
### U12 全检换料(夹爪待检件 ↔ FULL_CHECK 成品)
|
||
- **生成**:全检有 done 槽,且存在换料链 job——持成品在 OP35_DECIDE 的 job
|
||
被判定为链首,done 槽归属链前任(成品 job)
|
||
- **预约**:目的=全检 done 槽 → **DONE→PROCESSING(owner=本 job)**
|
||
- **序列**:`CameraWorkType`(M2022) → `FullCheckExchangeFetchPos`(M2081)=槽号
|
||
→ 1s → `FullCheckExchangePlacePos`(M2082)=槽号 → 1s →
|
||
`FullCheckExchangeReq`(M2080)=1 → 1s → 等 `FullCheckExchangeDone`(M2089)
|
||
(注:三条写信号之间**必须**各空 1 秒,与配方 wait_after_ms 一致,
|
||
缺间隔生产 PLC 会信号未生效即写下一条)
|
||
- **结果**:done 槽→OCCUPIED(owner=本 job);成品入夹爪(PrevJobID 持有)→
|
||
OP60_EXCHANGE_LOAD(链 job 代下料);本 job→OP40_BATCH_DECIDE(待检件
|
||
已落全检,走批次决策)
|
||
|
||
### U13 清洗(夹爪持成品 → AIR_BLOW,持料模型)
|
||
- **生成**:吹洗位可用且 job 持成品在 OP30_LOAD
|
||
- **预约**:目的=吹洗位 → **EMPTY→PROCESSING**(清洗位物理不持工件,洗完
|
||
仍夹在夹爪上)
|
||
- **序列**:`CameraWorkType`(M2022) → `WashStartReq`(M2130)=1 → 1s →
|
||
等 `AirBlowCompleteDone`(M2139)(**信号名是 AirBlowCompleteDone**,
|
||
旧名 WashCompleteDone 已不在信号表中,byte 型)
|
||
- **结果**:吹洗位→EMPTY;**夹爪不释放(持料模型)**;job→OP35_DECIDE
|
||
(持成品等全检容量决策)
|
||
|
||
### U14 缓存回流(CACHE → FULL_CHECK,两步串行)
|
||
- **生成**:缓存槽 OCCUPIED(owner=job) 且全检有空槽;job 在 OP50_UNLOAD
|
||
- **预约**:目的=全检空槽 → **EMPTY→PROCESSING(owner=job)**(取缓存这半程
|
||
的夹爪锁由任务本身保证)
|
||
- **序列**:U5 序列(`CacheFetchPos`(M2111)→`CacheFetchReq`(M2110)→等
|
||
`CacheFetchDone`(M2119))→ 立刻 U7 序列(`FullCheckPlacePos`(M2101)→
|
||
`FullCheckPlaceReq`(M2100)→等 `FullCheckPlaceDone`(M2109))→
|
||
`FullCheckPlaceDoneRequestInspect`(M2102) 脉冲(完成信号=放料完成)
|
||
- **结果**:缓存槽→EMPTY;全检槽→OCCUPIED(owner=job);夹爪释放;job→
|
||
OP40_BATCH_DECIDE
|
||
|
||
### U15 代取缓存件(CACHE→夹爪,换料链代做)
|
||
- **生成**:全检二次换料链需要缓存里的成品(缓存槽 OCCUPIED(owner=
|
||
ProxyJobID)),由链 job 持夹爪代取
|
||
- **预约**:目的=夹爪 → `temp_slot` 已由链 job 持有(本人持→通过)
|
||
- **序列**:`CameraWorkType`(M2022) → `CacheFetchPos`(M2111)=槽号 → 1s →
|
||
`CacheFetchReq`(M2110)=1 → 1s → 等 `CacheFetchDone`(M2119)
|
||
- **结果**:缓存槽→EMPTY;夹爪→链 job 持缓存成品;job→OP40_EXCHANGE_2ND
|
||
(持缓存件去做二次换料)
|
||
|
||
---
|
||
|
||
## 五、完整工单流转(示例:11 件圆形件,1 磨床 / 6 槽全检 / 1 槽缓存 / 1 机器人)
|
||
|
||
### 阶段 0:建单与放料
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 0.1 | 新建工单,11 件圆形件(product_type=1) | 11 个 job=CREATED;工单=CREATED |
|
||
| 0.2 | 接驳台放毛坯:AGV/人工把 11 件放接驳台各槽 | 接驳台槽1-11=OCCUPIED(各绑定 job1-11);磨床=EMPTY;全检 6 槽=EMPTY;缓存=EMPTY;temp_slot=free;robot=idle |
|
||
|
||
### 阶段 1:首件上线(接驳台→磨床)
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 1.1 | 启动工单,接驳台模块评估:job1 绑槽1 → 生成 DOCK-FETCH 任务(U1) | 任务入队(源槽位不预约,派车前才查夹爪锁) |
|
||
| 1.2 | 派发 U1:M2022 → M2001=1 → M2002=1 → 1s → M2000 → 等 M2009 | robot=held |
|
||
| 1.3 | **M2009 到达**:取料完成 | 接驳台槽1→EMPTY;temp_slot→job1(毛坯入夹爪);job1→OP10_LOAD→OP15_DECIDE;robot=idle |
|
||
| 1.4 | 磨床模块评估:磨床 EMPTY + job1 持毛坯 → 生成 PLACE 任务(U6) | 派车前预约磨床槽 EMPTY→PROCESSING(owner=job1) |
|
||
| 1.5 | 派发 U6:M2022 → M2040 → 等 M2049 | robot=held |
|
||
| 1.6 | **M2049 到达**:放料完成 | 磨床槽→OCCUPIED(owner=job1);temp_slot 释放;job1→OP20_WAIT;robot=idle |
|
||
| 1.7 | 磨床开始磨削 job1 | job1=PROCESSING;磨床槽=OCCUPIED(job1) |
|
||
|
||
**结果**:job1 在磨床加工中;夹爪空;接驳台槽1 空(余 10 件)。
|
||
|
||
### 阶段 2:首件完成 M3600 与换料(磨床优先)
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 2.1 | **PLC M3600.0 置位**(磨削完成)→ 上升沿 → 磨床模块处理 | 磨床槽 OCCUPIED→DONE(owner=job1);job1 仍 OP20_WAIT(成品在磨床等出路) |
|
||
| 2.2 | 评估出路:job2 持毛坯在夹爪(OP15_DECIDE)→ 生成 EXCHANGE 任务(job2 换 job1) | 派车前预约磨床 DONE 槽→PROCESSING(owner=job2),PrevJobID 取槽位原主人 job1 |
|
||
| 2.3 | 派发 U11:M2022 → M2050 → 等 M2059 | robot=held |
|
||
| 2.4 | **M2059 到达**:换料完成 | 磨床槽→OCCUPIED(owner=job2);job2→OP20_WAIT(开始磨);**temp_slot 交接 job2→job1**(成品入夹爪);job1→OP30_LOAD;robot=idle |
|
||
|
||
**结果**:磨床磨 job2;夹爪持 job1 成品;磨床不停机(换料即取即放)。
|
||
|
||
### 阶段 3:清洗(持料模型)与放全检
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 3.1 | 清洗模块评估:job1 持成品 → 生成 WASH 任务(U13) | 预约吹洗位 |
|
||
| 3.2 | 派发 U13:M2022 → M2130 → 等 M2139 | robot=held;job1 持料贯穿(temp_slot 不释放) |
|
||
| 3.3 | **M2139 到达**:清洗完成 | 吹洗位→EMPTY;**temp_slot 仍归 job1(持料模型)**;job1→OP35_DECIDE;robot=idle |
|
||
| 3.4 | 全检模块评估:全检有空槽 + job1 持成品 → 生成 PLACE 任务(U7) | 派车前预约全检空槽→PROCESSING(owner=job1) |
|
||
| 3.5 | 派发 U7:M2022 → M2101=槽号 → 1s → M2100 → 等 M2109 → **M2102 请求检验**(脉冲) | robot=held |
|
||
| 3.6 | **M2109 到达**:放料完成 | 全检槽→OCCUPIED(owner=job1);**temp_slot 释放**;job1→OP40_BATCH_DECIDE;robot=idle |
|
||
| 3.7 | 批次决策:槽1 已 OCCUPIED 但未满 2 件且非末件 → 不发 M2102,job1→OP40_WAIT | job1 在全检台待检;夹爪空 |
|
||
|
||
**结果**:job1 待检;夹爪空(持料在放全检后释放);磨床磨 job2。
|
||
|
||
### 阶段 4:批量流转(第 2-10 件循环)
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 4.1 | job2 M3600 → 换料给 job3(重复阶段 2);job2 清洗 → 放全检槽2(重复阶段 3) | 全检槽1=job1、槽2=job2 均 OCCUPIED;job3 磨床加工 |
|
||
| 4.2 | 全检槽1+槽2 均待检 → **发 M2102 请求检验**(满 2 件批次规则) | job1/job2→OP40_REQ;人工检验开始 |
|
||
| 4.3 | **PLC M2098 置位**(批次检测完成广播)→ 上升沿 | 全检槽1/2 OCCUPIED→**DONE**;job1/job2→OP40_UNLOAD(待取料) |
|
||
| 4.4 | 评估:job3 持成品在 OP35_DECIDE(清洗完)→ 生成**全检换料**任务(U12:job3 换 job1) | 任务入队;派车前预约槽1(DONE)→PROCESSING(owner=job3),PrevJobID=job1 |
|
||
| 4.5 | 派发 U12:M2081=槽1 → 1s → M2082=槽1 → 1s → M2080 → 等 M2089 | robot=held |
|
||
| 4.6 | **M2089 到达**:全检换料完成 | 槽1→OCCUPIED(owner=job3)(待检件落全检);**成品 job1 入夹爪**(temp_slot→job1);job1→OP60_EXCHANGE_LOAD;job3→OP40_BATCH_DECIDE |
|
||
| 4.7 | 全检评估:槽2 DONE 无换料者 → 生成**全检取料**任务(U4:job2 自取) | 任务入队;派车前查夹爪锁(源槽不预约) |
|
||
| 4.8 | 派发 U4:M2022 → M2091=槽2 → 1s → M2090 → 等 M2099 | robot=held |
|
||
| 4.9 | **M2099 到达**:取料完成 | 槽2→EMPTY;temp_slot→job2;job2→OP60_LOAD(持成品待下料) |
|
||
| 4.10 | 评估:job2 持成品 → 下料任务(U9,自行下料回自己取料槽位) | 派车前预约接驳台槽2(EMPTY→PROCESSING,owner=job2) |
|
||
| 4.11 | 派发 U9:M2022 → M2011=槽2 → M2012=台号 → 1s → M2010 → 等 M2019 | robot=held |
|
||
| 4.12 | **M2019 到达**:下料完成 | 接驳台槽2→OCCUPIED(owner=job2);temp_slot 释放;**job2→COMPLETED**(工单 finished_num=1) |
|
||
| 4.13 | job1 换料下料(job1 持成品,U9)→ COMPLETED | 接驳台槽1→OCCUPIED(owner=job1);finished_num=2 |
|
||
| 4.14 | 循环:job4-10 重复阶段 2-4(磨床换料 → 清洗 → 全检换料/放料 → 批次 → 下料) | 每 2 件一批 M2102/M2098;finished_num 递增 |
|
||
|
||
### 阶段 5:缓存暂存与回流(全检 6 槽满时)
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 5.1 | 全检 6 槽全 OCCUPIED(待检)且 job7 清洗完成持料 | job7=OP35_DECIDE(持成品)等全检空位 |
|
||
| 5.2 | 全检模块评估:无空槽 → 生成**缓存暂存**任务(U10) | 派车前预约缓存槽(EMPTY→PROCESSING) |
|
||
| 5.3 | 派发 U10:M2121 → 1s → M2120 → 等 M2129 | job7 持成品去缓存 |
|
||
| 5.4 | **M2129 到达**:暂存完成 | 缓存槽→OCCUPIED(owner=job7);job7.temp_slot_no=缓存槽;temp_slot 释放;job7→OP50_UNLOAD(待回流) |
|
||
| 5.5 | 全检批次 M2098 → 槽1-6 DONE → 逐步取走/换料 → 出现空槽 | 全检有空槽 |
|
||
| 5.6 | 缓存回流评估:缓存槽 OCCUPIED + 全检空槽 → 生成**回流**任务(U14) | 派车前预约全检空槽(EMPTY→PROCESSING) |
|
||
| 5.7 | 派发 U14:U5(M2111→M2110→等 M2119)→ U7(M2101→M2100→等 M2109 + M2102) | robot=held |
|
||
| 5.8 | **M2129 之后 M2109 到达**:回流完成 | 缓存槽→EMPTY;全检槽→OCCUPIED(owner=job7);temp_slot 释放;job7→OP40_BATCH_DECIDE(继续正常批次) |
|
||
|
||
### 阶段 6:全检+缓存全满的背压(no_space 场景:全检 2 槽+缓存 1 槽,15 件)
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 6.1 | job1/job2 磨完→清洗→放全检槽1/槽2 | 全检满(2 槽 OCCUPIED)→ 满 2 件即发 M2102 → 检验中 |
|
||
| 6.2 | job3 磨完→清洗→全检满→**缓存暂存**(U10) | 缓存槽→OCCUPIED(owner=job3);job3→OP50_UNLOAD |
|
||
| 6.3 | job4 磨完→清洗→全检满+缓存满→**无出路** | job4=OP35_DECIDE 持成品;temp_slot=job4(夹爪被占) |
|
||
| 6.4 | job5 毛坯取料任务(U1)**预约夹爪失败**(被 job4 持)→ 留队老化 | 接驳台不再上料;没有新 job 进入 OP15_DECIDE |
|
||
| 6.5 | 磨床磨完 job5 → M3600 → DONE,但**无待磨件**(无 OP15_DECIDE)→ 断料收尾生成 U2 取料任务 | U2 预约夹爪仍失败(被 job4 持)→ 留队;磨床停在 DONE 等出路 |
|
||
| 6.6 | **全线背压**:磨床 DONE、夹爪被 job4 持、全检/缓存全满;唯一出路是 PLC **M2098**(批次检测完成) | 全检槽1/2→DONE;job1/job2→OP40_UNLOAD |
|
||
| 6.7 | job4 持成品 → **全检换料链**(U12:job4 换 job1)→ job1 成品入夹爪→代下料(U9)→ job1 COMPLETED | 槽1→OCCUPIED(owner=job4);夹爪释放后按优先级恢复:上料/断料取料/缓存回流依次解锁 |
|
||
|
||
背压断言:暂停期间不崩溃、不空转、无死循环;恢复后槽位归属守恒。
|
||
|
||
### 阶段 7:最后一件收尾(last_piece)
|
||
| 步骤 | 发生 | 结果状态 |
|
||
|------|------|---------|
|
||
| 7.1 | job11 M3600(磨削完成)→ 评估:**无后继待磨件** → 不换料,生成断料取料任务(U2) | 任务入队;派车前查夹爪锁;无 EXCHANGE 任务 |
|
||
| 7.2 | 取料完成:磨床槽→EMPTY;temp_slot→job11;job11→OP30_LOAD | 磨床空(收尾完成) |
|
||
| 7.3 | 清洗 → 放全检(U13→U7)→ 批次决策:**工单最后一件(IsLastPieceOfOrder)→ 必发 M2102** | job11→OP40_REQ;即使不满 2 件也收尾批次 |
|
||
| 7.4 | **M2098** → job11→OP40_UNLOAD → 取料(U4)→ 下料(U9) | 接驳台槽11→OCCUPIED(owner=job11);**job11→COMPLETED**;finished_num=11 |
|
||
| 7.5 | FinishJob 检查:工单下全部 job 终态 → **工单→COMPLETED** | 工单完成;全部 11 件在接驳台槽位;temp_slot=free;robot=idle;磨床/全检/缓存全 EMPTY |
|
||
|
||
---
|
||
|
||
## 六、done 信号先后交替场景(done_cross)
|
||
|
||
同一时刻可能有多条 done 信号在不同设备上先后/交叉到达,验证系统不会错配、错序、漏消费:
|
||
|
||
| 子场景 | 注入方式 | 系统行为 | 预期结果 |
|
||
|--------|---------|---------|---------|
|
||
| a. 磨床 done 迟到 | M3600.0 置位延迟 **10s**(mock 注入延迟) | 期间其他 job 正常流转(清洗/放全检不受影响);磨床 done 迟到达后仍被正确消费 | job 消费 M3600 **恰好 1 次**,不因迟到丢失、不重复推进 |
|
||
| b. 全检 done 提前(陈旧) | 启动 ~5s 注入一次 **M2098=1**(此时无 job 处于 OP40_REQ) | 全检模块陈旧信号守卫:`jobsAtStep(OP40_REQ)` 为空 → **忽略**(不广播、不推进) | 陈旧 M2098 被过滤,不误唤醒任何 job |
|
||
| c. 两信号交叉到达 | M3600(迟到 10s)与真实 M2098 到达时间重叠 | doneWaits 按**信号名**匹配(单机器人同一时刻至多一个在途任务);M2098 仅在**发过 M2102** 后消费(批次广播与触发请求严格配对) | 各 job 消费各自的 done;M2098 消费不早于本批 M2102 发送;无错配 |
|
||
|
||
**时序图(子场景 a+c 示意)**:
|
||
```
|
||
job5 磨削中 ──────── M3600(迟到10s) ──► 磨床 DONE → 换料
|
||
job6 放全检 ── M2109 ──► M2102 请求检验 ──► M2098 批次广播 ──► 全检槽 DONE
|
||
(两信号在 ~10s 窗口内交叉到达,互不干扰)
|
||
```
|
||
|
||
**关键机制**:
|
||
1. **上升沿检测**:信号从 0→1 才算一次事件(持续为 1 不重复触发)
|
||
2. **doneWaits 登记先行**:派发前先登记 done 等待,防完成信号先于登记到达(约束 6.4.1)
|
||
3. **陈旧守卫**:M2098 只在有 job 处于 OP40_REQ(已发 M2102)时消费;M3600 只在有 OCCUPIED 槽时消费
|
||
4. **单在途任务**:机器人同一时刻只有一个在途任务,done 信号天然串行匹配
|
||
|
||
---
|
||
|
||
## 七、关键交互场景状态流转
|
||
|
||
### 7.1 磨床换料链(continuous_exchange,4 件 A/B/C/D 预置)
|
||
```
|
||
A(持毛坯,OP15) ──换B──► 磨床 OCCUPIED(A) [B 成品入夹爪]
|
||
B(持成品) ──清洗──► 全检换料 ──► B 成品下料(OP60_EXCHANGE_LOAD)
|
||
B ──OP61_DECIDE 决策:缓存有 C → 代取 C(OP50_EXCHANGE_TAKE)
|
||
B(持 C) ──二次换料(OP40_EXCHANGE_2ND, proxy C)──► 全检 done 槽换主人 → D 成品入夹爪
|
||
D 下料(OP60_LOAD_2ND) ──► D COMPLETED;B 完成链 → 批次决策 OP40_BATCH_DECIDE
|
||
```
|
||
- ProxyJobID:代做链中缓存件 C 的槽位归属(预约/落位都按 ProxyJobID)
|
||
- 断言:M2102 批次请求**恰好 1 次**;换料链 done 槽位不被自取任务抢走
|
||
(hasActiveExchangeChain 保护)
|
||
|
||
### 7.2 持料模型(airblow_hold)
|
||
- 清洗期间 robot 被本 job 持有(temp_slot 不释放)→ 其他 job 的取料任务预约失败留队
|
||
- **唯一释放点**:放全检(U7 完成,M2109 到达后 temp_slot release)
|
||
- 断言:temp_slot 释放审计事件仅落料点 1 次、清洗完成 0 次;其他 job 清洗晚于本 job 放全检
|
||
|
||
### 7.3 槽位归还(dock_slot_return,6 件跨 2 接驳台)
|
||
- 自行下料:成品回到**自己取料槽位**(dock_equipment_id 绑定)
|
||
- 代下料(换料收尾件):回到 **PrevJobID 绑定槽位**(成品从哪来回哪去)
|
||
- 断言:接驳台 OCCUPIED 槽数守恒(每件成品恰好一个落位)
|
||
|
||
### 7.4 缓存回流(cache_reflow)
|
||
- 全检满 → 缓存暂存(U10,temp_slot_no 记录)
|
||
- 全检空 → 回流(U14:取缓存+放全检连续动作,一次任务完成)
|
||
- 断言:OP50_LOAD 暂存 → OP50_UNLOAD 回流步骤序列正确;temp_slot_no 清除
|
||
|
||
---
|
||
|
||
## 八、执行方式与验收标准
|
||
|
||
```bash
|
||
# 全量 14 场景回归(每场景独立 DB 环境)
|
||
go run ./cmd/mockrun/ -scenario <round|single_job|square|exchange|cache_reflow|
|
||
no_material|no_space|last_piece|mom|cancel_restart|continuous_exchange|
|
||
airblow_hold|dock_slot_return|done_cross> [-jobs N] [-timeout T] [-verify]
|
||
```
|
||
|
||
验收标准:每场景 `验证结果: N 通过, 0 失败`、exit=0、无 `level=ERROR` 日志。
|
||
场景与验证项见 `14个场景.md`;本文档为信号级流转依据。
|