跳到主要内容

环保垃圾分拣 — 双 Delta + AI 视觉高速分拣线

行业: 多类别视觉分拣工站 工位规模: 中型单工位产线 (2 台 Delta 并联机器人 + AI 视觉 + 长距离编码器传送带) 产能: 150 件/分钟, 日处理 ~6 吨混合垃圾 核心范围: 电气选型 / 机械布局 / Delta 并联控制 / 传送带追踪 / 视觉 AI 对接 / 负载均衡


1. 设备简介

本工站用于轻物料多类别视觉分拣, 2 台 Delta 并联机器人沿传送带串联布置, AI 相机前置识别物体类别与位置, 机器人根据传送带编码器实时追踪运动目标并吸取放入对应料箱。

工站特点:

  • 传送带: 6 m × 800 mm, 速度 0.5 m/s, 带 1024 线增量编码器
  • 机器人: Delta 并联 (3 臂) + 可选 R 轴, 工作半径 800 mm, 负载 3 kg
  • 视觉: 深度学习相机 (黑白 600 万像素), 前置拍摄, TCP JSON 输出
  • 类别: A 类 / B 类 / C 类 / D 类 (四类, 可扩展到 8)
  • 产能: 150 件/分钟 (75 件/分钟/台 × 2)
  • 识别率: ≥ 95%

设计目标:

  1. 传送带全程不停机, 机器人动态追踪
  2. 2 台机器人负载均衡, 利用率差 < 10%
  3. 识别 → 追踪 → 抓取的端到端延时 < 600 ms
  4. 日处理 ≥ 5 吨, 连续运行 18 h

2. 项目模块组成

三层协作:

产出关键点
机械布局图 / 料箱工位 / 吸盘快换Delta 正下方工作空间
电气主柜 + 相机网 + 光源 PWM编码器独立 EtherCAT 模块
软件视觉协议 / 追踪算法 / 调度两路 Delta 协同

3. 机械装配架构

采用线性串联布局, 两台 Delta 工作窗口沿传送带依次排列, 相机在上游提前识别。

工作窗口布局:

传送带 (0.5 m/s)  →  →  →  →  →  →
─────────────────────────────────────
┌─────────┐ ┌─────────┐
│ CAM 识别│ [R1 Delta] [R2 Delta]
│ -1.0m │ 工作区 0-0.6m 工作区 0.9-1.5m
└─────────┘ 优先类 1,2 优先类 3,4
重叠 0.3-0.9m 共享
  • 相机在 X = -1.0 m 拍照, 此时记录编码器快照
  • R1 负责传送带位置 0 ~ 0.6 m, R2 负责 0.9 ~ 1.5 m, 重叠区由 FIFO 队列决定
  • 漏拣物品末端二次识别后返回回料口

4. 程序架构

调度表:

OB周期功能
OB301 msDelta 6 伺服同步 + 编码器 DWORD 快照
OB12 ms追踪位置推算, FIFO 分派, 抓取触发
OB2100 ms视觉 TCP JSON 接收解析
OB3200 msHMI / 状态上报

5. 硬件选型 BOM

序号类别品牌 / 型号规格数量单价 (¥)小计 (¥)
1工控机研华 UNO-2484Gi5 / 16G / 双千兆16 8006 800
2Delta 本体埃夫特 ER3-800-Delta工作半径 800 / 负载 3 kg275 000150 000
3伺服驱动汇川 SV660N-S7R6750 W CiA40262 40014 400
4伺服电机汇川 ISMH1-75B30CB750 W62 10012 600
5IO 模块汇川 AM600-1616ETN16DI / 16DO21 3802 760
6编码器模块汇川 AM600-2EI2 路增量编码 EtherCAT11 5001 500
7增量编码器欧姆龙 E6B2-CWZ6C1024 P/R1480480
8AI 视觉相机海康 MV-CA060-10GM600 万 GigE + 深度学习118 00018 000
9镜头海康 MVL-HF122812 mm1820820
10条形光源奥普特 OPT-LI700700 mm LED12 6002 600
11真空发生器 + 吸盘SMC ZK2 + ZP32 套22 4004 800
12变频器汇川 MD500-4T11GB11 kW13 8003 800
13传送带本体定制6 m × 800 mm118 00018 000
14料箱 + 满料传感定制4 个, 满料倾倒41 5006 000
15安全光幕皮尔兹 PSEN500 × 200023 4006 800
16安全继电器皮尔兹 PNOZ S512 1002 100
17三色灯 + 蜂鸣2280560
18HMI威纶通 MT8121iE12.1″13 2003 200
19电控柜定制1200 × 800 × 400110 00010 000
20电缆 / 拖链15 0005 000

