784 lines
33 KiB
Markdown
784 lines
33 KiB
Markdown
# agent业务.md
|
||
|
||
本文档是产线业务的完整描述,面向人类阅读(产线工程师、操作员、新员工)。配合 `agent约束.md`、`data.sql`、`signals.sql` 可还原当前项目全部代码。
|
||
|
||
禁止写入 SQL/schema/signals.sql 中已有的数据(设备参数、信号地址、槽位数等),禁止引用代码常量或函数名。
|
||
|
||
---
|
||
|
||
## 零、系统架构概述
|
||
|
||
### 全配置化流程引擎
|
||
|
||
系统采用**全配置化流程引擎**架构,所有工艺步骤的行为通过数据库配置驱动,不硬编码任何设备类型或工序行为。
|
||
|
||
**引擎核心循环(4 阶段):**
|
||
|
||
```
|
||
ACQUIRE(获取资源)→ EXECUTE(发送信号)→ WAIT(等待完成)→ COMPLETE(后置操作)
|
||
```
|
||
|
||
**引擎不包含任何业务知识**(不知道磨床、接驳台、全检台的区别),所有行为由以下数据库表配置:
|
||
|
||
| 配置表 | 作用 | 配置内容 |
|
||
|--------|------|----------|
|
||
| `recipe_step` | 步骤定义 | 步骤名称、序号、默认下一步 |
|
||
| `recipe_step_resource` | 资源需求 | 每一步需要获取哪些资源(机器人、槽位等) |
|
||
| `recipe_step_signal` | 信号序列 | 每一步发送什么 PLC 信号、等待什么 Done 信号 |
|
||
| `recipe_step_action` | 后置操作 | 步骤完成后释放资源、设置状态、发送额外信号 |
|
||
| `recipe_step_decision` | 决策分支 | 条件判断→跳转到不同步骤(如全检台满→缓存台) |
|
||
|
||
**资源类型:**
|
||
- `robot`:机器人(互斥,同一时间只能一个 job 使用)
|
||
- `temp_slot`:缓存槽(1 个,工件暂存用)
|
||
- `equipment_slot`:设备槽位(接驳台/磨床/全检台/缓存台等)
|
||
|
||
**资源操作:**
|
||
- `acquire`:独占获取(SELECT FOR UPDATE 事务锁),确保原子性
|
||
- `check`:非独占检查(SELECT FOR UPDATE 轻量锁),仅确认条件满足
|
||
|
||
**信号角色:**
|
||
- `param`:参数信号,在 req 之前写入(如工件类型 M2022、位置号)
|
||
- `req`:请求信号,触发 PLC 动作
|
||
- `done`:完成信号,由 SignalRouter 异步监控,到达后触发 COMPLETE
|
||
- `post`:后置信号,在 COMPLETE 阶段发送(如 M2102 检测请求)
|
||
|
||
---
|
||
|
||
## 一、产线概述
|
||
|
||
磨床自动化单元,由 1 台机器人串行搬运物料,串联 6 台设备完成从毛坯到成品的全流程加工。
|
||
|
||
设备清单见 `data.sql` 的 `equipment` + `equipment_type` 表,信号地址见 `signals.sql`。
|
||
|
||
机器人负责在设备间搬运工件,同一时间只能执行一个动作(串行互斥)。所有设备通过 PLC 控制,系统通过信号与 PLC 握手交互。
|
||
|
||
---
|
||
|
||
## 二、工艺步骤
|
||
|
||
### OP10 接驳台上料
|
||
|
||
- 做什么:机器人从接驳台取毛坯
|
||
- 来源:接驳台的托盘(左右各一个,AGV 送达)
|
||
- 完成条件:机器人成功取到毛坯
|
||
- 异常:取料失败需人工介入
|
||
- 特殊情况:接驳台没料时暂停,等 AGV 送来
|
||
|
||
### OP20 磨床磨削
|
||
|
||
- 做什么:机器人把毛坯放入磨床,等待磨削完成,取走成品
|
||
- 特殊处理:方形件需要先放换向机构换向,再放入磨床
|
||
- 换料:磨床已有成品时,机器人可一次完成「取成品+放毛坯」,减少搬运次数
|
||
- 完成条件:磨床发出磨削完成信号
|
||
- 异常:磨削超时/失败需人工介入
|
||
- 特殊情况:
|
||
- 磨床空时:直接放料(不用换料)
|
||
- 磨床有料且加工完成:换料
|
||
- 磨床有料但还在加工:等待
|
||
|
||
### OP30 工件清洗
|
||
|
||
- 做什么:机器人把工件放到清洗工位,启动清洗,等待完成,取走
|
||
- 完成条件:清洗完成信号
|
||
- 异常:清洗超时需人工介入
|
||
|
||
### (判断)全检台是否满位(OP35 全检台容量判断)
|
||
|
||
- 条件:全检台有空位 → 走 OP40 全检检测
|
||
- 条件:全检台满 + 缓存台有空位 → 走 OP50 缓存暂存
|
||
- 条件:全检台满 + 缓存台也满 → 不推进,等待下次调度重新判断
|
||
- 这是 recipe 中的 Decision 步骤,由引擎按优先级遍历决策分支
|
||
|
||
### (判断)磨床取料前下游容量判断(OP20_DECIDE 磨床下游容量判断)
|
||
|
||
- 触发时机:M3600 磨床加工完成信号到达后,在 OP20_UNLOAD(取料)之前
|
||
- 目的:防止 robot 取料后下游全满无处可放,形成死锁(robot 持料等待缓存空、全检台 done 件等待 robot 空爪、缓存件等待全检台空)
|
||
- 条件:全检台有空位 → 正常取料(OP20_UNLOAD)
|
||
- 条件:缓存台有空位 → 正常取料(OP20_UNLOAD)
|
||
- 条件:全检台+缓存台均满 → 不取料,等待下次调度重新判断(robot 不持料,其他 job 可继续)
|
||
|
||
### OP40 全检检测
|
||
|
||
- 做什么:机器人把工件放到全检台,等待 PLC 确认放料完成后,再通知人工可以开始检测
|
||
- 检测方式:纯人工检测,不区分合格/不合格,系统不参与判定
|
||
- 通知时机:全检台槽位装满 或 为工单最后一件工件时,发送 M2102 信号通知 PLC
|
||
- M2102 发送时机:仅在收到 PLC 放料完成信号(FullCheckPlaceDone)后检查并发送,不在放料请求发出时提前发送
|
||
- 完成条件:人工检测完成信号
|
||
- 异常:检测超时需人工介入
|
||
- 特殊情况:全检台满时,工件暂存缓存台
|
||
|
||
### OP50 缓存暂存
|
||
|
||
- 做什么:全检台满时,机器人把工件暂存到缓存台
|
||
- 完成条件:成功放入缓存台
|
||
- 异常:缓存台也满了暂停,等全检台有空位
|
||
- 暂存完成后 robot/temp_slot 立即释放(工件在缓存台,不占用机器人,防止死锁)
|
||
|
||
### OP50_UNLOAD 缓存取料
|
||
|
||
- 做什么:全检台有空位时,机器人从缓存台取回工件,随后放全检台
|
||
- 前置条件:FULL_CHECK 有空位才取料(check),防止取料后无位可放导致 robot 假占用
|
||
- 完成条件:成功从缓存台取出,缓存台槽位释放为 empty
|
||
- 回流:取料后 robot 持料直接进入 OP40_LOAD 放全检台,不再经过 OP35 重新判断
|
||
|
||
### OP60 接驳台下料
|
||
|
||
- 做什么:机器人把成品放回接驳台托盘
|
||
- 完成条件:成品成功放入托盘
|
||
- 异常:放料失败需人工介入
|
||
- 特殊情况:接驳台目标槽位非空时拒绝放料
|
||
|
||
---
|
||
|
||
## 三、业务规则
|
||
|
||
### 接驳台
|
||
|
||
- 左右两个托盘(dock_no=1左, dock_no=2右),每托盘 42 个位置(1-42),共 84 个槽位
|
||
- 槽位状态由 `equipment_slot` 表记录,状态包括:Empty(空)、Occupied(有料)、Processing(加工中)、Done(加工完成)
|
||
- AGV 负责上料和下料(AGV 是外部系统,通过 HTTP 通讯)
|
||
|
||
**接驳台互斥占用:**
|
||
|
||
接驳台同时只能被一个角色占用(机器人/AGV/人工),防止并发操作:
|
||
|
||
| 当前占用 | 机器人取放 | AGV 进线 | AGV 离场 | 人工操作 |
|
||
|----------|:---:|:---:|:---:|:---:|
|
||
| 空闲 | 允许 | 允许 | 允许 | 允许 |
|
||
| 机器人取放中 | — | 拒绝 | 允许 | 拒绝 |
|
||
| AGV 进线中 | 拒绝 | 拒绝 | 允许 | 拒绝 |
|
||
| 人工占用中 | 拒绝 | 拒绝 | 允许 | 仅解锁 |
|
||
|
||
- 机器人取放接驳台工件时,自动标记接驳台为 ROBOT 占用,完成后自动释放
|
||
- AGV 进线时标记接驳台为 AGV 占用,离场时释放
|
||
- AGV 离场不受任何占用影响(成品需尽快离开)
|
||
- 缓存台、磨床等其他设备不需要互斥占用(只有一个机器人操作)
|
||
|
||
**接驳台完整流程:**
|
||
|
||
1. **AGV 上料**:AGV 将毛坯运到接驳台,所有槽位为毛坯(Occupied 状态)
|
||
2. **加工循环**:机器人从接驳台取毛坯 → 磨削 → 清洗 → 全检 → 放回接驳台成品
|
||
3. **槽位状态流转**:取毛坯时 Occupied→Empty,放成品时 Empty→Done
|
||
4. **AGV 下料**:接驳台所有槽位变为 Done(成品)后,通知 AGV 运走
|
||
5. **清零**:AGV 运走后,PLC 发清零信号,软件清零槽位状态
|
||
|
||
**槽位分配规则(核心):**
|
||
|
||
- 先有槽位,后分配工件
|
||
- 创建工单时,必须检查接驳台有足够的空槽位才能创建
|
||
- 槽位按从小到大顺序分配(先分配编号小的空槽位)
|
||
- 不同接驳台独立分配,互不影响
|
||
|
||
**无料暂停规则:**
|
||
|
||
- 接驳台没料时,系统不挂起工件,而是等待 AGV 送货
|
||
- 未绑定槽位的工件(CREATED 状态,PositionRefId="")不会被调度,调度器自动跳过
|
||
- 工件绑定仅由 AGV 进线事件(`handleAgvRequestEntry`)或人工「绑定槽位」触发,系统不做自动绑定轮询
|
||
- 若 MOM 工单启动时接驳台无货,`tryAutoCallMaterialOnStart` 自动触发叫料
|
||
|
||
### 磨床
|
||
|
||
- 放料时自动判断:磨床已有成品 → 换料(取走成品的同时放入毛坯);磨床空 → 直接放料
|
||
- 有料/无料状态由系统自动记录,不需要人工判断
|
||
- 放料动作本身就会触发磨床启动,不需要单独的启动信号
|
||
|
||
**磨床换料规则:**
|
||
|
||
- 首次上料:磨床为空,执行"放料"动作(不是换料)
|
||
- 正常换料:磨床有成品,执行"换料"动作(取成品+放毛坯一次完成)
|
||
- 最后一件:磨床有成品,但没有后续毛坯需要上料,执行"卸料"动作(只取不放)
|
||
- 空磨床拒绝换料:如果磨床是空的,系统不会执行换料动作,必须先走放料
|
||
|
||
### 换向机构
|
||
|
||
- 仅方形件使用,用于换向(旋转工件方向)
|
||
- 放上换向机构后 PLC 自动旋转,旋转完成发信号通知系统
|
||
|
||
### 全检台
|
||
|
||
- 纯人工检测,检测结果由人工判定,系统不判定 OK/NG
|
||
- 放料完成后,等待 PLC 确认放料完成(FullCheckPlaceDone),再检查是否需要通知检测
|
||
- 通知时机:全检台槽位装满 或 为工单最后一件工件时,发送 M2102 信号通知 PLC
|
||
- 全检台满时发布报警事件(ALARM_RAISED),管理后台可见提示「全检台已满」
|
||
|
||
### 缓存台
|
||
|
||
- 全检台满时暂存工件
|
||
- 缓存台暂存完成后,工件直接取料回流(OP50_UNLOAD),不再经过 OP35 重新判断
|
||
- 全检台完成检测出现空位后 → OP50_UNLOAD 从缓存台取工件 → OP40_LOAD 放入全检台
|
||
- 缓存台满时:OP35 判断全检台+缓存台均满 → 不推进,等待全检台有空位
|
||
|
||
### 磨床完工下游容量检查
|
||
|
||
- 磨床发出 M3600(GrinderMachiningDone)完成信号时,引擎推进到 OP20_DECIDE 决策步骤
|
||
- OP20_DECIDE 检查下游容量:全检台有空位或缓存台有空位 → 正常取料(OP20_UNLOAD)
|
||
- 全检台满 + 缓存台满 → 不取料,等待资源释放后重试(robot 不持料,防止死锁)
|
||
- 此机制由引擎的 decision 步骤天然支持,无需额外定时器轮询
|
||
|
||
### 清洗
|
||
|
||
- 机器人放料 → 启动清洗 → 等待完成 → 取走,全程机器人被占用
|
||
|
||
---
|
||
|
||
## 四、业务闭环
|
||
|
||
### 正常流程
|
||
|
||
```
|
||
创建工单 → OP10上料(取毛坯) → OP20磨削 → OP30清洗
|
||
→ OP40全检(或OP50缓存→回流OP40) → OP60下料(放成品) → 工单完成
|
||
```
|
||
|
||
### 工单开始
|
||
|
||
**前置条件:**
|
||
|
||
- 接驳台必须有足够的空槽位
|
||
- 同一产品分类不能有其他活跃工单
|
||
- 产品类型必须关联工艺路线
|
||
|
||
**创建流程(人工创建):**
|
||
|
||
1. 用户选择产品类型和数量
|
||
2. 选择接驳台(左/右托盘)
|
||
3. 系统检查接驳台空槽位数量是否足够
|
||
4. 系统创建工单(状态 Created),不创建 Job
|
||
5. 用户点击「开始工单」→ 系统创建 Job 并启动调度
|
||
6. 若接驳台无货,操作员手动叫料或放置物料后绑定槽位
|
||
|
||
**启动流程(MOM 工单自动):**
|
||
|
||
1. MOM 轮询发现新工单 → 创建工单 → 回传 MOM 已接受 → 自动叫料
|
||
2. MOM 叫料成功后,AGV 送货到接驳台
|
||
3. AGV 到达 → `handleAgvRequestEntry` 自动绑定 Job 到槽位 → 触发调度
|
||
|
||
**自动叫料触发时机:**
|
||
|
||
| 触发点 | 说明 |
|
||
|--------|------|
|
||
| MOM 轮询发现新工单 | `processMomOrder` → `momCallMaterial` |
|
||
| 手动启动 MOM 工单 | `handleStartOrder` → `tryAutoCallMaterialOnStart` |
|
||
| AGV 离场后补叫料 | `replenishMaterial`(AGV 取走成品后自动补叫下一批) |
|
||
| 人工叫料 | 前端「人工叫料」按钮 → `handleManualCallMaterial` |
|
||
|
||
**自动绑定触发时机:**
|
||
|
||
| 触发点 | 说明 |
|
||
|--------|------|
|
||
| AGV 进线 | `handleAgvRequestEntry`(事件驱动,主要路径) |
|
||
| 人工绑定 | 管理后台接驳台页面「绑定槽位」→ `handleBindDock` |
|
||
|
||
### 工单中间
|
||
|
||
**暂停条件(所有情况都暂停):**
|
||
|
||
| 暂停原因 | 说明 | 恢复条件 |
|
||
|---------|------|---------|
|
||
| 接驳台没料 | 所有槽位都是 Empty 或 Done | AGV 送来新毛坯 |
|
||
| 全检台满 | 2 个槽位全部占用 | 检测完成释放槽位 |
|
||
| 缓存台满 | 1 个槽位被占用 | 全检台释放槽位,工件回流 |
|
||
| 磨床有料加工中 | 磨床正在加工,无法上料 | 磨床加工完成 |
|
||
| 换向机构有料换向中 | 换向机构正在换向 | 换向完成 |
|
||
|
||
**工单完成前的停止规则:**
|
||
|
||
- 当工单中所有工件都已经加工完成(最后一个工件离开磨床),系统停止向磨床上料
|
||
- 但系统继续完成后续工序:清洗 → 全检 → 放回接驳台
|
||
- 所有成品都放回接驳台后,工单才算真正完成
|
||
|
||
### 工单结尾
|
||
|
||
**工单完成条件:**
|
||
|
||
- 工单中所有工件状态都是 Completed
|
||
- 所有成品都已放回接驳台
|
||
- 接驳台对应槽位状态变为 Done
|
||
|
||
**工单完成流程:**
|
||
|
||
1. 最后一个工件完成 OP60 接驳台下料
|
||
2. 工件状态变为 Completed
|
||
3. 接驳台槽位状态变为 Done
|
||
4. 检查工单中所有工件是否都已完成
|
||
5. 工单状态变为 Completed
|
||
6. 通知 AGV:"接驳台有成品可以运走"
|
||
7. 清理运行时状态
|
||
|
||
**工单取消流程:**
|
||
|
||
1. 用户发起取消工单请求
|
||
2. 将所有非终态工件标记为 Scrapped
|
||
3. 释放所有设备槽位(磨床/换向机构/全检台)
|
||
4. 释放缓存台占用
|
||
5. 释放接驳台占用(槽位恢复为 Empty)
|
||
6. 更新工单状态为 Cancelled
|
||
|
||
**收尾特殊情况:**
|
||
|
||
| 情况 | 处理方式 |
|
||
|------|----------|
|
||
| 工单全部完成 | 所有工件完成,所有成品放回接驳台,工单自动标记完成 |
|
||
| 接驳台没料暂停 | 系统暂停调度,通知 AGV 上料,AGV 到位后恢复 |
|
||
| 全检台满暂停 | 工件暂存缓存台,缓存台也满则暂停,等全检台释放 |
|
||
| 缓存台满暂停 | 暂停调度,等待全检台释放槽位 |
|
||
| 磨床最后一件 | 加工完成后只卸料,不上料 |
|
||
| 工单暂停 | 暂停后不再调度新任务,当前正在加工的工件继续完成 |
|
||
| 工单取消 | 停止所有工件,释放所有设备槽位和缓存台占用 |
|
||
| 工件异常 | 单个工件挂起,不影响其他工件,需人工处理 |
|
||
| 断电恢复 | 启动时自动恢复未完成工单,检查工件状态一致性,异常部分人工确认 |
|
||
|
||
---
|
||
|
||
## 五、AGV 交互规则
|
||
|
||
### AGV 上料触发
|
||
|
||
- 触发方式:事件驱动(MOM 叫料成功 → AGV 送货 → AGV 到达时回调 `request-entry`)
|
||
- 绑定方式:AGV 进线 `handleAgvRequestEntry` 自动绑定,或人工「绑定槽位」,系统无自动绑定轮询
|
||
- 达到后处理:`handleAgvRequestEntry` 自动绑定 Job 到槽位 → 触发 `trySchedule` 开始调度
|
||
- 幂等保护:同一接驳台已有工件时,AGV 重复进线请求直接返回成功
|
||
|
||
### AGV 下料触发
|
||
|
||
- 当接驳台所有槽位都是 Done 时,系统通知 AGV 下料
|
||
- AGV 运走后,PLC 发清零信号
|
||
- 系统收到信号后,清空槽位状态为 Empty
|
||
|
||
### AGV 离场处理
|
||
|
||
- `checkAgvDeparture` 在 MOM 轮询中检查:槽位全部空 + 无活跃工件 → 触发离场
|
||
- 离场后:清除 AGV 占用、重置接驳台槽位、清理终态工件 dock 绑定、补叫料
|
||
|
||
### AGV 通知方式
|
||
|
||
- 通过 HTTP 接口调用 AGV 系统
|
||
- 通知内容:接驳台位置、物料类型、操作类型(上料/下料)
|
||
- 系统等待 AGV 确认后再继续
|
||
|
||
---
|
||
|
||
## 六、人工操作规则
|
||
|
||
### 人工报工
|
||
|
||
未达到自动报工触发条件时,人工触发通知 AGV 取走成品:
|
||
|
||
1. 操作员点击人工报工
|
||
2. 前置校验:接驳台被机器人/AGV 占用时拒绝;同一接驳台报工成功后 60 秒内再次触发拒绝(防重复报工)
|
||
3. 系统检查该接驳台是否有成品(Completed 状态的工件)
|
||
4. 有成品 → 调用 MOM 接口通知 AGV 来取
|
||
5. AGV 到达 → 取走成品 → AGV 离场 → 占用释放
|
||
6. 无成品 → 提示"该接驳台无成品可报工"
|
||
|
||
人工报工/叫料本身不占用接驳台(不设置为 MANUAL 占用),避免阻止 AGV 进线;占用由 AGV 到达时自然发生。
|
||
|
||
### 人工叫料
|
||
|
||
人工触发通知 AGV 送来毛坯:
|
||
|
||
1. 操作员点击人工叫料
|
||
2. 前置校验:接驳台被机器人/AGV 占用时拒绝;同一接驳台叫料成功后 60 秒内再次触发拒绝(防重复叫料)
|
||
3. 以内部工单计划数量计算尚缺毛坯;分配已足够则提示"无需叫料"
|
||
4. 调用 MOM 接口叫料
|
||
5. AGV 送货 → 到达 → AGV 进线 → 占用自动切换为 AGV
|
||
|
||
### 人工占用与解锁
|
||
|
||
用于故障排查或维护时临时冻结接驳台:
|
||
|
||
1. 操作员点击人工占用 → 接驳台标记为 MANUAL 占用
|
||
2. 占用期间:机器人不能取放、AGV 不能进线(AGV 离场不受影响)
|
||
3. 排查/维护完成后 → 操作员手动解锁
|
||
4. 解锁后视情况发起人工叫料或人工报工
|
||
|
||
人工占用只有一种类型,不区分叫料/维护子场景。解锁后不自动通知 AGV,由操作员主动操作。
|
||
|
||
---
|
||
|
||
## 七、设备状态检查清单
|
||
|
||
启动或恢复生产前,必须检查以下设备状态:
|
||
|
||
| 检查项 | 检查内容 | 正常状态 | 异常处理 |
|
||
|--------|---------|---------|---------|
|
||
| 接驳台 | 槽位是否有毛坯 | 至少有一个 Occupied | 通知 AGV 上料 |
|
||
| 磨床 | 是否有工件 | Empty 或 Done | 如为 Processing,等待完成 |
|
||
| 换向机构 | 是否有工件 | Empty | 如为 Processing,等待完成 |
|
||
| 全检台 | 是否有空位 | 至少有一个 Empty | 等待检测完成 |
|
||
| 缓存台 | 是否有空位 | 至少有一个 Empty | 等待全检台释放 |
|
||
| 清洗 | 是否就绪 | Ready | 等待设备就绪 |
|
||
|
||
---
|
||
|
||
## 八、常见问题处理
|
||
|
||
### 问题:接驳台没料
|
||
|
||
**现象:** 系统暂停调度,日志显示"接驳台无可用槽位"
|
||
|
||
**处理:**
|
||
1. 检查 AGV 是否已送达毛坯
|
||
2. 检查 PLC 信号是否正常
|
||
3. 如果 AGV 未送达,手动通知 AGV 上料
|
||
4. AGV 送达后,系统自动恢复调度
|
||
|
||
### 问题:全检台满
|
||
|
||
**现象:** 工件堆积在缓存台
|
||
|
||
**处理:**
|
||
1. 通知检测人员加快检测
|
||
2. 检查检测完成信号是否正常
|
||
3. 等待全检台释放槽位
|
||
|
||
### 问题:磨床不换料
|
||
|
||
**现象:** 磨床有成品,但系统没有执行换料动作
|
||
|
||
**检查:**
|
||
1. 是否有后续毛坯等待上料
|
||
2. 缓存台是否有毛坯
|
||
3. 如果没有后续毛坯,系统只执行卸料(正常行为)
|
||
|
||
### 问题:工件挂起
|
||
|
||
**现象:** 单个工件状态变为 Suspended,调度器跳过该工件,不再为其生成任务。
|
||
|
||
**挂起原因分类:**
|
||
|
||
| 挂起原因 | 触发场景 | 严重程度 |
|
||
|----------|----------|----------|
|
||
| `order_paused` | 工单暂停,所有非终态工件随工单一并挂起 | 正常,恢复工单自动恢复 |
|
||
| `manual` | 操作员手动挂起 | 主动操作 |
|
||
| `step_timeout` | 工序超时 | 需人工介入 |
|
||
| `上料/下料/换料失败: xxx` | 机器人动作执行失败(含取料时接驳台无货) | 设备异常,需人工介入 |
|
||
|
||
**处理:**
|
||
1. 查看预警通知中的 `ACTION_FAILED` 报警,了解挂起原因
|
||
2. 人工处理异常情况(设备故障、接驳台缺料等)
|
||
3. 处理完成后恢复工件
|
||
|
||
#### 边界场景:OP10 取料失败挂起后的恢复
|
||
|
||
**发生条件:** 工件在 OP10(接驳台上料)步骤执行 `load_from_dock` 时失败,被挂起。此时工件状态为 SUSPENDED,`current_step_id` 仍为 OP10,`dock_equipment_id` / `dock_slot_no` / `position_ref_id` 均为空(或指向取料失败的槽位)。
|
||
|
||
**恢复路径与限制:**
|
||
|
||
| 场景 | 能否自动恢复 | 说明 |
|
||
|------|:---:|------|
|
||
| 恢复工件后直接调度 | 否 | 工件恢复后状态变为 PROCESSING,但无接驳台绑定(`dock_equipment_id` 为空),调度器生成 `KindLoadDock` 时无法确定目标接驳台,动作被跳过 |
|
||
| AGV 后续送货到接驳台 | 否 | AGV 送货只更新槽位状态(Empty→Occupied),不自动绑定工件。工件与槽位是独立的,调度器不知道哪个槽位属于哪个工件 |
|
||
| 管理后台人工绑定槽位 | 是 | `handleBindDock` 匹配 `CREATED` 或 `PROCESSING`(含挂起恢复后)且 `position_ref_id=""` 的工件,绑定后自动触发调度 |
|
||
| 人工绑定槽位后再恢复 | 是 | 先通过管理后台绑定槽位,再恢复工件,调度器即可正确识别 |
|
||
|
||
**正确的恢复操作顺序:**
|
||
|
||
1. 确认接驳台对应槽位已有物料(AGV 送达或人工放置)
|
||
2. 在管理后台 → 接驳台页面,选择已有物料的空槽位,点击"绑定槽位"
|
||
- `handleBindDock` 会匹配当前工单下首个 `CREATED` 或 `PROCESSING` 且未绑定的工件
|
||
3. 绑定成功后,工件获得 `dock_equipment_id`、`dock_slot_no` 等字段
|
||
4. 前端点击"恢复工件"
|
||
5. 调度器生成 `KindLoadDock` 动作,此时 `DockEquipmentID` 有效,取料正常执行
|
||
|
||
**已知限制:**
|
||
|
||
- 工件挂起后原始 `dock_equipment_id` 等字段未保留,恢复后需通过管理后台重新绑定槽位
|
||
- 若接驳台无可用物料(所有槽位为空),需等待 AGV 送货或人工放置物料后再绑定
|
||
|
||
### 问题:AGV 送货与工件绑定
|
||
|
||
**绑定时机:** 工件绑定接驳台槽位发生在工单启动后,由人工通过管理后台触发 `CmdBindDock`。
|
||
|
||
**绑定流程:**
|
||
1. 工单状态为 InProgress 时,管理后台的接驳台页面出现"绑定槽位"操作入口
|
||
2. 操作员选择接驳台的某个空槽位,点击绑定
|
||
3. `handleBindDock` 查找当前工单下首个 `status=CREATED AND position_ref_id=""` 的工件
|
||
4. 将该工件绑定到选中槽位,同时更新槽位状态为 Occupied
|
||
5. 绑定后工件获得 `dock_equipment_id`、`dock_slot_no`、`position_ref_id`,调度器可在下一轮调度中为其生成 `KindLoadDock` 动作
|
||
|
||
**绑定与挂起的交互:**
|
||
- 如果工件在绑定前已被挂起,绑定操作无法匹配到该工件(因为 status 不是 CREATED)
|
||
- 如果工件在绑定后被挂起(如取料失败),恢复后 `dock_equipment_id` 等信息可能已丢失,需重新绑定
|
||
|
||
### 问题:AGV 送货后工件自动恢复
|
||
|
||
**当前行为:** AGV 送货后,接驳台槽位状态更新为 Occupied,但挂起的工件不会自动恢复。
|
||
|
||
**原因:**
|
||
- 工件挂起是显式状态变更,需要显式恢复操作
|
||
- 系统不假设"槽位有货"等价于"工件可以取料",因为工件可能因其他原因挂起(如质量问题、设备故障)
|
||
- AGV 送货与工件调度是解耦的:AGV 负责物料搬运,EventLoop 负责工件调度
|
||
|
||
**设计意图:** 挂起是"人工介入"的信号,不应由系统自动解除。即使 AGV 补货完成,也需人工确认工件状态正常后再恢复。
|
||
|
||
## 九、事件日志(生产日志/预警通知)
|
||
|
||
所有事件经 EventBus 发布,同时推送 SSE(前端实时刷新)并异步写入 event_log 表(日志查询页)。
|
||
|
||
### 工单生命周期事件
|
||
|
||
| 事件类型 | 触发时机 | 发布位置 |
|
||
|----------|----------|----------|
|
||
| `ORDER_CREATED` | 创建工单 | create_work_order_logic.go |
|
||
| `ORDER_STARTED` | 开始工单(有活跃工件) | eventloop handleStartOrder |
|
||
| `ORDER_PAUSED` | 暂停工单 | eventloop handlePauseOrder / pause 逻辑无活跃工件分支 |
|
||
| `ORDER_RESUMED` | 恢复工单 | eventloop handleResumeOrder / resume 逻辑无活跃工件分支 |
|
||
| `ORDER_CANCELLED` | 取消工单 | eventloop handleCancelOrder / cancel 逻辑无活跃工件分支 |
|
||
| `ORDER_COMPLETED` | 工单完工 | eventloop checkOrderCompletion |
|
||
|
||
### 工件生命周期事件
|
||
|
||
| 事件类型 | 触发时机 | 发布位置 |
|
||
|----------|----------|----------|
|
||
| `JOB_COMPLETED` | 工件全部工序完成 | eventloop |
|
||
| `JOB_SCRAPPED` | 工件报废 | eventloop |
|
||
| `JOB_SUSPENDED` | 工件挂起(手动或步骤超时) | eventloop handleSuspendJob / handleStepTimeout |
|
||
| `JOB_RESUMED` | 工件恢复 | eventloop handleResumeJob |
|
||
| `JOB_REWORKED` | 工件返工 | eventloop handleReworkJob |
|
||
| `JOB_DISCHARGED` | 工件下线出料 | eventloop |
|
||
|
||
### 其他事件
|
||
|
||
- 物料流转:`LOAD`/`UNLOAD`/`EXCHANGE`/`REPLENISH`
|
||
- 加工:`MACHINE_START`/`MACHINE_DONE`/`INSPECTION_RESULT`
|
||
- 报警:`ALARM_RAISED`/`ALARM_ACKED`
|
||
- 人工交互:`MANUAL_ACTION_CREATED`/`MANUAL_ACTION_RESOLVED`
|
||
- MOM/AGV:`MOM_*`/`AGV_*`
|
||
- 缓存台:`TEMP_SLOT_CHANGED`
|
||
|
||
> 说明:任何工单/工件状态变更都必须发布对应事件,保证日志查询+预警通知能完整回溯整个生产流程。前端 `frontend/src/constants/event.ts` 与 `views/dashboard/event-log/index.tsx` 需与后端事件类型保持同步。
|
||
|
||
---
|
||
|
||
## 十、信号参考与精确时序
|
||
|
||
### 设备信号一览
|
||
|
||
#### 接驳台(Dock, equipment_id=1/8)
|
||
| 逻辑名 | 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|--------|------|------|------|
|
||
| 取料请求 | DockFetchReq | M2000 | bool | 机器人取料请求 |
|
||
| 取料位置 | DockFetchPos | M2001 | byte | 取料位置号(1-42) |
|
||
| 取料托盘 | DockFetchTray | M2002 | byte | 托盘号(1左/2右) |
|
||
| 取料完成 | DockFetchDone | M2009 | byte | PLC 取料完成 |
|
||
| 放料请求 | DockPlaceReq | M2010 | bool | 机器人放料请求 |
|
||
| 放料位置 | DockPlacePos | M2011 | byte | 放料位置号 |
|
||
| 放料托盘 | DockPlaceTray | M2012 | byte | 托盘号 |
|
||
| 放料完成 | DockPlaceDone | M2019 | byte | PLC 放料完成 |
|
||
|
||
#### 磨床(Grinder, equipment_id=2)
|
||
| 逻辑名 | 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|--------|------|------|------|
|
||
| 取料请求 | GrinderFetchReq | M2030 | bool | 机器人取成品 |
|
||
| 取料完成 | GrinderFetchDone | M2039 | byte | 取料完成 |
|
||
| 放料请求 | GrinderPlaceReq | M2040 | bool | 机器人放毛坯 |
|
||
| 放料完成 | GrinderPlaceDone | M2049 | byte | 放料完成 |
|
||
| 换料请求 | GrinderExchangeReq | M2050 | bool | 取成品+放毛坯一次完成 |
|
||
| 换料完成 | GrinderExchangeDone | M2059 | byte | 换料完成 |
|
||
| 加工完成 | GrinderMachiningDone | M3600.0 | bool | 磨削加工完成,触发取料 |
|
||
|
||
#### 换向机构(TurnTable, equipment_id=3)—— 仅方形件使用
|
||
| 逻辑名 | 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|--------|------|------|------|
|
||
| 取料请求 | TurnTableFetchReq | M2060 | bool | 机器人取料 |
|
||
| 取料完成 | TurnTableFetchDone | M2069 | byte | 取料完成 |
|
||
| 放料请求 | TurnTablePlaceReq | M2070 | bool | 放料+PLC自动旋转 |
|
||
| 放料完成 | TurnTablePlaceDone | M2079 | byte | 放料+旋转完成 |
|
||
|
||
> **注意**:转换台没有独立的旋转信号。PLC 在收到 M2070 放料请求后自动完成旋转,M2079 同时表示放料和旋转完成。
|
||
|
||
#### 清洗(Wash/AirBlow, equipment_id=4)
|
||
| 逻辑名 | 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|--------|------|------|------|
|
||
| 启动请求 | WashStartReq | M2130 | bool | 启动清洗 |
|
||
| 清洗完成 | AirBlowCompleteDone | M2139 | byte | 清洗完成 |
|
||
|
||
#### 全检台(FullCheck, equipment_id=6)
|
||
| 逻辑名 | 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|--------|------|------|------|
|
||
| 放料请求 | FullCheckPlaceReq | M2100 | bool | 机器人放料 |
|
||
| 放料位置 | FullCheckPlacePos | M2101 | byte | 位置号(1-2) |
|
||
| 放料完成 | FullCheckPlaceDone | M2109 | byte | PLC 放料完成 |
|
||
| 检测请求 | FullCheckPlaceDoneRequestInspect | M2102 | bool | 通知人工检测 |
|
||
| 检测完成 | FullCheckInspectDone | M2098 | byte | 人工检测完成 |
|
||
| 取料请求 | FullCheckFetchReq | M2090 | bool | 机器人取成品 |
|
||
| 取料位置 | FullCheckFetchPos | M2091 | byte | 位置号 |
|
||
| 取料完成 | FullCheckFetchDone | M2099 | byte | 取料完成 |
|
||
| 换料请求 | FullCheckExchangeReq | M2080 | bool | 全检台换料 |
|
||
| 换料完成 | FullCheckExchangeDone | M2089 | byte | 换料完成 |
|
||
|
||
#### 缓存台(Cache, equipment_id=5)
|
||
| 逻辑名 | 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|--------|------|------|------|
|
||
| 取料请求 | CacheFetchReq | M2110 | bool | 机器人取料 |
|
||
| 取料位置 | CacheFetchPos | M2111 | byte | 位置号 |
|
||
| 取料完成 | CacheFetchDone | M2119 | byte | 取料完成 |
|
||
| 放料请求 | CachePlaceReq | M2120 | bool | 机器人放料 |
|
||
| 放料位置 | CachePlacePos | M2121 | byte | 位置号 |
|
||
| 放料完成 | CachePlaceDone | M2129 | byte | 放料完成 |
|
||
|
||
#### 全局信号
|
||
| 信号名 | 地址 | 类型 | 说明 |
|
||
|--------|------|------|------|
|
||
| CameraWorkType | M2022 | byte | 工件类型(每组操作前写入) |
|
||
|
||
### 信号握手时序
|
||
|
||
所有 PLC 动作遵循标准的 5 步握手时序:
|
||
|
||
```
|
||
1. 写参数(如有)→ 等 1 秒
|
||
2. 写 Req=true → 触发 PLC 动作
|
||
3. 立即返回(不等待 Done)
|
||
4. PLC 执行动作 → 完成后设 Done=true
|
||
5. SignalRouter 检测到 Done → 通知引擎 → COMPLETE 阶段
|
||
```
|
||
|
||
**关键约束:**
|
||
- Go 程序只写 Req=true,绝不写 Req=false(PLC 自行管理复位)
|
||
- 两次 PLC 写操作之间至少间隔 1 秒
|
||
- Done 信号由 SignalRouter 异步监控,不在业务代码中同步等待
|
||
- 收到 Done 信号后,需等待 3 秒再发送下一个 Req(确保 PLC 读取信号)
|
||
|
||
### 各步骤精确时序
|
||
|
||
#### OP10 接驳台取料
|
||
```
|
||
前置条件:robot=idle, temp_slot=free, DOCK slot=occupied
|
||
1. ACQUIRE: 获取 robot + temp_slot + DOCK occupied 槽位(事务)
|
||
2. EXECUTE:
|
||
a. 写 M2022 = 工件类型(byte)
|
||
b. 写 M2001 = 位置号(byte)
|
||
c. 写 M2002 = 托盘号(byte)
|
||
d. 等 1 秒
|
||
e. 写 M2000 = true(取料请求)
|
||
3. WAIT: 等 M2009 Done(byte≠0)
|
||
4. COMPLETE:
|
||
a. 释放 robot → idle
|
||
b. temp_slot → occupied(工件在缓存槽)
|
||
c. DOCK slot → empty
|
||
```
|
||
|
||
#### OP20 磨床放料(圆形件)/ OP25 转换台放料(方形件)
|
||
```
|
||
前置条件:robot=idle, 目标设备 slot=empty
|
||
1. ACQUIRE: 获取 robot + 目标设备 empty 槽位
|
||
2. EXECUTE:
|
||
a. 写 M2022 = 工件类型
|
||
b. 写 PlaceReq = true
|
||
c. 等 1 秒
|
||
3. WAIT: 等 PlaceDone
|
||
4. COMPLETE:
|
||
a. 释放 robot → idle
|
||
b. 释放 temp_slot → free
|
||
c. 目标设备 slot → occupied
|
||
```
|
||
|
||
#### OP20_WAIT 磨床等待加工
|
||
```
|
||
前置条件:GRINDER slot=occupied(确认工件在磨床上)
|
||
1. ACQUIRE: check GRINDER occupied(无资源获取)
|
||
2. EXECUTE: 无信号发送(纯等待)
|
||
3. WAIT: 等 M3600.0 GrinderMachiningDone
|
||
4. COMPLETE:
|
||
a. GRINDER slot → done(加工完成,等待取料)
|
||
```
|
||
|
||
#### OP20_UNLOAD 磨床取料
|
||
```
|
||
前置条件:robot=idle, temp_slot=free, GRINDER slot=done
|
||
1. ACQUIRE: 获取 robot + temp_slot + GRINDER done 槽位
|
||
2. EXECUTE: 写 GrinderFetchReq → 等 GrinderFetchDone
|
||
3. COMPLETE:
|
||
a. 释放 robot → idle
|
||
b. temp_slot → occupied(工件在缓存槽)
|
||
c. GRINDER slot → empty
|
||
```
|
||
|
||
#### OP30 清洗(工件在机器人夹爪上)
|
||
```
|
||
前置条件:robot=idle(持有中), temp_slot=occupied
|
||
1. ACQUIRE: 获取 robot + temp_slot occupied
|
||
2. EXECUTE: 写 WashStartReq → 等 AirBlowCompleteDone
|
||
3. COMPLETE:
|
||
a. 释放 temp_slot → free
|
||
b. robot 不释放!held_by_job_id 机制保证跨步骤持料
|
||
```
|
||
|
||
#### OP35 全检台容量判断(决策步骤)
|
||
```
|
||
前置条件:无(决策步骤不获取资源)
|
||
1. 查询 FULL_CHECK empty 槽位数
|
||
2. 分支1: empty >= 1 → 跳转 OP40_LOAD(全检放料)
|
||
3. 分支2: CACHE empty >= 1 → 跳转 OP50_LOAD(缓存暂存,全检台满时)
|
||
4. 都不匹配(全检台+缓存台均满)→ 等待资源变更后重试
|
||
```
|
||
|
||
#### OP20_DECIDE 磨床下游容量判断(决策步骤)
|
||
```
|
||
前置条件:无(决策步骤不获取资源)
|
||
1. 查询 FULL_CHECK empty 槽位数
|
||
2. 分支1: FULL_CHECK empty >= 1 → 跳转 OP20_UNLOAD(正常取料)
|
||
3. 分支2: CACHE empty >= 1 → 跳转 OP20_UNLOAD(正常取料)
|
||
4. 都不匹配(全检台+缓存台均满)→ 等待资源变更后重试
|
||
```
|
||
|
||
#### OP40 全检台放料
|
||
```
|
||
前置条件:robot=idle, temp_slot=occupied, FULL_CHECK slot=empty
|
||
1. ACQUIRE: 获取 robot + temp_slot + FULL_CHECK empty 槽位
|
||
2. EXECUTE:
|
||
a. 写 M2022 = 工件类型(byte)
|
||
b. 写 M2101 = 位置号(byte)
|
||
c. 等 1 秒
|
||
d. 写 M2100 = true(放料请求)
|
||
3. WAIT: 等 M2109 Done(byte≠0)
|
||
4. COMPLETE:
|
||
a. 释放 robot → idle
|
||
b. 释放 temp_slot → free
|
||
c. FULL_CHECK slot → occupied
|
||
d. 发送 M2102(通知人工检测)
|
||
```
|
||
|
||
#### OP40_WAIT 全检台等待检测
|
||
```
|
||
前置条件:FULL_CHECK slot=occupied
|
||
1. ACQUIRE: check FULL_CHECK occupied
|
||
2. WAIT: 等 FullCheckInspectDone(M2098)
|
||
3. COMPLETE: FULL_CHECK slot → done
|
||
```
|
||
|
||
#### OP60 接驳台下料
|
||
```
|
||
前置条件:robot=idle, temp_slot=occupied, DOCK slot=empty
|
||
1. ACQUIRE: 获取 robot + temp_slot + DOCK empty 槽位
|
||
2. EXECUTE: 写 DockPlaceReq → 等 DockPlaceDone
|
||
3. COMPLETE:
|
||
a. 释放 robot → idle
|
||
b. 释放 temp_slot → free
|
||
c. DOCK slot → done(等待 AGV 取走)
|
||
```
|
||
|
||
### 工艺路线对比
|
||
|
||
#### 缸体工艺(圆形件,recipe_id=1)
|
||
```
|
||
OP10_LOAD(接驳台取料) → OP20_LOAD(磨床放料) → OP20_WAIT(等M3600)
|
||
→ OP20_DECIDE(下游容量判断) → OP20_UNLOAD(磨床取料) → OP30_LOAD(清洗)
|
||
→ OP35_DECIDE(容量判断) → OP40_LOAD(全检放料) / OP50_LOAD(缓存暂存→回流OP35)
|
||
→ OP40_WAIT(等M2098) → OP40_UNLOAD(全检取料) → OP60_LOAD(接驳台下料)
|
||
```
|
||
|
||
#### 配油盘工艺(方形件,recipe_id=2)
|
||
```
|
||
OP10_LOAD(接驳台取料) → OP25_TURN_LOAD(转换台放料+旋转)
|
||
→ OP25_TURN_UNLOAD(转换台取料) → OP20_LOAD(磨床放料)
|
||
→ OP20_WAIT(等M3600) → OP20_DECIDE(下游容量判断) → OP20_UNLOAD(磨床取料)
|
||
→ OP30_LOAD(清洗) → OP35_DECIDE(容量判断) → OP40_LOAD / OP50_LOAD(缓存暂存) → OP50_UNLOAD(缓存取料)
|
||
→ OP40_WAIT → OP40_UNLOAD → OP60_LOAD(接驳台下料)
|
||
```
|
||
|
||
**区别:** 方形件在磨床放料前多了转换台放料+旋转+取料三步(OP25_TURN_LOAD + OP25_TURN_UNLOAD)。
|