机器视觉运动控制一体机应用例程(八)零件分拣系统
工件分拣是工业生产环节中重要的组成部分,其目的是将不同类型的物料或工件分类摆放到相应的位置,避免不同的物料或工件产生混料,其步骤主要分为定位、识别、抓取和放置4个阶段。
在传统分拣中一般采用人工分拣的方式 ,因工人操作会存在疲劳度的问题,对于长时间作业来说,显然工作效率是无法满足。
即使采用工业机器人分拣方式,由于传统的工业机器人一般采用示教或离线编程的方式工作,机器人到达目标点的位置是固定的,每次动作均为重复进行,只能重复完成预先规定好的动作。
对于加工对象以及工作环境的感知能力低,以及物料或工件的来料方向不确定,使机器人的使用受到了限制。随着机器视觉和人工智能的发展,机器人也能够适应分拣环境的需求,随时变更作业对象和分拣工序。
机器视觉分拣系统对工件或物料进行位置和类型的判断是必要的,与传统的机械分拣作业相比,使用正运动技术机器视觉运动控制一体机分拣系统的工业机器人进行分拣,不但工作效率高效准确而且稳定性强,在工业分拣系统中具有较大的优势。
00:35
机器视觉运控一体机分拣系统案例分享视频
上期课程,我们讲述了VPLC系列机器视觉运动控制一体机快速入门的实现多轮廓匹配功能,本期课程我们将和大家一起分享如何实现零件分拣的功能。
15:25
(一)检测要求
在工位上同时存在若干个圆环状的零件、稍大尺寸的六边形螺帽零件、稍小尺寸的六边形螺帽零件。现在要求检测出不同形状零件的数量,并发送对应零件的位置供机械手进行抓取。
(二)软件算法
先将图片进行二值化处理,其次计算黑色BLOB连通区域,将BLOB区域结果存放到列表后,对BLOB结果数据进行分析比较。
首先根据面积结果降序排序,将对应序号显示在BLOB结果中心,再根据不同形状零件处理出来后的BLOB面积范围进行分类,并统计对应数量,最后将BLOB的重心位置结果打印在命令与输出窗口。
(一)软件实现
1.打开ZDevelop软件:新建名称为“sorting.zpj”项目→新建“HMI”文件→新建“main.bas”文件,用于编写界面响应函数→新建“global_variable.bas”文件用于存放全局变量并开启HMI自动运行任务→新建“detectParam.bas”文件用于初始化测量参数→新建“camera.bas”文件用于实现相机采集功能→文件添加到项目。
2.设计HMI界面。
3.在“global_variable.bas”文件中定义全局变量,定义完成后运行“Hmi.hmi”文件。
'''''全局变量大部分使用数组结构'''''
''注:basic编程中很多函数会以TABLE(系统的数据结构)做为参数
''table 说明 table 说明
''0 ' 自动二值化阈值 4 暗区域的面积
''2 亮区域的面积 6 连通区域的数量
''20~24 图像信息
'主任务状态
'0 - 未初始化
'1 - 停止
'2 - 运行中
'3 - 正在停止
GLOBAL DIM main_task_state
main_task_state = 1
'采集开关
'0 - 停止采集
'1 - 请求采集
GLOBAL DIM grab_switch
grab_switch = 0
'相机个数
GLOBAL cam_num
cam_num = 0
'相机种类,'zmotion;mvision;basler;mindvision;huaray'
GLOBAL DIM CAMERA_TYPE(16)
CAMERA_TYPE = 'mvision'
' 定义主任务id - 10
GLOBAL DIM main_task_id
main_task_id = 10
'定义连续采集任务id - 9
GLOBAL DIM grab_task_id
grab_task_id = 9
'定义全局图像变量
GLOBAL ZVOBJECT grabImg '采集图像
GLOBAL ZVOBJECT binImg '采集图像
GLOBAL ZVOBJECT disImg '显示图像
'定义常用颜色变量
GLOBAL C_RED, C_GREEN, C_BLUE, C_YELLOW
C_RED = RGB(255, 0, 0)
C_GREEN = RGB( 0,255, 0)
C_BLUE = RGB( 0, 0,255)
C_YELLOW= RGB(255,255, 0)
'检测参数:阈值模式(自动阈值或手动阈值)、低阈值、高阈值、最小面积、最大面积
GLOBAL DIM d_detect_param(5) 'd开头表示数据结构
'显示打印的字符
GLOBAL ShowString(64)
'定义结果变量数组,包括垫圈数量、大螺帽数量、小螺帽数量
GLOBAL DIM d_num_rst(3)
'定义检测消耗时间
GLOBAL DIM d_detect_time
'***********定义读取本地文件功能相关变量**************
''注意,该功能只在使用仿真器时有效
'定义是否使用本地图片标志
GLOBAL DIM d_use_imgfile
'定义本地图片索引
GLOBAL DIM d_index
'定义读取图片的路径
GLOBAL DIM File_Name(100)
'***********结束定义读取本地文件功能相关变量**********
'运行HMI文件
RUN 'Hmi.hmi',1
4.在“detectParam.bas”文件中初始化测量参数。
end
GLOBAL SUB init_detect_param() '初始化测量参数
'初始化检测参数:阈值模式(自动阈值 = 1 或 手动阈值 = 0)、低阈值、高阈值、极性(黑或白)、最大、最小、反向(即结果取反,成功变成失败、失败变成成功)
d_detect_param(0) = 0 '手动阈值
d_detect_param(1) = 200 '低阈值
d_detect_param(2) = 255 '高阈值
d_detect_param(3) = 20000 '最小面积即像素个数
d_detect_param(4) = 50000 '最大面积
for i=0 to 2
d_num_rst(i)=0
next
d_use_imgfile = 1 '默认使用本地图片
d_index = 0
END SUB
5.关联HMI界面控件变量。
6.在“main.bas”文件中添加HMI界面初始化函数并在Hmi系统设置中关联初始化函数。
end
'注:
'凡是要使用Region有关的算子在系统初始化时都要调用ZV_RESETCLIPSIZE(width, height)这个算子设置下图像尺寸,以满足相机分辨率,因为默认的是640*480尺寸
'HMI界面初始化函数
GLOBAL SUB hmi_init()
ZV_RESETCLIPSIZE(2448, 2048)'根据图像分辨率设置图像区域的裁剪尺寸,此处图像分辨率为2448x2048
ZV_LATCHSETSIZE(0, HMI_CONTROLSIZEX(10, 7), HMI_CONTROLSIZEY(10, 7)) '设置锁存的大小
init_detect_param()'初始化测量参数
ZV_SETSYSDBL('CamGetTimeout', 1000) '设置采集超时
ZV_LATCHCLEAR(0) '清空锁存通道0
END SUB
7.在“camera.bas”文件中添加HMI界面中采集相关按钮响应的函数并关联动作函数。(说明:具体实现函数前面两篇课程内容已经有操作演示,此处不做赘述。)
8.在“main.bas”文件中添加HMI界面中测试按钮响应的函数并关联动作函数。
'HMI界面按下测试按钮时响应的函数
GLOBAL SUB btn_test()
TICKS=0
for i=0 to 2
d_num_rst(i)=0
next
ZVOBJECT regionWhite, regionMask, regionBlack,re_connecte,circle_connect
dim loop_num,bigNut_num,smlNut_num
loop_num=0
bigNut_num=0
smlNut_num=0
ZV_REGENFULLIMG(grabImg,regionMask)'生成的覆盖全图的区域到re这个区域变量中
ZV_DILATE (grabImg,binImg,15,15) '对图像进行膨胀处理,分离轻微粘连的零件
'二值化处理
if d_detect_param(0) = 0 then '如果选择手动阈值模式
'根据低阈值和高阈值参数生成白色像素图像regionWhite
ZV_RETHRESH(binImg, regionMask, regionWhite, d_detect_param(1), d_detect_param(2))
'对白色像素区域进行一次1*1的闭运算
ZV_RECLOSING(regionWhite,regionWhite,7,7)
else '如果选择自动阈值模式
Dim autoThresh '定义自动阈值模式下的二值化阈值
'在grabImg图像中的指定区域内对图像进行自动二值化处理,输出二值化区域regionWhite
ZV_REAUTOTHRESH(binImg, regionMask, regionWhite, 0)
'对白色像素区域进行一次1*1的闭运算
ZV_RECLOSING(regionWhite,regionWhite,7,7)
autoThresh = TABLE(0)
? 'autoThresh = ' autoThresh '打印提示信息,当前二值化阈值
endif
ZV_REDIFF (regionMask, regionWhite, regionBlack) '将regionMask区域(检测区域)和regionWhite(白色像素区域)进行差集运算,结果为regionBlack(黑色像素区域)
ZV_REAREA(regionBlack, 4) '计算黑色像素区域的面积(即像素数量)存放到table(4)中
if(TABLE(4) >0) then '如果获取到的黑色像素数量大于0
ZV_RECONNECT(regionBlack,re_connecte) '计算区域的连通区域,存放到re_connecte列表中
zv_refilter(re_connecte,0,d_detect_param(3),d_detect_param(4),0)'对区域列表中的区域进行过滤
zv_refilter(re_connecte,20,0.8,1.2,0)
ZV_LISTCOUNT(re_connecte,6) '获取列表中的连通区域的数量,存放到table(6)中
else
TABLE(6)=0
endif
?'产品个数'TABLE(6) '打印提示信息
'绘制效果图
Dim width, height
ZV_IMGINFO (binImg, 20)'获取grabImg的图像信息
width = TABLE(20)
height = TABLE(21)
ZV_GRAYTORGB(binImg,disImg)'将灰度图转换到RGB图像,用于绘制检测结果图像
ZV_REGION(disImg, regionMask, 0, ZV_COLOR(0,0,0)) '在disImg中绘制黑色的regionMask区域
ZV_REGION(disImg, regionWhite, 0, ZV_COLOR(255,255,255)) '在disImg中绘制白色的regionWhite区域
ZV_RESORT(re_connecte,0,0) '对BLOB结果进行面积降序排序
for i=0 to TABLE(6)-1
ZV_LISTGET(re_connecte,circle_connect,i) '获取列表中序号为i的元素,即依次获取列表中零件连通区域
ZV_REAREACENTER(circle_connect,40) '计算每个零件的面积与中心位置,将数据放入TABLE(40)中
ShowString=TOSTR(i+1,1,0) '将BLOB的数量转换成字符串变量
if (TABLE(40)>47000) AND (TABLE(40)<50000) then '筛选出垫圈
loop_num=loop_num+1
?'序号'ShowString'是圆环:位置为'TABLE(41),TABLE(42)
endif
if (TABLE(40)>33000) AND (TABLE(40)<36000) then '筛选出大螺帽
bigNut_num=bigNut_num+1
?'序号'ShowString'是大螺帽:位置为'TABLE(41),TABLE(42)
endif
if (TABLE(40)>27000) AND (TABLE(40)<29000) then '筛选出小螺帽
smlNut_num=smlNut_num+1
?'序号'ShowString'是小螺帽:位置为'TABLE(41),TABLE(42)
endif
ZV_TEXT(disImg,ShowString,TABLE(41),TABLE(42),140,ZV_COLOR(255,131,6)) '显示结果文本
'?i+1,'面积'TABLE(40)
next
d_num_rst(0)=loop_num
d_num_rst(1)=bigNut_num
d_num_rst(2)=smlNut_num
d_detect_time=ABS(TICKS)
ZV_LATCH(disImg, 0) '在锁存通道0中显示结果图像
END SUB
9.在“main.bas”文件中添加HMI界面中运行按钮响应的函数并关联动作函数。
'HMI界面按下运行按钮时响应的函数
GLOBAL SUB btn_run()
if(2 = main_task_state) then '如果主任务处于运行状态,打印提示信息并退出函数
?'已经开启连续运行任务,请勿重复操作!'
return
endif
if (1 = main_task_state) then '如果主任务处于停止状态
if (0 = PROC_STATUS(main_task_id)) then '如果任务未开启
main_task_state = 2 '主任务状态设置为2,表示正在执行连续任务
RUNTASK main_task_id, main_task '开启主任务
endif
endif
END SUB
'主任务实现函数
main_task:
while(1)
if (3 = main_task_state) then '如果主任务状态处于3即按下停止按钮时
main_task_state = 1 '将主任务状态置为1
exit while '退出循环
endif
delay (500)
'重复执行采集和检测函数
if (d_use_imgfile=1) then
if(d_index=3) then
d_index=0
endif
File_Name='分拣/'+TOSTR(d_index,1,0)+'.bmp' '读取本地图片时图片所在的路径名称
ZV_IMGREAD(grabImg,File_Name,1)
d_index=d_index+1
else
if cam_num = 0 then
?'请先扫描相机!'
return
endif
CAM_SETPARAM('TriggerSoftware', 0) '发送触发指令
CAM_GET(grabImg, 0) '获取一帧图像存放到grabImg变量中
endif
btn_test()
wend
END
10.在“main.bas”文件中添加HMI界面中停止按钮响应的函数并关联动作函数。
'HMI界面按下停止按钮时响应的函数
GLOBAL SUB btn_stop()
if (2 = main_task_state) then '如果主任务状态处于3即正在连续执行任务时
main_task_state = 3 '将主任务状态置为3,退出循环
endif
END SUB
(一)操作步骤
查看运行效果:将本次课程使用到的“分拣”图像复制到ZDevelop软件目录下的flash文件夹项目→再将项目下载到仿真器中→使用本地图片→单次采集→选用手动阈值模式→设置阈值范围→设置筛选的黑色像素区域的面积范围→点击测试,查看单次运行效果→点击运行,查看连续运行效果→结束。