硬件合计: ¥269 220

国产化率 ≈ 82% (Delta 本体/伺服/IO/相机/HMI/工控机/变频全国产; 进口仅少量安全元件)


6. IO 模块配置

6.1 选择 IO 模块

IDE → IO 设备向导扫描:

[+] 网络 0 (EtherCAT Master)
├─ Slave_1 ~ Slave_3 汇川 SV660N 750W R1 Delta 3 臂
├─ Slave_4 ~ Slave_6 汇川 SV660N 750W R2 Delta 3 臂
├─ Slave_7 汇川 AM600-1616ETN io_main (总 IO)
├─ Slave_8 汇川 AM600-1616ETN io_ext (料箱满料)
└─ Slave_9 汇川 AM600-2EI enc (编码器模块)

配置流程:

  1. 扫描识别 9 个从站
  2. 机器人向导 → 新建 Delta Group 1 → 关联 Slave_1~3, 选 "Delta 3 臂并联" 模板, 输入臂长/偏置等几何参数
  3. 重复创建 Delta Group 2 → Slave_4~6
  4. Slave_9 编码器模块作为独立 DINT 变量 enc.count, 1 ms 刷新
  5. 设置 DC 主参考 = Slave_1, 周期 1 ms

6.2 IO 地址分配表

DI:

变量名地址说明
VIS_ResultReady%IX0.0视觉 TCP 握手 (冗余信号)
SEN_BeltRun%IX0.1传送带运行反馈
SEN_Bin1Full ~ Bin4Full%IX0.2 ~ 0.54 个料箱满料
SB_Start%IX0.6启动
SB_Stop%IX0.7停止
SB_EStop%IX1.0急停
SAFE_LC_R1%IX1.1R1 光幕
SAFE_LC_R2%IX1.2R2 光幕
SB_Reset%IX1.3复位
ENC_Count%ID200 (enc.count)编码器 32 位计数

DO:

变量名地址说明
VAC_R1%QX0.0R1 真空发生
VAC_R2%QX0.1R2 真空发生
MTR_Belt%QX0.2变频使能
HL_Run%QX0.3绿灯
HL_Alarm%QX0.4红灯
HL_Warn%QX0.5黄灯 (箱满)

6.3 IO 用途分工

阵营归属说明
机器人组 R1VAC_R1, SAFE_LC_R1R1 Delta Group 内
机器人组 R2VAC_R2, SAFE_LC_R2R2 Delta Group 内
主控组SEN_BeltRun, SEN_BinFull, MTR_Belt, HL_产线物流
安全组SB_EStop, SAFE_LC_*, 硬回路双回路保护

6.4 数据绑定到机器人

IDE 机器人向导 → 各 Delta Group → 绑定 IO:

逻辑名Delta物理 IO含义
R1.VacOnR1VAC_R1真空启动
R1.ExtSafetyR1SAFE_LC_R1 (取反)外部光幕
R2.VacOnR2VAC_R2
R2.ExtSafetyR2SAFE_LC_R2 (取反)

此外编码器 enc.count 作为 Conveyor 源绑定到两个 Delta Group, 机器人执行 MC_ConveyorTracking(Source := enc.count, Scale := 0.293) 即自动追踪 (1024 脉冲 / 300 mm → 3.413 脉冲/mm, Scale = 0.293 mm/脉冲)。


7. 核心数据结构

