称重仪表与定量控制
1. 设备简介
定量配料机是粮油饲料、化工、医药、建材 (水泥搅拌站)、食品行业最常见的计量设备, 通过多料仓独立下料实现精确配方。典型形态为 1 主料大仓 + 3 副料小仓, 按配方自动下料到搅拌釜或包装袋, 精度要求 ±0.5% 甚至 ±0.1% (OIML C3 级)。本案例以4 料仓配料机为对象 (主仓 1000 kg, 副仓 50 kg × 3), 读取 4 台宝山 XK3190-DS3 称重仪表 (Modbus RTU, 50 Hz 刷新), 使用快加/慢加/落差补偿三段式下料避免冲料超差, 配方管理 32 组, 单袋数据自动写入 SQLite 并提供手机对账界面, 具备防作弊 HMAC 签名。
2. 项目模块组成
- 机械部分: 4 个料仓 + 快加/慢加/排空阀 × 4 + 总放料阀 + 搅拌釜或包装头
- 电气部分: 研华工控机 + 汇川 IO × 2 + 宝山 XK3190-DS3 仪表 × 4 + 柯力称重模块 + 亚德客电磁阀
- 软件部分: OB30 Modbus 通讯 + OB1 主循环 + FB_FillSequence/RecipeManager/Traceability + DB_Recipe/Batch/Silo
3. 机械装配架构
上料从顶部气力输送进入上料斗, 分配到 4 个料仓。每个料仓下方安装 DN100 快加阀 (粗流) 与 DN50 慢加阀 (精流), 独立控制下料速度。下料完成后总放料阀打开统一进入搅拌釜混合, 再经包装头计重装袋。大仓采用 3 只并联称重模块提高量程稳定性, 小仓单只传感器即可。
4. 程序架构
OB30 每 20 ms 通过 Modbus RTU 读取 4 台称重仪表的净重值 (50 Hz 刷新), OB1 执行下料状态机与配方管理。每完成一袋, FB_Traceability 写入 SQLite 并附带 HMAC 签名, 防止事后篡改。
5. 硬件选型 BOM
| 品牌 | 型号 | 数量 | 单价 (¥) | 用途 |
|---|---|---|---|---|
| 研华 | MIO-5272 工控机 | 1 | 3,000 | 主控 |
| 汇川 | AM600-1616END | 2 | 850 | DI/DO 32 点 |
| 宝山 | XK3190-DS3 仪表 | 4 | 1,800 | 4 仓称重 Modbus |
| 柯力 | QS-D 2t 称重模块 | 3 | 450 | 大仓 3 只并联 |
| 柯力 | QS-A 500 kg | 3 | 280 | 3 副仓 |
| 国产通用 | DN100 气动蝶阀 | 4 | 320 | 快加阀 |
| 国产通用 | DN50 气动蝶阀 | 4 | 180 | 慢加阀 |
| 国产通用 | DN100 排空阀 | 4 | 320 | 排空 |
| 亚德客 | 5 位 2 通电磁阀 | 12 | 65 | 气动驱动 |
| 威纶通 | TK6071iP | 1 | 1,100 | 本地 HMI |
| 研华 | RS485 隔离转换器 | 1 | 180 | Modbus |
| 明纬 | LRS-200-24 | 1 | 240 | 24V |
6. IO 模块配置
6.1 选择 IO 模块
IDE 项目树 > IO 设备 > 右键 > 添加 IO 设备:
- 从站 1: 汇川 AM600-1616END — 12 阀门 + 启停按钮
- 从站 2: 汇川 AM600-1616END — 料位传感器 + 指示灯 + 扩展
称重仪表通过 通讯 > Modbus RTU 主站 添加 4 台 Slave (SlaveId = 1/2/3/4), 波特率 9600, 8N1。
6.2 IO 地址分配
| 地址 | 模块 | 信号 | 用途 |
|---|---|---|---|
| %IX0.0 | 从站 1 | SB_Start | 启动 |
| %IX0.1 | 从站 1 | SB_Stop | 停止 (常闭) |
| %IX0.2 | 从站 1 | SB_EStop | 急停 (常闭) |
| %IX0.3 | 从站 1 | LS_Hopper_Full | 上料斗满 |
| %IX0.4 | 从站 1 | LS_Hopper_Empty | 空 |
| %IX0.5~0.8 | 从站 1 | Silo_Empty[0..3] | 各料仓空料 |
| %QX0.0~0.3 | 从站 1 | V_Fast[0..3] | 快加阀 |
| %QX0.4~0.7 | 从站 1 | V_Slow[0..3] | 慢加阀 |
| %QX1.0~1.3 | 从站 1 | V_Dump[0..3] | 排空阀 |
| %QX1.4 | 从站 1 | V_Discharge | 总放料 |
| %QX1.5 | 从站 2 | Pump_Air | 气动泵 |
| %QX2.0 | 从站 2 | HL_Run | 运行灯 |
| %QX2.1 | 从站 2 | HL_Fault | 故障灯 |
| %QX2.2 | 从站 2 | Buzzer | 完成蜂鸣 |
6.3 IO 用途分工
- PLC 主控: 三段式下料状态机 + 配方管理 + 追溯写入, 全部在 PLC 完成
- 称重数据: 通过 Modbus 读取仪表净重, 不经模拟量, 精度优势显著
- 防作弊: 每袋追溯记录附 HMAC 签名, 即使数据库被复制也无法伪造
- 安全链: 急停 + 停止 + 低水位 (上料斗) 全部接 DI 常闭触点
6.4 对接 MES / ERP (追溯)
在 通讯 > OPC UA 服务端 配置以下变量给 ERP 订阅:
gBat.aRecipes[*].sName: 配方名gBat.nBagSeq: 当前批次已下袋数gBat.aSilos[0..3].rActualKg: 各仓实际下料量gBat.nBatchId: 批次号
ERP 接单后下发配方号到 PLC, PLC 按 nTargetBags 自动生产, 每袋完成后回传实重 + 时间戳 + 签名到 ERP 追溯库。
7. 核心数据结构
TYPE UDT_Silo:
STRUCT
rTargetKg : REAL;
rActualKg : REAL;
rFastEnd : REAL;
rSlowEnd : REAL;
rOvershoot : REAL; // 落差 (动态学习)
aRecent : ARRAY[0..4] OF REAL;
eStep : INT; // 0=idle 1=fast 2=slow 3=dwell 4=done
bDone : BOOL;
nFillCount : DINT; // 累计袋数 (Retain)
END_STRUCT
END_TYPE
TYPE UDT_Recipe:
STRUCT
sName : STRING[32];
aWeights : ARRAY[0..3] OF REAL;
nTotalKg : REAL;
nBags : DINT;
END_STRUCT
END_TYPE
TYPE UDT_Batcher:
STRUCT
aRecipes : ARRAY[0..31] OF UDT_Recipe;
nCurRecipe : INT;
aSilos : ARRAY[0..3] OF UDT_Silo;
eState : INT;
nBagSeq : DINT;
nTargetBags : DINT;
bBatchDone : BOOL;
nBatchId : DINT;
END_STRUCT
END_TYPE
VAR_GLOBAL RETAIN
gBat : UDT_Batcher;
END_VAR
8. 核心程序代码
FB_ModbusRTU — OB30 20 ms 读 4 仪表:
FUNCTION_BLOCK FB_ReadScales
VAR
fbRead : MB_ReadHolding;
i : INT;
END_VAR
FOR i := 0 TO 3 DO
// XK3190-DS3 净重寄存器 0x0001 (4 字节浮点)
fbRead(Port := MB_PORT_1, SlaveId := i+1,
StartReg := 16#0001, Count := 2,
Target := gBat.aSilos[i].rActualKg);
END_FOR;
FB_FillSequence — 单仓三段式下料 (快加 → 慢加 → 静置 → 完成):
FUNCTION_BLOCK FB_FillSequence
VAR_INPUT
siloIdx : INT;
END_VAR
VAR
tonDwell : TON;
i : INT;
rTarget, rActual : REAL;
END_VAR
rTarget := gBat.aRecipes[gBat.nCurRecipe].aWeights[siloIdx];
rActual := gBat.aSilos[siloIdx].rActualKg;
CASE gBat.aSilos[siloIdx].eStep OF
0: // 空闲 → 启动快加
IF gBat.eState = 1 AND rTarget > 0.01 THEN
gBat.aSilos[siloIdx].rTargetKg := rTarget;
gBat.aSilos[siloIdx].rFastEnd := rTarget * 0.85;
gBat.aSilos[siloIdx].rSlowEnd := rTarget - gBat.aSilos[siloIdx].rOvershoot;
gBat.aSilos[siloIdx].eStep := 1;
END_IF;
1: // 快加
V_Fast[siloIdx] := TRUE;
V_Slow[siloIdx] := TRUE;
IF rActual >= gBat.aSilos[siloIdx].rFastEnd THEN
V_Fast[siloIdx] := FALSE;
gBat.aSilos[siloIdx].eStep := 2;
END_IF;
2: // 慢加
V_Slow[siloIdx] := TRUE;
IF rActual >= gBat.aSilos[siloIdx].rSlowEnd THEN
V_Slow[siloIdx] := FALSE;
gBat.aSilos[siloIdx].eStep := 3;
END_IF;
3: // 静置 3 秒 + 落差学习
tonDwell(IN := TRUE, PT := T#3s);
IF tonDwell.Q THEN
tonDwell(IN := FALSE);
FOR i := 0 TO 3 DO
gBat.aSilos[siloIdx].aRecent[i] := gBat.aSilos[siloIdx].aRecent[i+1];
END_FOR;
gBat.aSilos[siloIdx].aRecent[4] := rActual - rTarget;
// 最近 5 次平均 = 新落差
gBat.aSilos[siloIdx].rOvershoot :=
(gBat.aSilos[siloIdx].aRecent[0] + gBat.aSilos[siloIdx].aRecent[1] +
gBat.aSilos[siloIdx].aRecent[2] + gBat.aSilos[siloIdx].aRecent[3] +
gBat.aSilos[siloIdx].aRecent[4]) / 5.0;
gBat.aSilos[siloIdx].nFillCount := gBat.aSilos[siloIdx].nFillCount + 1;
gBat.aSilos[siloIdx].eStep := 4;
END_IF;
4: // 完成
gBat.aSilos[siloIdx].bDone := TRUE;
END_CASE;
FB_Traceability — 追溯记录 + HMAC 签名:
FUNCTION_BLOCK FB_Traceability
VAR_INPUT
bBagDone : BOOL;
END_VAR
VAR
rTotal : REAL;
END_VAR
IF bBagDone THEN
rTotal := gBat.aSilos[0].rActualKg + gBat.aSilos[1].rActualKg +
gBat.aSilos[2].rActualKg + gBat.aSilos[3].rActualKg;
// Darra 内置日志 API (伪代码)
LogEvent('BATCH_BAG_DONE', {
batch := gBat.nBatchId,
bag := gBat.nBagSeq,
recipe := gBat.aRecipes[gBat.nCurRecipe].sName,
w0 := gBat.aSilos[0].rActualKg,
w1 := gBat.aSilos[1].rActualKg,
w2 := gBat.aSilos[2].rActualKg,
w3 := gBat.aSilos[3].rActualKg,
total := rTotal,
sign := HMAC_SHA256(...) // 防篡改签名
});
gBat.nBagSeq := gBat.nBagSeq + 1;
END_IF;
9. 运行与调试
- 仪表零点校准: 每台仪表通电后空载按 "TARE" 去皮, IDE 日志确认零点 < 0.05% FS
- 仿真验证: 仿真 Runtime 手动注入
rActualKg, 观察三段式状态机切换是否正确 - 下载到 Runtime: IDE "部署" → 选 Runtime IP → 下载
- 配方测试: 新建一个 "5+10+20+30 kg" 测试配方, 实际下料 → 检查偏差是否 < 0.5%
- 落差自学习: 连续下 5 袋观察
rOvershoot是否收敛稳定 - 强制信号: 强制
SB_EStop := FALSE, 验证快/慢加阀立即关闭 - 常见排查:
- 单袋超差 > 0.5% → 检查慢加阀口径是否过大, 调小
rFastEnd比例 - 仪表读数抖动 → 屏蔽接地, 移开变频器干扰源
- Modbus 响应超时 → 降波特率到 9600 或检查 A/B 极性
- 单袋超差 > 0.5% → 检查慢加阀口径是否过大, 调小
10. 用到的 Darra 功能
| 功能模块 | 本案例用到的 | 说明 |
|---|---|---|
| PLC 编程 | SCL + 状态机 + UDT + Retain | IEC 61131-3 |
| 工艺对象 | 仪表 Modbus FB + 配方数组 | 无需外购下料控制器 |
| HMI | 配方选择 + 实时重量 + 追溯台账 + 打印 | 一体化 UI |
| 通讯 | EtherCAT + Modbus RTU × 4 + OPC UA + USB 打印 | 多协议内置 |
| 数据记录 | 每袋 SQLite + 手机对账 | 完整追溯闭环 |
| 服务 | 终端授权 + 按袋次收费 + 远程对账 | OEM 按服务收费模式 |
11. 项目总结
- 实测指标: 单袋精度 ±0.3% (优于 0.5% 要求), 节拍 28 秒/袋, 连续 3 班次无超差
- 扩展方向:
- 增加自动包装机对接 (包装头 + 码垛机器人)
- 在线粒度/湿度检测, 原料波动时自动补偿
- 对接 ERP 批次管理, 客户扫码可查完整生产链路