汽车发动机装配线 (综合案例)
汽车行业三个硬指标: 多机器人毫秒同步、MES/ERP 双通道、15 年 UID 追溯。
传统方案需要 "3 台 PLC + 12 台机器人控制器 + 协议网关 + 自写数据库" 拼装, 任何一个组件掉链子整条线停。Darra 用 一个 Runtime + EtherCAT 主站 管住 12 台机器人 + 20 工位 + PostgreSQL 入库, 并通过 OPC UA/REST 向上层 MES/ERP 暴露数据, 总投资约 ¥ 480 万/条线。MES/ERP 仍是独立的上层系统。
一、设备简介
1.1 产线定位
- 客户: 国内头部新能源车企 (上海临港) 的动力总成工厂
- 产品: 1.5T 混动发动机 + 2.0T 汽油发动机 共线生产
- 节拍: 60 秒/台
- 日产能: 3 班 × 480 台 = 1,440 台
- 年产能: 40 万台
1.2 系统规模
| 项 | 数量 | 说明 |
|---|---|---|
| 工位 | 20+ | 上料 / 视觉识型 / 涂胶 / 搬运 / 拧紧 / 冷试 / 热试 / 下线 |
| 机器人 | 12 台 | 6 搬运 + 4 涂胶 + 2 视觉拧紧 |
| 拧紧枪 | 6 | Atlas Copco TensorST (EtherCAT) |
| 精密拧紧点 | 85 | 分 6 工序, 每点记录扭矩/角度/曲线 |
| 伺服轴 (工装) | 24 | 传送辊 / 工装顶升 / 定位 |
| 视觉系统 | 3 套 | 型号识别 + AOI + 拧紧复核 |
| EtherCAT 从站 | 约 180 个 | 12 机器人 × 6 + 24 伺服 + 6 拧紧 + IO + 安全 |
| 本地 IO | ≈ 1,200 点 | 15 块远程 IO + 4 块安全 IO |
1.3 关键指标
| 指标 | 目标 | 实测 |
|---|---|---|
| 单台节拍 | 60 s | 58.5 s |
| EtherCAT 周期 | 1 ms | 1 ms (抖动 < 10μs) |
| 多机器人同步误差 | < 0.5 ms | 0.28 ms |
| 拧紧精度 | ±2% 扭矩 | ±1.5% |
| 产线 OEE | ≥ 88% | 90.2% |
| MTBF | ≥ 2,000 h | 预期 2,500 h |
| MES 上报延迟 | < 500 ms | 320 ms |
| UID 追溯查询 | < 2 s | 1.1 s |
1.4 合规要求
- IATF 16949 汽车质量管理体系
- 追溯 15 年 (国家召回法规 / 主机厂强制)
- MES 断线不停线 (本地缓存 + 恢复补传)
- 主备热备 (主控故障 5 秒内切换)
二、项目模块组成
2.1 工艺流程
- M1 上料: 缸体 / 缸盖 送入, 视觉识别型号 (EA211-1.5T / EA888-2.0T)
- R1-R2 搬运: 双机器人同步搬缸体到装配工装
- R3 涂胶 (密封圈): KUKA KR 20 走胶圈轨迹
- R4 涂胶 (油道): 埃斯顿 ER20 走油道线
- R5-R6 拧紧定位: 机器人夹持拧紧枪到螺栓位
- M2/M3 拧紧 (85 点, 6 工序):
- 工序 1 主轴承盖 (10 点, 80±1 Nm + 90°)
- 工序 2 连杆盖 (16 点, 45±1 Nm + 60°)
- 工序 3 缸盖螺栓 (10 点, 90±2 Nm + 180°)
- 工序 4 进气歧管 (8 点, 25 Nm)
- 工序 5 排气歧管 (8 点, 30 Nm)
- 工序 6 辅助螺栓 (33 点, 10-25 Nm)
- R7 视觉复核: 协作机器人带相机逐点扫描确认
- M4 冷试: 密封性 / 气道通畅性
- M5 热试: 点火 30 秒, 水温 / 油压 / 转速曲线
- R8 下线: 搬到检测合格区 / NG 返修区
- AGV 入库
2.2 逻辑对象
| 对象 | 数量 | 类型 |
|---|---|---|
| T_Engine | 队列 | 发动机 UID + 工序记录 |
| T_Robot | 12 | 机器人状态 |
| T_TorqueRecord | 每台 85 条 | 每螺栓扭矩/角度/曲线 |
| T_VisionResult | 每台 23 条 | 视觉检测结果 |
| T_ColdTestResult | 每台 1 条 | 冷试结果 |
| T_HotTestResult | 每台 1 条 | 热试结果 |
| T_Recipe | 数十个 | 机型 × 工序 参数库 |
| T_MES | 1 | MES 连接状态 |
三、机械装配架构
3.1 产线布局 (180 m, 20+ 工位)
AGV 入口 ─► [M1 上料/视觉识型]
│
▼
[R1][R2] 缸体搬运 (同步)
│
▼
[R3]涂胶圈 ─► [R4]涂油道
│
▼
[M2 拧紧工序 1-3] ←─ [R5][R6] 夹持拧紧枪
│
▼
[M3 拧紧工序 4-6] ←─ (同上)
│
▼
[R7] 视觉复核 (法奥 FR5 协作)
│
▼
[M4 冷试] (气密 / 油道)
│
▼
[M5 热试] (点火 30s, 转速曲线)
│
▼
[R8] 下线 ─► OK 区 / NG 返修区 ─► AGV 出口
3.2 工件流向
缸体/缸盖 → 装配工装 → 涂胶 → 拧紧 → 视觉复核 → 冷试 → 热试 → OK / NG 分流 → AGV
每工位有工装顶升 + 定位销, 工件到位精度 ±0.05 mm。
3.3 多机器人同步要求
| 场景 | 要求 | 方案 |
|---|---|---|
| R1-R2 双机搬缸体 | 同步到位 ±0.3 ms | EtherCAT DC 时钟 + Robot_MoveAbs_Sync |
| R5-R6 拧紧定位 | 交替工作, 不碰撞 | 区域互斥 + 共享 Token |
| R7 视觉复核 | 与 R8 路径无冲突 | 安全区规划 |
| 涂胶与拧紧 | 涂胶完 30s 固化后拧紧 | 定时器 + 状态变量 |
四、程序架构
4.1 OB 分层
4.2 FB 清单
| FB | 周期 | 职责 |
|---|---|---|
| FB_SafetyChain | 1 ms | 急停 / 光栅 / 门锁 |
| FB_LineSequencer | 1 ms | 20 工位节拍 + 握手 |
| FB_RobotGroup12 | 1 ms | 12 机器人统一调度 |
| FB_ServoGroup24 | 1 ms | 24 工装轴 |
| FB_TorqueCurveLogger | 10 ms | 拧紧枪 10ms 采样扭矩曲线 |
| FB_MESBridge | 100 ms | REST 上报 + 工单下载 |
| FB_OPCPublish | 100 ms | OPC UA 实时发布 |
| FB_TraceDBLogger | 1 s | PostgreSQL 批量入库 |
| FB_AlarmMgr | 1 s | L1~L4 分级 + 推送 |
| FB_SAPReporter | 10 s | SAP 日汇总 |
| FB_OEECalc | 10 s | OEE 滚动计算 |
4.3 主备热备
主备 Runtime 通过 Keepalive (100ms) 监测, 主掉线时备接管:
- 主备共享同一 EtherCAT 主站配置 (VRRP 虚拟 IP)
- Retain 变量每 500ms 镜像到备机
- 切换时间 ≤ 5s, HMI / MES 无感知
五、硬件 BOM
5.1 主控与 HMI
| 项 | 型号 | 数量 | 单价 (¥) | 小计 (¥) |
|---|---|---|---|---|
| 主控工控机 | 研华 ARK-3520 定制 (i9-13900 / 64GB ECC / 1TB NVMe RAID1) | 1 | 32,000 | 32,000 |
| 备份主控 (热备) | 同上 | 1 | 32,000 | 32,000 |
| 工位触摸屏 | 研华 TPC-1881WP 21.5" | 20 | 6,500 | 130,000 |
| 车间大屏 | 创维 85" 商用屏 × 2 | 2 | 12,800 | 25,600 |
| 管理工位 | 戴尔 OptiPlex 7010 | 5 | 6,800 | 34,000 |
5.2 机器人 (12 台 + 4 备用)
策略: 高精度 / 重载用进口, 常规用国产。Darra 机器人对象层让混合毫无感觉。
| 位置 | 型号 | 数量 | 单价 (¥) | 小计 (¥) | 备注 |
|---|---|---|---|---|---|
| R1-R2 搬运 (重载) | ABB IRB 6700 (235kg / 2.65m) | 2 | 420,000 | 840,000 | 缸体重载 |
| R3 涂胶密封 | KUKA KR 20 R3100 | 1 | 280,000 | 280,000 | 高重复精度 |
| R4 涂胶油道 | 埃斯顿 ER20-1780 | 1 | 82,000 | 82,000 | 国产 |
| R5-R6 拧紧定位 | 埃斯顿 ER10-1600 | 2 | 48,000 | 96,000 | 国产 |
| R7 视觉复核 | 法奥意威 FR5 协作 | 1 | 68,000 | 68,000 | 协作型 |
| R8 下线抓放 | 埃夫特 ER50-2100 | 1 | 168,000 | 168,000 | 50kg 负载 |
| 备用涂胶 | 埃斯顿 ER10 | 2 | 48,000 | 96,000 | |
| 备用搬运 | 埃斯顿 ER20 | 2 | 82,000 | 164,000 |
5.3 精密拧紧枪
| 项 | 型号 | 数量 | 单价 (¥) | 小计 (¥) |
|---|---|---|---|---|
| 电动拧紧枪 (EtherCAT) | Atlas Copco TensorST | 6 | 42,000 | 252,000 |
| 拧紧控制器 (PowerFocus) | Atlas Copco PF6000 | 6 | 28,000 | 168,000 |
| 手持示教枪 (返工) | Atlas Copco | 2 | 18,000 | 36,000 |
5.4 伺服 + 工装
| 项 | 型号 | 数量 | 单价 (¥) | 小计 (¥) |
|---|---|---|---|---|
| 伺服驱动 (工装) | 汇川 SV660N | 24 | 3,600 | 86,400 |
| 伺服电机 | 汇川 ISMH2 系列 | 24 | 3,200 | 76,800 |
| 传送辊筒 (定制) | 6 段 | 6 | 28,000 | 168,000 |
5.5 IO / 视觉
| 项 | 型号 | 数量 | 单价 (¥) | 小计 (¥) |
|---|---|---|---|---|
| 远程 IO | 汇川 GL10-EC | 15 | 4,200 | 63,000 |
| 安全 IO (FSoE) | 汇川 GL10-FSO | 4 | 5,600 | 22,400 |
| 安全光栅 | SICK deTec4 | 8 | 8,500 | 68,000 |
| 急停 / 门锁 | Pilz | 1 批 | 40,000 | 40,000 |
| 视觉相机 (型号识别) | 海康 MV-CH250-10M 2500W | 1 | 32,000 | 32,000 |
| 视觉相机 (AOI) | 海康 MV-CU050-60GM × 3 | 3 | 6,800 | 20,400 |
| AI 视觉工控机 | 研华 MIC-710AI | 3 | 15,000 | 45,000 |
| 扫码枪 (UID) | 海康 MV-ID2013M | 8 | 1,600 | 12,800 |
| 标签打印机 | Zebra ZT411 | 2 | 6,800 | 13,600 |
5.6 网络 / 辅件
| 项 | 型号 | 数量 | 单价 (¥) | 小计 (¥) |
|---|---|---|---|---|
| 工业交换机 (管理) | 华为 S5720-28X | 4 | 6,800 | 27,200 |
| UPS 10kVA 在线式 | 山特 | 2 | 18,000 | 36,000 |
| 电气柜 | 定制 | 8 | 18,000 | 144,000 |
| 线缆 / 接插 | 菲尼克斯 | 1 批 | 60,000 | 60,000 |
| 安装工时 | 自有 | 1 | 180,000 | 180,000 |
5.7 Darra 软件
| 项 | 说明 | 单价 (¥) | 小计 (¥) |
|---|---|---|---|
| Darra Runtime (主 + 备) | 35,000 | 70,000 | |
| Darra IDE × 3 | 工程师授权 | 15,000 | 45,000 |
| Darra HMI 扩展 20,000 点位 | 35,000 | 35,000 | |
| DarraCloud 企业版 (年) | 多终端 + 云备份 | 36,000 | 36,000 |
5.8 总预算
| 大项 | 小计 (¥) |
|---|---|
| 主控 / HMI | 253,600 |
| 机器人 (含备用) | 1,794,000 |
| 拧紧 | 456,000 |
| 伺服 / 工装 | 331,200 |
| IO / 视觉 / 外设 | 317,200 |
| 网络 / 辅件 / 安装 | 447,200 |
| Darra 软件 | 186,000 |
| 硬件 + 软件小计 | 3,785,200 |
| 调试 / 集成 (3 工程师 × 4 月) | 600,000 |
| 备件 / 风险金 | 400,000 |
| 项目合计 (不含税) | ≈ 4,785,200 |
| 对外含税报价 | ≈ ¥ 4,800,000 (480 万) |
六、IO 模块配置
6.1 IO 清单 (按工位)
| 工位区 | 模块 | 数量 | 说明 |
|---|---|---|---|
| M1 上料 | GL10-EC | 1 | 32DI/32DO/8AI/4AO |
| R1-R4 搬运涂胶区 | GL10-EC | 3 | 机器人围栏 + 工装 |
| M2-M3 拧紧区 | GL10-EC | 4 | 拧紧工装定位 |
| R7-M4 检测区 | GL10-EC | 3 | 视觉 + 冷试 |
| M5 热试区 | GL10-EC | 2 | 点火台架 |
| R8 下线 | GL10-EC | 2 | 分流 + OK/NG 道 |
| 安全模块 | GL10-FSO | 4 | 4 个安全回路 |
合计 15 × GL10-EC = 480 DI + 480 DO + 120 AI + 60 AO + 4 × GL10-FSO。
6.2 IO 地址分配 (节选)
| 地址 | 类型 | 符号 | 说明 |
|---|---|---|---|
| %IX0.0 | FSI | g_Safety.bEStop | 总急停 |
| %IX0.1 | FSI | g_Safety.bLineGate | 产线门 |
| %IX0.2 | FSI | g_Safety.bLightCurtain1 | R1-R2 区光栅 |
| %IX0.3 | FSI | g_Safety.bLightCurtain2 | R3-R4 区光栅 |
| %IX10.0 | DI | g_M1.bEnginePresent | M1 工件到位 |
| %IX10.1 | DI | g_M1.bModelReadOK | 型号识别 OK |
| %IX20.0 | DI | g_M2.bFixtureDocked | M2 工装对接 |
| %IX20.1 | DI | g_M2.bTorqueGunReady | 拧紧枪就绪 |
| %IX30.0 | DI | g_M4.bColdTestStart | 冷试开始 |
| %IX30.1 | DI | g_M4.bColdTestDone | 冷试完成 |
| %IX40.0 | DI | g_M5.bIgnitionOK | 点火成功 |
| %QX0.0 | DO | g_LineEnable | 产线使能 |
| %QX10.0 | DO | g_M1.bFixtureLift | 工装顶升 |
| %QX20.0 | DO | g_M2.bFixtureClamp | 夹紧 |
| %QX30.0 | DO | g_M4.bAirInlet | 冷试进气 |
| %QX40.0 | DO | g_M5.bIgnitionCmd | 热试点火命令 |
| %IW100 | AI | g_M4.rPressureDecay | 压降速率 |
| %IW102 | AI | g_M5.rOilPressure | 油压 |
| %IW104 | AI | g_M5.rRpm | 转速 |
| %QW100 | AO | g_M5.rThrottle | 节气门开度 |
6.3 IO 用途分工 (工位间 / 机器人握手 / MES)
| 交接 | 信号 | 方式 |
|---|---|---|
| M1 → R1/R2 | bEnginePresent + sEngineUID + sModel | 本地 + T_Engine |
| R1/R2 → R3 | bArrivedDockPos + sUID 握手 | Robot_MoveAbs_Sync 确保双机同步 |
| R3 / R4 涂胶 → 拧紧 | bGlueDone + 固化计时器 (30s) | TON_GlueCure |
| R5-R6 → M2/M3 | 拧紧枪到位 r.bGunAtPos | 区域 Token 互斥 |
| 拧紧曲线 → DB | 每 10ms 采样 TorqueRecord[i] | OB10 异步 |
| M4 冷试 → M5 | bColdTestOK + 参数 | 本地变量 |
| M5 热试 → R8 | bHotTestResult + bFinalOK | R8 根据结果分流 |
| 产线 → MES | 每螺栓立即 POST, 每台完工汇总 | HTTP Async |
| 产线 → SAP | 每班次汇总 OPC UA | 被 SAP 轮询 |
6.4 数据绑定 (12 机器人 + 主备 PLC)
# 主 Runtime
deviceBinding:
- name: R1
type: EtherCAT_Robot
vendor: ABB
model: IRB6700
slaveAddr: 1001
axes: 6
- name: R2
type: EtherCAT_Robot
vendor: ABB
model: IRB6700
slaveAddr: 1002
axes: 6
- name: R3
type: EtherCAT_Robot
vendor: KUKA
model: KR20
slaveAddr: 1003
axes: 6
- name: R4
type: EtherCAT_Robot
vendor: Estun
model: ER20
slaveAddr: 1004
axes: 6
# R5-R8, R备1-R备4 同上
- name: TorqueGun1
type: EtherCAT_TorqueTool
vendor: AtlasCopco
model: TensorST
slaveAddr: 2001
# TG2-TG6 同上
syncReplication:
primary: DarraRT_Master
standby: DarraRT_Standby
heartbeat_ms: 100
retain_mirror_ms: 500
switchover_max_s: 5
主备双机共用同一组 EtherCAT 从站 (备机平时只接收不发送, 切换时立即接管发送)。
七、核心数据结构
7.1 发动机 (UID 追溯主对象)
TYPE T_Engine :
STRUCT
sUID : STRING(24); // "ENG20260417001234"
sModel : STRING(12); // "EA211-1.5T" / "EA888-2.0T"
sWorkOrder : STRING(32);
eState : E_EngineState;
dtStartTime : DT;
dtEndTime : DT;
TorqueList : ARRAY[1..85] OF T_TorqueRecord;
VisionList : ARRAY[1..23] OF T_VisionResult;
GlueList : ARRAY[1..4] OF T_GlueRecord;
ColdTest : T_ColdTestResult;
HotTest : T_HotTestResult;
sOperator : STRING(16);
bFinalOK : BOOL;
sFinalRemark : STRING(200);
rYieldCycle : REAL; // 本台综合节拍
END_STRUCT
END_TYPE
7.2 扭矩记录
TYPE T_TorqueRecord :
STRUCT
nId : INT; // 1..85
sPositionName : STRING(32); // "M10_MainBearing_01"
nProcessGroup : INT; // 工序 1..6
rTargetTorque : REAL; // Nm
rToleranceTorque : REAL; // ±Nm
rTargetAngle : REAL; // °
rActualTorque : REAL;
rActualAngle : REAL;
rPeakRpm : REAL; // 峰值转速
Curve : ARRAY[1..200] OF REAL; // 10ms 采样曲线 (2 秒)
nCurveLen : INT;
dtTimestamp : DT;
sOperator : STRING(16);
bOK : BOOL;
sNgReason : STRING(80);
END_STRUCT
END_TYPE
7.3 视觉结果
TYPE T_VisionResult :
STRUCT
nId : INT;
sCheckItem : STRING(32); // "密封圈完整" / "油道通" / "型号正确"
bResult : BOOL; // TRUE=OK
rScore : REAL; // 置信度
sImagePath : STRING(240);
sDefectType : STRING(32); // 如果 NG
dtTimestamp : DT;
END_STRUCT
END_TYPE
7.4 冷试 / 热试
TYPE T_ColdTestResult :
STRUCT
bLeakOK : BOOL;
rPressureDecay : REAL; // Pa / 10s
rOilChannelPress : REAL;
dtStart : DT;
dtEnd : DT;
bOverall : BOOL;
END_STRUCT
END_TYPE
TYPE T_HotTestResult :
STRUCT
bIgniteOK : BOOL;
rMaxRpm : REAL;
rIdleRpm : REAL;
rOilPressPeak : REAL;
rCoolantTemp : REAL;
RpmCurve : ARRAY[1..300] OF REAL; // 100ms × 30s
dtStart : DT;
dtEnd : DT;
bOverall : BOOL;
END_STRUCT
END_TYPE
7.5 机器人群
TYPE T_RobotGroup :
STRUCT
Robots : ARRAY[1..12] OF T_Robot;
bAllReady : BOOL;
nBusyCount : INT;
TokenZone : ARRAY[1..4] OF INT; // 4 个区域互斥 Token: 持有的机器人 ID
END_STRUCT
END_TYPE
八、核心程序代码
8.1 双机器人同步搬运
FUNCTION_BLOCK FB_TwoRobotLift
VAR_IN_OUT
r1 : T_Robot;
r2 : T_Robot;
END_VAR
VAR
p1, p2 : E6POS;
END_VAR
// R1 + R2 同步抬起缸体, 误差 ≤ 50 μm / 0.3 ms
// 1) 分别移动到对称取点
p1 := g_CylinderBlockLeft;
p2 := g_CylinderBlockRight;
Robot_MoveAbs(r1, p1, 300.0);
Robot_MoveAbs(r2, p2, 300.0);
WAIT_UNTIL(r1.bReached AND r2.bReached); // 同周期检查 → 同步到位
// 2) 同步夹紧
Robot_GripperClose(r1);
Robot_GripperClose(r2);
WAIT_MS(100);
// 3) 同步直线抬起 500mm (关键: 位置由 Darra DC 保证同步)
p1.Z := p1.Z + 500;
p2.Z := p2.Z + 500;
Robot_MoveAbs_Sync(r1, p1, r2, p2, 200.0); // 同步线性, 到达时间差 < 0.3 ms
WAIT_UNTIL(r1.bReached AND r2.bReached);
// 4) 同步移动到装配工装上方
p1 := g_FixtureLeftAbove;
p2 := g_FixtureRightAbove;
Robot_MoveAbs_Sync(r1, p1, r2, p2, 300.0);
WAIT_UNTIL(r1.bReached AND r2.bReached);
// 5) 同步下放
p1 := g_FixtureLeft;
p2 := g_FixtureRight;
Robot_MoveAbs_Sync(r1, p1, r2, p2, 100.0);
WAIT_UNTIL(r1.bReached AND r2.bReached);
// 6) 同步松开
Robot_GripperOpen(r1);
Robot_GripperOpen(r2);
WAIT_MS(100);
END_FUNCTION_BLOCK
Robot_MoveAbs_Sync底层用 EtherCAT Distributed Clock (DC) 同步所有轴, 到达误差 < 1 ms, 这是传统 TCP / Profinet 方案无法达到的。
8.2 拧紧流水 (6 工序 85 点)
FUNCTION_BLOCK FB_TorqueSequence
VAR_IN_OUT
engine : T_Engine;
END_VAR
VAR
i, gunId : INT;
recipe : T_TorqueGroup;
END_VAR
FOR i := 1 TO 85 DO
// 1) 读配方
recipe := Recipe_GetTorque(engine.sModel, i);
// 2) 机器人把拧紧枪挪到位
gunId := TorqueGun_SelectByPos(recipe.pPosition);
Robot_MoveGun(g_Robot[5], recipe.pPosition);
WAIT_UNTIL(Robot_Reached(g_Robot[5]));
// 3) 启动拧紧 (Atlas Copco PowerFocus over EtherCAT)
TorqueGun_Start(gunId, recipe);
// 4) 10 ms 采样曲线 (由 OB10 FB_TorqueCurveLogger 独立采集)
engine.TorqueList[i].nId := i;
engine.TorqueList[i].sPositionName := recipe.sName;
engine.TorqueList[i].rTargetTorque := recipe.rTarget;
engine.TorqueList[i].dtTimestamp := NOW();
engine.TorqueList[i].sOperator := g_CurrentOperator.sId;
WAIT_UNTIL(TorqueGun_Complete(gunId));
engine.TorqueList[i].rActualTorque := TorqueGun_GetFinalTorque(gunId);
engine.TorqueList[i].rActualAngle := TorqueGun_GetFinalAngle(gunId);
engine.TorqueList[i].rPeakRpm := TorqueGun_GetPeakRpm(gunId);
engine.TorqueList[i].bOK := TorqueGun_ResultOK(gunId);
// 5) 实时入库 + MES 上报
DB_Insert_Async('tbl_torque', engine.TorqueList[i]);
MES_UploadTorque(engine.sUID, engine.TorqueList[i]);
IF NOT engine.TorqueList[i].bOK THEN
engine.TorqueList[i].sNgReason := TorqueGun_FailReason(gunId);
Alarm_Raise(AlarmId.TorqueNG,
'扭矩不合格 UID=' + engine.sUID
+ ' pos=' + recipe.sName
+ ' actual=' + REAL_TO_STR(engine.TorqueList[i].rActualTorque));
// 主机厂要求: 任何拧紧失败, 工件流入返修道
engine.bFinalOK := FALSE;
EXIT;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
8.3 拧紧曲线采样 (OB10, 10ms)
FUNCTION_BLOCK FB_TorqueCurveLogger
VAR
i, j : INT;
gunId : INT;
END_VAR
FOR gunId := 1 TO 6 DO
IF TorqueGun_InProgress(gunId) THEN
i := TorqueGun_GetCurrentRecordId(gunId); // 当前记录到哪条
j := g_Engine.TorqueList[i].nCurveLen + 1;
IF j <= 200 THEN
g_Engine.TorqueList[i].Curve[j] := TorqueGun_GetInstantTorque(gunId);
g_Engine.TorqueList[i].nCurveLen := j;
END_IF;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
8.4 MES 上报 (REST + OPC UA 双通道)
FUNCTION_BLOCK FB_MESBridge
VAR
req : HTTP_Request;
rsp : HTTP_Response;
sBody : STRING(1024);
END_VAR
// 每拧紧一个螺栓立即上报 (汽车主机厂要求)
IF g_Events.bTorqueDone THEN
sBody := '{"stationId":"M3","engineUID":"' + g_Events.sUID
+ '","torqueId":"' + g_Events.sTorqueName
+ '","value":' + REAL_TO_STR(g_Events.rTorque)
+ ',"angle":' + REAL_TO_STR(g_Events.rAngle)
+ ',"timestamp":"' + DT_TO_ISO(NOW())
+ '","operatorId":"' + g_Events.sOperator
+ '","result":"' + BOOL_TO_STR(g_Events.bOK, 'OK', 'NG')
+ '"}';
req.Url := g_MES.sBaseUrl + '/api/v2/torque';
req.Method := 'POST';
req.Body := sBody;
req.Header['Authorization'] := 'Bearer ' + g_MES.sToken;
req.TimeoutMs := 1000;
HTTP_Post_Async(req, rsp); // 非阻塞, 失败自动重试 3 次, 缓存到本地队列
g_Events.bTorqueDone := FALSE;
END_IF;
// 整台发动机完工, 上报汇总
IF g_Events.bEngineDone THEN
req.Url := g_MES.sBaseUrl + '/api/v2/engine/complete';
req.Method := 'POST';
req.Body := JSON.Stringify(g_CurrentEngine); // 整个 T_Engine 序列化
HTTP_Post_Async(req, rsp);
g_Events.bEngineDone := FALSE;
END_IF;
END_FUNCTION_BLOCK
8.5 追溯入库 (PostgreSQL)
FUNCTION_BLOCK FB_TraceDBLogger
VAR
i : INT;
END_VAR
// 每台完工, 批量入库 (85 条扭矩 + 23 条视觉 + 冷/热试 + 主表)
IF g_Events.bEngineDone THEN
DB_BeginTransaction();
DB_Insert('tbl_engine', g_CurrentEngine);
FOR i := 1 TO 85 DO
DB_Insert('tbl_torque_detail', g_CurrentEngine.TorqueList[i]);
END_FOR;
FOR i := 1 TO 23 DO
DB_Insert('tbl_vision_detail', g_CurrentEngine.VisionList[i]);
END_FOR;
DB_Insert('tbl_cold_test', g_CurrentEngine.ColdTest);
DB_Insert('tbl_hot_test', g_CurrentEngine.HotTest);
DB_Commit();
// 15 年追溯要求: 每月归档到冷存储 (DarraCloud)
IF IS_MONTH_CROSS() THEN
DarraCloud_ArchiveMonth();
END_IF;
END_IF;
END_FUNCTION_BLOCK
8.6 UID 追溯查询 (HMI 调用)
FUNCTION_BLOCK FB_TraceQuery
VAR_INPUT
sUID : STRING(24);
END_VAR
VAR_OUTPUT
eng : T_Engine;
bFound : BOOL;
END_VAR
VAR
sSql : STRING(500);
END_VAR
sSql := 'SELECT * FROM tbl_engine WHERE uid = $1';
bFound := DB_QuerySingle(sSql, sUID, eng);
IF bFound THEN
// 补充 85 条扭矩 + 23 条视觉
DB_QueryArray('SELECT * FROM tbl_torque_detail WHERE engine_uid = $1 ORDER BY id',
sUID, eng.TorqueList);
DB_QueryArray('SELECT * FROM tbl_vision_detail WHERE engine_uid = $1 ORDER BY id',
sUID, eng.VisionList);
END_IF;
END_FUNCTION_BLOCK
九、运行与调试
9.1 上线部署顺序
- 主备工控机开机, 加载同一 Runtime 工程
- 检查 EtherCAT 全部从站 OP 状态 (180 个从站全绿)
- 12 机器人上电, 逐台回零, 示教共用参考点
- 6 把拧紧枪校准 (扭矩传感器 + 角度编码器)
- 视觉 3 套独立调试 (光源 / 曝光 / 模型)
- 冷试 / 热试台架独立验收
- 单工位手动 → 全线手动 → 单台自动 → 连续自动
- MES Token 配置 + OPC UA 节点发布
- 主备切换测试 (5 秒内)
- 7×24 小时压力测试 1 周
9.2 调试工具
| 工具 | 作用 |
|---|---|
| 机器人示教盒 | 单机器人示教 |
| Darra 机器人联动仿真 | 12 机器人不碰撞预演 |
| EtherCAT 诊断 | 180 从站 WKC / DC |
| 扭矩曲线分析 | 离线分析 Curve[1..200] |
| MES Mock | 离线模拟 MES |
| DbgView | 内核驱动日志 |
| DarraCloud 运维 | 远程工程师协助 |
9.3 典型故障
| 现象 | 原因 | 处理 |
|---|---|---|
| 双机搬运到位时间差 > 1ms | DC 时钟漂移 | 检查网线 / 重置 DC |
| 扭矩不合格率 > 2% | 配方参数 / 机械松动 | 校准枪 + 重新示教定位 |
| MES 上报堆积 | 网络抖动 | 本地队列缓存, 恢复后批量发 |
| 主备切换失败 | Retain 未同步 | 检查镜像周期 500ms 是否达标 |
| 视觉误判 | 光源衰减 | 每月检查光源亮度 |
| OEE 异常低 | 某工位等料 | 看节拍瀑布图, 调整传送带速度 |
9.4 数据量估算
- 单台发动机: 85 扭矩 × (10 字段 + 200 曲线点) ≈ 50 KB
- 加视觉 + 冷热试: 约 200 KB/台
- 1,440 台/日 × 200 KB ≈ 288 MB/日
- 15 年 ≈ 1.5 TB (含索引和备份约 4 TB)
- PostgreSQL 分区表 按月分 + 按年归档冷存储
十、Darra 功能对照表
| 项目需求 | Darra 功能 | 模块 |
|---|---|---|
| 12 机器人 EtherCAT 1ms | Darra 单 Runtime + EtherCAT Master | 内置 |
| 多机器人同步运动 | Robot_MoveAbs_Sync + DC 时钟 | MC 库 |
| 85 螺栓扭矩采集 | Darra TorqueTool 对象 + 10ms 采样 | 内置 |
| 拧紧枪 EtherCAT 对接 | Atlas Copco EtherCAT Slave 驱动 | 内置 |
| 视觉 TCP + AI 推理 | Darra Vision + Python FFI | 插件 |
| 冷试 / 热试 | Darra AI + AO + Timer FB | 内置 |
| 主备热备 | Darra HA (Keepalive + VIP + Retain 镜像) | 企业版 |
| MES REST | Darra HTTP Client Async + 缓存重试 | 内置 |
| SAP OPC UA | Darra OPC UA Server + 白名单 | 内置 |
| 15 年追溯 | PostgreSQL 分区 + DarraCloud 冷备 | 数据库 + 云 |
| UID 追溯查询 | SQL 二级索引 + 前端 HMI | 内置 |
| 报警分级 | AlarmMgr L1~L4 + 企业微信 WebHook | 内置 |
| 配方管理 | Recipe 对象 + 机型切换 | IDE |
| 本地 HMI | Darra HMI 20 工位屏 | 内置 |
| 中控大屏 | Darra Web HMI | 内置 |
| 远程运维 | DarraCloud 反向隧道 | 云服务 |
十一、项目总结
11.1 交付结果
- 单线 1,440 台/日 (节拍 58.5s, 优于 60s 目标)
- OEE 90.2% (目标 88%)
- 综合 NG 返修率 1.2% (前方案 4.5%)
- MES 上报 100% 成功 (丢包时本地队列自动补传)
- 主备切换实测 4.2 秒 (< 5s 要求)
- IATF 16949 审核通过
- 15 年追溯 Demo 通过 (查询响应 1.1 秒)
11.2 产品价值体现
- 多机器人协同: 一个 Runtime 管 12 台, 从 30~80ms 跨控制器延迟降到 < 0.3ms DC 同步
- 数据不丢: MES 断线 → 本地 SQLite 缓存 → 恢复自动补传, 30 天累计丢失 0 条
- 主备稳定: 7×24 跑了 3 个月, 主动切换 1 次 (主机升级), 被动切换 0 次
- UID 追溯真实可用: 客户被主机厂召回抽检时, 2 秒调出 6 个月前的数据
- 国产替代部分成本: 4 台常规机器人用国产 (埃斯顿/埃夫特) 替代 ABB, 单台省 30 万
11.3 关键经验
- 多机器人同步: 一定用 EtherCAT DC 时钟, 不要尝试 TCP 方案
- 拧紧枪选型: Atlas Copco EtherCAT 版贵 30%, 但省去 Profinet 网关 + 免去延迟问题
- 扭矩曲线采样: 10ms 采样 200 点足够, 1ms 采样会撑爆数据库
- 数据库分区: PostgreSQL 按月分区, 15 年数据查询毫秒级
- 热备切换: Keepalive 100ms + Retain 镜像 500ms 是实测最平衡参数
- 机器人品牌混搭: Darra 机器人对象让 ABB + KUKA + 埃斯顿 + 法奥 + 埃夫特同线跑, 上层零代码差异
11.4 下一步扩展
- 增加 数字孪生: 基于拧紧曲线训练模型, 预测螺栓疲劳寿命
- 部署 AI 外观检测: 把 R7 视觉升级到深度学习, 识别微小铸造瑕疵
- 集成 能耗 SPC: 每台发动机装配能耗分析, 优化工序顺序
- 车型扩展: 同一产线加 2.0T 混动配方, 共线支持 4 种发动机