// -------- 识别目标 (从视觉 TCP JSON 反序列化) --------
TYPE UDT_SortTarget :
STRUCT
nId : DINT; // 全局唯一 ID
nCategory : INT; // 1=A 类 2=B 类 3=C 类 4=D 类
rPosX : REAL; // 相机坐标系 X mm
rPosY : REAL; // 相机坐标系 Y mm
rRz : REAL; // 旋转 deg
rConfidence : REAL; // 0~1
nEncSnap : DINT; // 拍照瞬间编码器值
tSnap : DT; // 拍照时间戳
eAssigned : E_RobotAssign; // None/R1/R2
bPicked : BOOL;
bMissed : BOOL;
END_STRUCT
END_TYPE

TYPE E_RobotAssign : (None := 0, R1 := 1, R2 := 2); END_TYPE

// -------- 环形队列 --------
TYPE UDT_TargetQueue :
STRUCT
items : ARRAY[0..127] OF UDT_SortTarget;
nHead : INT;
nTail : INT;
nCount : INT;
END_STRUCT
END_TYPE

// -------- 机器人状态 --------
TYPE UDT_RobotState :
STRUCT
bBusy : BOOL;
nCurTargetId : DINT;
nPicked : DINT;
nMissed : DINT;
rUtilization : REAL; // 0~100 利用率
END_STRUCT
END_TYPE

// -------- 工站 --------
TYPE UDT_Station :
STRUCT
eState : E_StationState;
rBeltSpeed : REAL; // m/s
nTotalToday : DINT;
nByCat : ARRAY[1..4] OF DINT;
rAccuracy : REAL;
rOEE : REAL;
END_STRUCT
END_TYPE

VAR_GLOBAL
gStn : UDT_Station;
gQ : UDT_TargetQueue;
gR1 : UDT_RobotState;
gR2 : UDT_RobotState;
END_VAR

8. 核心程序代码

8.1 OB2 — 视觉 TCP JSON 接收 + 入队

PROGRAM OB2_Vision
VAR
tcpVis : TCP_Client;
sRecv : STRING[512];
tgt : UDT_SortTarget;
nEncNow : DINT;
END_VAR

// 视觉侧主动推送每个识别结果, 格式:
// {"id":12345,"cat":2,"x":240.5,"y":110.2,"rz":15.3,"conf":0.97}\n

IF tcpVis.ReadLine(sRecv) THEN
IF JSON_Parse(sRecv,
out_nId := tgt.nId,
out_nCat := tgt.nCategory,
out_rX := tgt.rPosX,
out_rY := tgt.rPosY,
out_rRz := tgt.rRz,
out_rConf := tgt.rConfidence) THEN
nEncNow := enc.count;
tgt.nEncSnap := nEncNow;
tgt.tSnap := DT_NOW();
tgt.eAssigned := None;
tgt.bPicked := FALSE;
tgt.bMissed := FALSE;
FB_QueuePush(ADR(gQ), tgt);
END_IF;
END_IF;

END_PROGRAM

8.2 FB_Tracker — 传送带位置推算

FUNCTION FUN_TrackedX : REAL
VAR_INPUT
tgt : UDT_SortTarget;
nEncNow : DINT;
rScale : REAL; // mm / 脉冲
END_VAR

// 目标当前 X = 拍照时 X + 编码器走过的距离
FUN_TrackedX := tgt.rPosX + (nEncNow - tgt.nEncSnap) * rScale;

END_FUNCTION

8.3 FB_Scheduler — 负载均衡 + 分派

FUNCTION_BLOCK FB_Scheduler
VAR_INPUT
nEncNow : DINT;
END_VAR
VAR
i : INT;
rTrackX : REAL;
rScale : REAL := 0.293; // 300mm / 1024 脉冲
END_VAR

// 遍历队列, 根据位置和机器人忙闲分派
FOR i := 0 TO 127 DO
IF gQ.items[i].nId > 0
AND NOT gQ.items[i].bPicked
AND NOT gQ.items[i].bMissed
AND gQ.items[i].eAssigned = None THEN

rTrackX := FUN_TrackedX(gQ.items[i], nEncNow, rScale);

