OEE 综合设备效率服务
概述
OEE (Overall Equipment Effectiveness) 是衡量生产效率的核心 KPI, 由稼动率 × 性能率 × 合格率三项相乘得到, 单位 %。世界级工厂 OEE ≥ 85%, 普通工厂 50-60%, 连 40% 都达不到说明产线有系统性问题。
DarraRT 内置 Darra.OEE.Service 子服务, 基于 PLC 状态变量 + 计数器 + 故障码自动计算, 支持班次 / 日 / 周 / 月多层汇总, 配合 HMI 大屏实时显示。
OEE = 稼动率 (Availability) × 性能率 (Performance) × 合格率 (Quality)
公式
| 分项 | 公式 | 典型值 |
|---|---|---|
| 稼动率 | 实际运行时间 / 计划生产时间 | 85-95% |
| 性能率 | (实际产量 × 标准节拍) / 实际运行时间 | 80-90% |
| 合格率 | 合格数 / 总产量 | 95-99% |
| OEE | 三者相乘 | 70-85% |
定义细化:
- 计划生产时间 = 班次时长 − 计划停机 (用餐 / 换模 / 计划保养)
- 实际运行时间 = 计划生产时间 − 非计划停机 (故障 / 待料 / 换线)
- 标准节拍 (Ideal Cycle Time) = 设计产能对应的单件时间
- 合格数 = 总产量 − 不良 − 返工
适用场景
| 场景 | 数据源 | 汇总粒度 |
|---|---|---|
| 单工位 OEE | PLC 状态 + 计数 | 实时 / 小时 / 班次 |
| 单设备 / 单元 OEE | 本机多工位瓶颈 | 班次 / 日 |
车间 / 厂级的跨产线、多车间 OEE 汇总属于上层 MES 职责。DarraRT 只计算本机/本单元的 OEE, 并通过 OPC UA 把这些指标暴露给上层 MES/SCADA 做跨线汇总。
架构图
┌────────── PLC ──────────┐
│ - RunState (BOOL) │
│ - FaultCode (WORD) │
│ - ProduceCount (DINT) │ ── 每秒采样 ──► ┌─────────────┐
│ - RejectCount (DINT) │ │ OEE.Service │
│ - CycleMs (DINT) │ │ (FB调用 + SQL) │
│ - ShiftPlan (STRUCT) │ └──────┬──────┘
└─────────────────────────┘ │
▼
┌───────────────────────┐
│ t_oee_minute (分钟级) │
│ t_oee_shift (班次级) │
│ t_oee_day (日级) │
└─────────┬─────────────┘
│ API / HMI
▼
┌───────────────────────┐
│ <darra-dx-speedometer>│
│ <darra-trend> │
└───────────────────────┘
前置条件
- PLC 程序已声明
RunState / FaultCode / ProduceCount / RejectCount / CycleMs - 班次计划表已录入
t_shift_plan - 标准节拍已标定 (每个产品型号不同)
详细步骤
步骤 1: PLC 侧状态机
// 运行状态枚举 (与 OEE 服务约定)
TYPE E_RunState : (
IDLE := 0, // 空闲/待机 (非计划停机)
RUN := 1, // 正常生产
FAULT := 2, // 故障
PAUSE := 3, // 计划停机 (换模/保养/餐休)
BLOCKED := 4, // 堵料 (下游满)
STARVED := 5 // 待料 (上游空)
);
END_TYPE
VAR_GLOBAL
DB_OEE : STRUCT
state : E_RunState;
fault_code : WORD;
produce_count : DINT;
reject_count : DINT;
cycle_ms : DINT; // 最近一次周期时间
ideal_cycle_ms: DINT := 1200; // 标准节拍
shift_start : DT;
shift_end : DT;
END_STRUCT
END_VAR
步骤 2: FB_OEECalculator 功能块
FUNCTION_BLOCK FB_OEECalculator
VAR_INPUT
runState : E_RunState;
faultCode : WORD;
produceCount : DINT;
rejectCount : DINT;
idealCycleMs : DINT;
sampleIntervalMs : DINT := 1000; // 调用周期
END_VAR
VAR_OUTPUT
Availability : REAL; // 0..100
Performance : REAL; // 0..100
Quality : REAL; // 0..100
OEE : REAL; // 0..100
END_VAR
VAR
// 时间累积 (ms)
plannedMs : DINT;
runMs : DINT;
faultMs : DINT;
pauseMs : DINT;
// 产量累积
totalProduced : DINT;
totalRejected : DINT;
// 上次调用的计数, 用来算 delta
lastProduce : DINT;
lastReject : DINT;
lastState : E_RunState;
END_VAR
// 1. 时间统计 (每调用一次累加 sampleIntervalMs)
CASE runState OF
RUN: runMs := runMs + sampleIntervalMs;
FAULT: faultMs := faultMs + sampleIntervalMs;
PAUSE: pauseMs := pauseMs + sampleIntervalMs;
IDLE, BLOCKED, STARVED:
// 这些算作非计划停机, 不计入运行, 但计入"计划生产时间"
;
END_CASE;
// 计划生产时间 = 所有时间 - 计划停机
plannedMs := plannedMs + sampleIntervalMs;
IF runState = PAUSE THEN
// 计划停机不计入
plannedMs := plannedMs - sampleIntervalMs;
END_IF;
// 2. 产量增量
totalProduced := totalProduced + (produceCount - lastProduce);
totalRejected := totalRejected + (rejectCount - lastReject);
lastProduce := produceCount;
lastReject := rejectCount;
// 3. 三率计算
IF plannedMs > 0 THEN
Availability := 100.0 * DINT_TO_REAL(runMs) / DINT_TO_REAL(plannedMs);
ELSE
Availability := 0.0;
END_IF;
IF runMs > 0 AND totalProduced > 0 THEN
Performance := 100.0 *
(DINT_TO_REAL(totalProduced) * DINT_TO_REAL(idealCycleMs))
/ DINT_TO_REAL(runMs);
IF Performance > 100.0 THEN Performance := 100.0; END_IF;
ELSE
Performance := 0.0;
END_IF;
IF totalProduced > 0 THEN
Quality := 100.0 * DINT_TO_REAL(totalProduced - totalRejected)
/ DINT_TO_REAL(totalProduced);
ELSE
Quality := 0.0;
END_IF;
OEE := Availability * Performance * Quality / 10000.0;
lastState := runState;
步骤 3: Service 侧汇总
Service 每分钟把 FB 累积的 plannedMs / runMs / totalProduced / totalRejected 快照落库, 同时重置 FB 计数器。
// Darra.PLC.Service / OEE / OeeAggregator.cs
public async Task FlushMinuteAsync(DateTime ts)
{
var snap = _plc.Read<OeeSnapshot>("DB_OEE.snapshot");
await _db.ExecuteAsync(@"
INSERT INTO t_oee_minute(ts, device_id, planned_ms, run_ms,
fault_ms, pause_ms,
produced, rejected,
availability, performance, quality, oee)
VALUES (@ts, @dev, @planned, @run,
@fault, @pause,
@produced, @rejected,
@a, @p, @q, @oee)
", new { ts, dev = _deviceId, /* ... */ });
_plc.ResetCounters("FB_OEE");
}
// 班次/日 汇总由定时 Job 从 t_oee_minute 聚合上卷
步骤 4: 数据库 Schema
CREATE TABLE t_oee_minute (
ts TIMESTAMPTZ NOT NULL,
device_id TEXT NOT NULL,
planned_ms BIGINT,
run_ms BIGINT,
fault_ms BIGINT,
pause_ms BIGINT,
produced INTEGER,
rejected INTEGER,
availability NUMERIC(5,2),
performance NUMERIC(5,2),
quality NUMERIC(5,2),
oee NUMERIC(5,2),
PRIMARY KEY (ts, device_id)
);
CREATE TABLE t_oee_shift (
shift_id BIGINT PRIMARY KEY,
shift_code TEXT NOT NULL, -- A班/B班/C班
device_id TEXT NOT NULL,
start_ts TIMESTAMPTZ NOT NULL,
end_ts TIMESTAMPTZ NOT NULL,
availability NUMERIC(5,2),
performance NUMERIC(5,2),
quality NUMERIC(5,2),
oee NUMERIC(5,2),
produced INTEGER,
rejected INTEGER
);
CREATE TABLE t_oee_day (
date DATE NOT NULL,
device_id TEXT NOT NULL,
oee NUMERIC(5,2),
-- ... 同上
PRIMARY KEY (date, device_id)
);
步骤 5: HMI 大屏展示
HMI 大屏用三组速度表 + 一个 OEE 仪表 + 趋势图:
<darra-dx-speedometer
bind-value="oee.availability"
min="0" max="100"
ranges='[{"start":0,"end":60,"color":"red"},
{"start":60,"end":85,"color":"orange"},
{"start":85,"end":100,"color":"green"}]'
label="稼动率 %">
</darra-dx-speedometer>
<darra-dx-speedometer bind-value="oee.performance" label="性能率 %"/>
<darra-dx-speedometer bind-value="oee.quality" label="合格率 %"/>
<darra-dx-gauge bind-value="oee.oee" label="OEE"
ranges='[{"end":50,"color":"red"},
{"end":70,"color":"orange"},
{"end":85,"color":"yellow"},
{"end":100,"color":"green"}]'/>
<darra-trend
api="/api/oee/trend?device=L1&range=24h&bucket=1h"
series='["availability","performance","quality","oee"]'
title="近 24 小时 OEE 趋势"/>
步骤 6: API
GET /api/oee/current?device=L1
→ {"availability":92.3,"performance":88.1,"quality":98.5,"oee":80.1}
GET /api/oee/shift?device=L1&date=2026-04-18
→ [{"shift":"A","oee":82.1},{"shift":"B","oee":78.4},...]
GET /api/oee/trend?device=L1&range=7d&bucket=1d
→ [{"ts":"2026-04-12","oee":79.5}, ...]
GET /api/oee/reasons?device=L1&shift=A&date=2026-04-18
→ [{"reason":"机械故障","duration_min":42,"count":3},...]
排错与解读
| 现象 | 可能原因 |
|---|---|
Availability 低 (<80%) | 故障多 / 换线慢 / 待料频繁 |
Performance 低 (<80%) | 实际节拍慢于标准 / 微停机 |
Quality 低 (<95%) | 工艺不稳 / 来料差 / 人为 |
| OEE 一直 100% | 标准节拍定得太松, 不真实 |
| OEE 跳变 | 计数器没清零 / 班次切换时序错 |
高级技巧
- 瓶颈识别: 多工位产线 OEE 的最低者就是瓶颈, 优先改善
- 六大损失归因: 故障 / 换模 / 空转 / 减速 / 启动 / 不良, 每类单独统计
- 标准节拍动态: 按产品型号查表, 不同批次用不同
idealCycleMs - 微停机捕获:
<5min的小停机传统数采抓不到, DarraRT 1s 采样能抓 - 与 SPC 联动: 合格率跌 → SPC 异常触发 → 自动排故