Files
bj_power/bj_power_mes/自动化流程.md
T

159 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 自动化生产线管控系统 — 框架流程说明
> 本文档描述框架级的自动化流程,不包含具体产线设备或工艺的业务细节。
> 具体业务内容(设备清单、工艺步骤、业务规则)见 `agent业务.md` 和 `doc/data.sql`。
> 全配置化流程引擎设计见 `流程文档.md`,引擎作为纯执行器,所有业务逻辑通过数据库配置驱动。
---
## 软件架构核心概念
### Actor(设备代理,纯内存)
每台物理设备对应一个 **MachineActor**(统一实现),通过 `Type` 字段适配不同设备类型。Actor 是 mutex 保护的同步状态结构体,由 EventLoop 同步调用。负责:
- **管理槽位状态**:当前槽位上有无工件、哪个工件
- **处理 PLC 信号**:收到完成信号后,把槽位状态改为 DONE
Actor 不写数据库、不调度、不操作 PLC。
### PlcExecutorPLC 信号握手)
`PlcExecutor` 封装所有设备类型的 PLC 信号握手时序,通过方法名区分不同操作。负责:
- **Load**:将工件放入设备槽位(写 Req → 等 Done → 复位 Req
- **Unload**:从设备槽位取出工件
- **Exchange**:同时取成品+放毛坯(仅支持 exchange 的设备类型)
### Recipe(工艺配方)
每种工件型号定义一份 Recipe(加工步骤有序列表)。每个步骤包含:
- 工序类型(MACHINING / INSPECTION / BUFFER_STAGE / …)
- 资源类型(指定需要的设备种类)
- 默认下一步步骤编号
Recipe 是静态配置,启动时加载到内存。工件实例只记录当前步骤,不复制整份配方。
### SignalRouter(信号路由,`actor/signal_router.go`
- 每秒轮询 PLC 输入寄存器,检测上升沿变化
- 根据信号找到对应 Actor,投递 SignalEvent 到 EventLoop
- 信号是系统的输入,触发状态机迁移,但信号本身不是状态源
### EventLoop(事件循环,`eventloop/loop.go`
产线大脑,运行在独立 goroutine 中,**串行处理**所有生产事件:
- 来自 PLC 的设备信号 → 更新 Actor 槽位状态 → 投递 MACHINE_DONE → 推进步骤
- 触发调度器 → 决策下一步动作
- 下发动作指令 → PlcWorker 执行
- 处理执行结果 → 推进 Job 步骤 → 触发下一轮调度
- **唯一写数据库的入口**
### Scheduler(调度器,`scheduler/`
三层管道,只读不写:
1. **TaskGenerator**:根据 Job 当前步骤生成候选动作
2. **ConstraintFilter**:排除不可用设备、冲突、暂停工单等
3. **PolicyEngine**:按优先级排序,选出最优方案
一次调度只派遣一个 Worker 动作,确保机器人串行执行。
### PlcWorkerPLC 执行器,`plc_worker.go`
按 Action 类型调用 PlcExecutor 对应方法,执行 PLC 信号握手。
### EventBus(事件总线,`eventbus/`
组件间解耦通信,当前实现为内存 LocalBus。订阅者:
- EventLogWriter:异步写入数据库,用于审计和恢复
- SSEBridge:推送到前端看板
- AlarmService:告警通知
---
## 自动化流程(框架级)
### 阶段一:上料
```
操作员创建工单 → 系统创建 N 个 Job(工件实例)
→ 调度器发现 Job 就绪
→ 下发上料动作 → PlcWorker → PlcExecutor.DockFetch
→ 搬运设备从接驳台取件 → 扫码
```
**扫码结果分支:**
- **成功** → 分配暂存台空闲槽位,状态推进
- **失败** → 放回原接驳台槽位,挂起,等待人工处理
### 阶段二:加工
```
暂存台有料 → 调度器选择加工设备
→ PlcWorker → PlcExecutor.GrinderPlace(上料)
→ 设备开始加工
→ 加工完成 → PLC 发送完成信号
→ SignalRouter 检测上升沿 → 投递 SignalEvent → EventLoop
→ MachineActor.MarkSlotDone → 槽位状态 PROCESSING → DONE
→ 调度器得知"有工件待取走"
→ PlcWorker → PlcExecutor.GrinderFetch(卸料)
→ 工件放回暂存台
```
**Exchange 换料优化:** 支持 exchange 的设备可一次往返同时完成"取成品 + 放毛坯"。
### 阶段三:检测
```
暂存台有料 → 调度器选择检测设备
→ PlcWorker → PlcExecutor.FullCheckPlace(上料)
→ 设备开始检测
→ 检测完成 → PLC 发送结果信号(OK / NG)
→ SignalRouter → EventLoop → MachineActor.MarkSlotDone
→ 判定结果分支:
├── OK → 推进到下一步工序
└── NG → 报废处理
```
### 阶段四:下料
```
暂存台有料 → 调度器决定去向
→ PlcWorker → PlcExecutor.DockPlace(下料)
→ 搬运设备放到接驳台 → 送走
```
---
## 信号触发点(框架级)
| 信号类型 | 触发时机 | 处理方 | 产生结果 |
|----------|---------|--------|---------|
| 设备完成信号 | 加工/检测完成 | EventLoop.handleMachineSignal → Actor.MarkSlotDone | 槽位状态 OCCUPIED → DONE,投递 MACHINE_DONE |
| 调度触发 | 定时器/Worker完成 | EventLoop.trySchedule | 调度决策,派遣 Worker 动作 |
具体信号名称和地址见 `doc/signals.sql`
---
## 关键设计原则
1. **事件驱动,不预排任务** — 每个工件只记录当前步骤,下一步由事件触发实时决策
2. **PLC 信号是输入,不是状态源** — 系统以数据库中的状态为准,PLC 信号只用来触发状态迁移
3. **Actor 只管槽位和信号** — 不做调度决策,不写数据库,由 EventLoop 同步调用
4. **PlcExecutor 封装 PLC 握手** — 所有设备类型的 PLC 操作统一通过 PlcExecutor 方法实现,信号地址校验前置
5. **调度器只读不写** — 查询状态做决策,下发任务,不直接操作硬件或数据库
6. **EventLoop 是唯一写路径** — 所有生产状态变更必须经过 EventLoop → DBState
7. **防御式编程** — 所有错误必须有日志记录或向上抛出,禁止隐性失败
---
## 技术栈
- 后端:Go 1.23.4 + go-zero v1.3.8
- 数据库:PostgreSQL + ent ORM
- 缓存/Token 存储:Redis(可选,未配置时降级内存)
- PLC 通信:Snap7(西门子 S7 协议)
- 前端:React 19 + Semi Design + Zustand + Vite 7
## 代码生成
- 生成 ent`cd schema && go generate`
- 生成 go-zero API`cd apis && go generate`
## 全局规则
- 不要在 `handler` 写业务逻辑,保持薄层
- 不要手动修改 `ent/``cmd/control-api/internal/handler/routes.go``types/types.go`、goctl 生成的 handler
- 所有 API 变更先改 `apis/*.api`,再生成代码
- 所有 schema 变更先改 `schema/`,再生成 ent