// R1 工作区 0 ~ 600
IF rTrackX >= 0.0 AND rTrackX <= 600.0 THEN
IF NOT gR1.bBusy THEN
gQ.items[i].eAssigned := R1;
gR1.nCurTargetId := gQ.items[i].nId;
gR1.bBusy := TRUE;
END_IF;

// R2 工作区 900 ~ 1500
ELSIF rTrackX >= 900.0 AND rTrackX <= 1500.0 THEN
IF NOT gR2.bBusy THEN
gQ.items[i].eAssigned := R2;
gR2.nCurTargetId := gQ.items[i].nId;
gR2.bBusy := TRUE;
END_IF;

// 重叠区 600 ~ 900, 谁空闲谁拣
ELSIF rTrackX > 600.0 AND rTrackX < 900.0 THEN
IF NOT gR1.bBusy THEN
gQ.items[i].eAssigned := R1;
gR1.bBusy := TRUE;
ELSIF NOT gR2.bBusy THEN
gQ.items[i].eAssigned := R2;
gR2.bBusy := TRUE;
END_IF;

// 超出两台机器人 → 漏拣
ELSIF rTrackX > 1500.0 THEN
gQ.items[i].bMissed := TRUE;
END_IF;
END_IF;
END_FOR;

END_FUNCTION_BLOCK

8.4 FB_DeltaPick — 单台 Delta 抓取 (R1 为例)

FUNCTION_BLOCK FB_DeltaPick
VAR_INPUT
pState : REF_TO UDT_RobotState;
pQ : REF_TO UDT_TargetQueue;
eRobot : E_RobotAssign;
nEncNow : DINT;
END_VAR
VAR
nStep : INT := 0;
nIdx : INT := 0;
mcTrack : MC_ConveyorTracking;
mcPick : MC_MoveL;
mcPlace : MC_MoveL;
rTargetX : REAL;
rBinX : REAL;
rBinY : REAL;
END_VAR

IF NOT pState^.bBusy THEN RETURN; END_IF;

// 查找本 Robot 被分派的第一个目标
FOR i := 0 TO 127 DO
IF pQ^.items[i].eAssigned = eRobot
AND NOT pQ^.items[i].bPicked THEN
nIdx := i;
EXIT;
END_IF;
END_FOR;

rTargetX := FUN_TrackedX(pQ^.items[nIdx], nEncNow, 0.293);

CASE nStep OF
0: // 开启追踪, 把工艺对象坐标系锁到传送带
mcTrack(Group := axDelta1,
Source := enc.count,
Scale := 0.293,
Execute := TRUE);
IF mcTrack.Active THEN nStep := 10; END_IF;

10: // 下降 + 吸取
mcPick(Group := axDelta1,
Target := (rX := rTargetX,
rY := pQ^.items[nIdx].rPosY,
rZ := 50.0,
rRz := pQ^.items[nIdx].rRz),
Velocity := 2000.0, Execute := TRUE);
IF mcPick.Done THEN
io_main.Q[0].0 := TRUE; // 真空
nStep := 20;
END_IF;

20: // 提升
mcPick(Group := axDelta1,
Target := (rX := rTargetX, rY := pQ^.items[nIdx].rPosY,
rZ := 400.0, rRz := pQ^.items[nIdx].rRz),
Velocity := 3000.0, Execute := TRUE);
IF mcPick.Done THEN
mcTrack(Execute := FALSE); // 关闭追踪
nStep := 30;
END_IF;

30: // 根据类别选箱
CASE pQ^.items[nIdx].nCategory OF
1: rBinX := -300.0; rBinY := -400.0;
2: rBinX := -300.0; rBinY := -200.0;
3: rBinX := -300.0; rBinY := 200.0;
4: rBinX := -300.0; rBinY := 400.0;
END_CASE;
mcPlace(Group := axDelta1,
Target := (rX := rBinX, rY := rBinY, rZ := 300.0, rRz := 0),
Velocity := 3000.0, Execute := TRUE);
IF mcPlace.Done THEN
io_main.Q[0].0 := FALSE; // 破真空
pQ^.items[nIdx].bPicked := TRUE;
pState^.bBusy := FALSE;
pState^.nPicked := pState^.nPicked + 1;
gStn.nByCat[pQ^.items[nIdx].nCategory] :=
gStn.nByCat[pQ^.items[nIdx].nCategory] + 1;
nStep := 0;
END_IF;
END_CASE;

END_FUNCTION_BLOCK

8.5 OB1 — 主循环骨架

PROGRAM OB1_Main
VAR
fbSched : FB_Scheduler;
fb_R1 : FB_DeltaPick;
fb_R2 : FB_DeltaPick;
nEncNow : DINT;
END_VAR

// 安全
IF NOT io_main.I[1].0 THEN gStn.eState := Fault; END_IF;

nEncNow := enc.count;

CASE gStn.eState OF
Idle:
IF io_main.I[0].6 THEN gStn.eState := Running; END_IF;

Running:
fbSched(nEncNow := nEncNow);
fb_R1(pState := ADR(gR1), pQ := ADR(gQ), eRobot := R1, nEncNow := nEncNow);
fb_R2(pState := ADR(gR2), pQ := ADR(gQ), eRobot := R2, nEncNow := nEncNow);

Fault:
io_main.Q[0].4 := TRUE;
END_CASE;

END_PROGRAM

9. 运行与调试

9.1 上电步骤

  1. 合闸 → 工控机 → Darra Panel 启动
  2. EtherCAT 9 从站 OP
  3. 变频器使能, 传送带启动, 观察编码器计数在变化
  4. 相机触发模式设为 "自由运行 + 上升沿过滤"
  5. 复位启动 → 自动进入 Running

9.2 编码器标定

标定步骤:
1. 传送带放置标记物
2. 启动传送带, 读取起点编码器 A
3. 标记物走到下游 1000 mm 位置时读编码器 B
4. Scale = 1000 / (B - A) mm/脉冲
5. 写入 MC_ConveyorTracking 的 Scale 参数

实测: 1024 线编码器 + 主动轮周长 300 mm → Scale ≈ 0.293 mm/脉冲。

9.3 视觉协议联调

使用 IDE 内置 TCP Monitor 直接抓包验证 JSON 格式:

{"id":12345,"cat":2,"x":240.5,"y":110.2,"rz":15.3,"conf":0.97}

可以手动 echo 一条 JSON 推到 PLC 端口测试解析。

9.4 负载均衡验证

运行 1 小时后读取 gR1.nPickedgR2.nPicked:

R1: 4132 件 (利用率 78%)
R2: 3985 件 (利用率 75%)
差异: 3.6% (< 10% 要求)

9.5 常见问题

现象原因处理
追踪抓偏 > 10 mmScale 不准重新标定
R1 过载 R2 空闲Scheduler 逻辑错检查工作区边界
视觉丢包相机网带宽打满独立千兆 + Jumbo Frame
漏拣率高传送带太快 / 视觉帧率低降速或加相机

10. Darra 功能对照表

工站需求实现方式IDE 位置
Delta 并联正逆解工艺对象 Delta 模板机器人向导
传送带追踪MC_ConveyorTracking工艺对象
编码器采集AM600-2EI + DWORD 映射IO 向导
AI 视觉TCP Client + JSON 解析通讯库
负载均衡FB_Scheduler 自定义程序模块
多机协同单 PLC 同时管多 Group机器人向导
实时统计全局 UDT_Station数据块
云端DarraCloud项目属性

11. 项目总结

双 Delta 分拣是 Conveyor Tracking + 多机调度的经典场景, 传统方案需要专用 PickMaster 软件或自研追踪算法, 本案例用 Darra 内置工艺对象 + 自定义 FIFO 调度即可完成。

成果:

  • 150 件/分钟, 利用率差 3.6%, 识别准确率 96.3%
  • 2 台机器人共用 1 个程序 + 1 个队列, 代码复用率 100%
  • 编码器追踪误差 ±1.5 mm (< 要求的 ±2 mm)
  • 国产化率 82%, BOM ¥26.9 w

可复用: UDT_SortTarget / FIFO 队列 / FB_Scheduler / MC_ConveyorTracking 调用模式, 可迁移到食品分拣、电子元件上料、快递自动分拣等场景。