【教程】工业应用场景下的M5Stack UnitV2应用之不良品筛选
本帖最后由 沧海笑1122 于 2021-7-7 18:55 编辑【教程】工业应用场景下的M5Stack UnitV2应用之不良品筛选
【项目故事】 这是一个严肃的话题,从流水线产品质量控制、到矿石分选,利用AI技术,将不良品或者不同种类的矿石进行分选,都是非常常见的工业AI应用场景。 我们先看一下真实的工业场景,图片来自网络(http://www.tjmeiteng.com/)。这是一个原煤分选的案例,识别装置使用了视觉+X光等双源方式,来判别是精煤还是矸石,用识别后的结果(目标物的坐标)驱动储气罐+电磁阀,对需要分选的对象(精煤或者矸石)进行吹选,落在不同的仓内,从而达到分选目的。 本文尝试使用M5Stack出品的最新Linux AI智能摄像头UnitV2,搭建一个模拟工业应用场景下的不良品筛选功能。我们看看成品的运行状况。▶▶▶https://www.bilibili.com/video/BV1Vq4y1x7o1/
我们看到,上一个工序形成的一个个零件,均匀布撒在传送带上。良品上面有一个螺丝,而“不良品”我们设定是漏装这颗螺丝的零件。经过AI摄像头后,会通过目标检测功能,识别出零件的类别(良品还是不良品)以及兴趣框的左上角坐标、兴趣框长宽等四个数据,通过uart串口,将json格式的识别结果发送到一台M5Stack Basic上,后者会进行简单的数据统计(良品、不良品以及总零件数),良品通过时,会以一个1/4拍的低音A来告知,不良品被发现时,会发出一个1/4拍的高音A来警示用户。对于不良品,M5StackBasic将驱动两只电磁阀,喷出压缩空气,将不良品吹至不良品仓,从而完成分选。这个项目的推荐评级:有趣度:四星★★★★难度:三星★★★同样是一个易于上手复现的玩具,却可以真实再现工业场景。下面我们就一起动手试试吧。
【硬件准备】
内容数量型号或参数备注
1Linux AI摄像头1M5Stack UnitV2AI识别模块
2M5Stack Basic1
执行元件
3电动传送带127*6.6*8.6cm(长宽高)儿童科教玩具,来自网购,自带3V电机
4电磁阀2台湾新恭12V 电磁气阀一进一出
5压力水壶
2
带自锁功能
6硅胶软管、连接件若干
喷吹用管路以及连接件
7铜质天线1
制作空气喷嘴
8玩具积木模块10乐高作为良品、不良品样本
在这里穿插一下背景知识,介绍一下基于Linux的新品M5Stack UnitV2。
我原先文章中的AI摄像头是基于K210的,这次UnitV2是M5Stack最新推出的一款高效率的AI识别模块, 采用Sigmstar SSD202D(集成双核Cortex-A7 1.2Ghz处理器)控制核心,集成128MB-DDR3内存,512MBNAND Flash, 1080P摄像头。内嵌Linux操作系统,集成软硬件资源与开发工具。你可以理解为一个由M5Stack高度定制的带摄像头的Linux小电脑,将识别结果用串口送出,格式是标准的json,便于玩家在PC、树莓派或者esp32单片机上将识别结果进一步解析、运用、展示及控制。 【软件准备】
内容型号备注
1UIFLOW1.7.5为了便于Thonny调试,我选择了离线版,在线版功能更强、版本更高
2Thonny IDE3.3.11优秀的轻量级micropython调试工具
3Python jupyter notebook
M5Stack UnitV2内置
4V-trianingV-Training(m5stack.com)M5Stack在线AI训练平台
【主要原理流程图】M5Stack Basic部分:【制作过程】 1、 目标检测模型训练(新一代的v-training)(1) 批量采样 UnitV2本身带有1080P摄像头,支持完整的pytho3(不再是micropython),所以我用python写了一个小程序,实现了对样本的采集,每隔3秒拍摄一张照片,照片320*240,保存在UnitV2里,然后通过http方式访问、下载。本次采样我一共拍摄了190张样本。(2) 模型训练适配UnitV2的训练也同步升级,V-Training(m5stack.com)。官网有比较详细的教程,在此大致描述一下训练过程。第一步:注册训练用户第二步:上传样本,本次上传190张,为提升训练效果,样本是多多益善,尽可能采用实际应用中的环境、采光条件来取样。第三步:建立标签,比如本文建立了两个样本标签,i_yes:良品,i_no:不良品。① 设定为不良品(缺螺丝);②设定为良品
第四步:标记。这个步骤比较枯燥,需要手工将图片中的目标标记出来,同时匹配相应的标签。对残缺不全的目标可以放弃。注意,这个过程中切勿刷新页面,否则前功尽弃。第五步:训练、等待结果返回。如果你漏标了样本,系统也会提醒你完善。 (1) 成果应用 结果返回后,是一个压缩文件,比如我的模型是:v2model_3c6b26928a46a81e.tar。这个文件并不需要像k210那样拷贝到TF卡上,UnitV2提供了AP模式和Ethernet模式连接,我是用后者连接到UnitV2设备,访问域名unitv2.py或IP:10.254.239.1访问预览网页。切换功能至Object Recognition,点击add按键,在本地路径中上传模型即可。此刻就可以看到,在目标检测中,增加了一个模型(就是刚才训练的模型),在UnitV2镜头下放上样品,就可以看到在右侧的结果框,出现识别结果(json格式)。此刻我们可以把UnitV2当成一个AI摄像头,将目标检测结果从串口送出,我们用PC、树莓派或者单片机进行后期的结果处理、展示和执行。本文我们使用esp32为核心的M5StackBasic来作为执行元件。2、 传送带 为了这个工业场景,我在网购平台找到了这款木质结构的微型电机传送带,尺寸是27*6.6*8.6cm(长宽高),电机靠两节1.5V干电池驱动,可以控制正反转。我测试了一下转速,基本满足我的试验要求。很可惜,运输过程中,整个传送带收到了很严重的破损,商家很给力(必须点个赞),重新发货一台。由于是成品,所以可以直接使用。3、 吹选系统(压缩空气装置+电磁阀+管路以及喷嘴)(1) 喷嘴制作
电磁阀系统,由压缩空气装置+电磁阀+管路以及喷嘴组成,喷嘴要求稳定、便于连接、口径合适。我找到了一些收音机天线(铜质镀锌),天线实质就是一节节优质的铜管,用电磨截断、打磨后,我得到了两根内径4mm的铜管,作为我们两只电磁阀的喷嘴。
(2) 压缩空气装置+电磁阀+管路以及喷嘴组装
压缩空气装置就是两只带有自锁功能的压力喷水壶,我把壶嘴做了改装,与硅胶软管连接,电磁阀是执行元件,一端接压力壶,一端接刚才制作的喷嘴。这样就形成了一套完整的压缩空气系统。
注:①是电磁阀驱动板;②是电磁阀(两只)(3) 电控部分以及吹选系统联调:
我在制作“高速水滴碰撞摄影装置”时,制作了一块电磁阀扩展板,扩流采用了ULN2803A 8通道达林顿阵列。本次使用M5StackBasic的第16、17引脚,通过ULN2803A扩流后,驱动2只12V电磁阀。ULN2803A和M5StackBasic的GND相连接。电磁阀系统单独调试,用3.3V点击ULN2803A的相应输入端,验证电磁阀动作可靠、压缩空气排出正常、整个系统无漏气。① 电磁阀引线;②ULN2803达林顿;③12V直流输入4、 系统总装测试
我使用了一个俯拍支架,将UnitV2和M5StackBasic固定在俯拍支架上,准备了两个成品盒,一个放置良品(在传送带末端),另一个放置不良品(在传送带末端垂直于传送带方向)。样品一共准备了十只,乐高积木+连接件(模拟螺丝)构成良品,不良品就是不带连接件的积木块。注:①传送带以及样品;②UnitV2;③M5StackBasic;④电磁阀驱动板;⑤电磁阀;⑥压力壶;⑦零件盒(待分选);⑧传送带开关;⑨有源hub以及俯拍支架底座。
使用UIFLOW设计了UI和基本流程后,主要的调试工作在Thonny IDE完成,这是一个轻量级的python和micropython调试软件。调试M5StackBasic非常方便,调试过程中,可以观察各个变量以及程序节点的状态。
【代码】
一、M5StackBasic侧代码# UNITV2 之传送带质量监测
# 2021-07-04
# 0620 使用Basic 的grove tx=21, rx=22 与V2建立uart通信
# 0620 完成了识别、计数、LED闪动等功能联调
# 0621 编制电磁阀吹零件功能,联调电磁阀+管路以及压力壶
# 0704 在传送带垂直方向安装2只电磁阀,将不良品吹入不良品仓,调试完成
# 沧海
from m5stack import *
from m5ui import *
from uiflow import *
from easyIO import *
import json
setScreenColor(0x222222)
print("Begin...")
# 变量init
rev_str = None
rev_obj = None
vprob = None
vtype = None
vx = None
vy = None
vw = None
vh = None
#vexe 执行控制字,确保目标进入执行框后,只执行一次(计数以及吹不良品)
vexe=0
#c_ok累计良品
c_ok=0
#c_ng累计次品
c_ng=0
#c_total累计总零件数量
c_total=0
#v_timer
v_timer=0
#vobj_x 目标中心的x值
vobj_x =0
#vobj_y 目标中心的y值
vobj_y =0
okorng= None
#UI INIT
title0 = M5Title(title="QC 202106", x=3, fgcolor=0xFFFFFF, bgcolor=0x0000FF)
label0 = M5TextBox(13, 47, "OK=", lcd.FONT_DejaVu40, 0x30f905, rotate=0)
label1 = M5TextBox(9, 94, "NG=", lcd.FONT_DejaVu40, 0xf70606, rotate=0)
label2 = M5TextBox(13, 149, "TOTAL=", lcd.FONT_DejaVu40, 0xf3f4f6, rotate=0)
i_ok = M5TextBox(204, 47, "0", lcd.FONT_DejaVu40, 0x04fe03, rotate=0)
i_ng = M5TextBox(204, 99, "0", lcd.FONT_DejaVu40, 0xf10303, rotate=0)
i_total = M5TextBox(204, 149, "0", lcd.FONT_DejaVu40, 0xFFFFFF, rotate=0)
label3 = M5TextBox(52, 217, "Reset", lcd.FONT_Default, 0xf8db04, rotate=0)
#Uart INIT
uart1 = machine.UART(1, tx=21, rx=22)
uart1.init(115200, bits=8, parity=None, stop=1)
# 电磁阀1:Pin 16 电磁阀2:Pin 17
# 执行函数,将驱动2只电磁阀吹动不良品进入不良品仓
# 本程序中,电磁阀排列在传送带垂直方向。
# 良品使用低音作为指示
def f_exe1(okorng,vobj_y,vobj_x):
if vobj_y>=150 and vobj_y<310 and okorng=="i_no":
speaker.sing(889, 1/4) #不良品声音
digitalWrite(16, 1)
digitalWrite(17, 1)
wait_ms(60)
digitalWrite(16, 0)
digitalWrite(17, 0)
if okorng=="i_yes":
speaker.sing(220, 1/4) #良品声音
def buttonA_wasPressed():
global c_ok,c_ng,c_total
#计数以及变量清零
i_ok.setText('0')
i_ng.setText('0')
i_total.setText('0')
c_ok=0
c_ng=0
c_total=0
pass
btnA.wasPressed(buttonA_wasPressed)
#目标检测函数,检测到良品(不良品),分别进行计数,并且驱动电磁阀吹动不良品
def f_detection(vx,vy,vw,vh,vprob,vtype):
#计算目标坐标
global vexe,c_ok,c_ng,c_total
vobj_x=(vx+vw/2)
vobj_y=(vy+vh/2)
print(vobj_x)
print(vobj_y)
print(vexe)
#目标进入执行框(如x=260~400),则执行一次(计数以及吹不良品)
if vprob>0.5 and vobj_x>260 and vobj_x<400:
print("in exe area")
if vtype=="i_yes" and vexe==0:
c_ok=c_ok+1
i_ok.setText(str(c_ok))
f_exe1(vtype,vobj_x,vobj_y) #绿灯
c_total=c_total+1
i_total.setText(str(c_total))
vexe=1 #确保在整个执行框只动作一次
else:
if vtype=="i_no" and vexe==0:
c_ng=c_ng+1
i_ng.setText(str(c_ng))
c_total=c_total+1
i_total.setText(str(c_total))
f_exe1(vtype,vobj_x,vobj_y) #电磁阀吹动50ms
vexe=1 #确保在整个执行框只动作一次
else:
print("out exe area")
vexe=0
#Main loop
while True:
try:
if uart1.any():
rev_str = json.loads((uart1.read()).decode())
rev_obj=rev_str["obj"]
#print(rev_obj)
for zidian in rev_obj:
#print(type(zidian))
vtype=zidian.get("type")
vprob=zidian.get("prob")
vx=zidian.get("x")
vy=zidian.get("y")
vw=zidian.get("w")
vh=zidian.get("h")
f_detection(vx,vy,vw,vh,vprob,vtype)
#print(vx,vy,vw,vh,vtype,vprob)
wait_ms(2)
#f_detection(vx,vy,vw,vh,vporb,vtype)
except:
print("except")
二、UnitV2侧连续拍摄采样代码import cv2
import time
camera = cv2.VideoCapture(0)
camera.set(3, 320)# width=320
camera.set(4, 240)# height=320
path = "train/0613/b"
ext=".jpg"
cnt=0
def control_white_led(value):
open('/sys/class/gpio/export', 'w').write('0') # Export the GPIO0
open('/sys/class/gpio/gpio0/direction', 'w').write('out') # Set the direction of the GPIO
open('/sys/class/gpio/gpio0/value', 'w').write(str(value)) # Set the calute, '1' or '0'
try:
while True:
ret, frame = camera.read()
if ret:
cnt+=1
fname=path+str(cnt)+ext
#led blink
control_white_led(0)
print(fname+" is saved")
cv2.imwrite(fname,frame)
time.sleep(0.2)
control_white_led(1)
#time.sleep(2.8)
else:
print('OOps, we get some trouble!')
time.sleep(2.8)
except KeyboardInterrupt:
pass
【小结】
[*] 小电脑还是AI摄像头?
UnitV2升级为Linux 系统的AI摄像头后,实际上是一个带有1080P摄像头的完整Linux计算机系统,只是对系统高度定制后,给用户开放了更加便捷、友好的训练、使用界面,尤其是通过grove接口,将识别出来的结果,以json格式传送给上位机进行二次开发利用,用户可以更加关注训练和应用,而无须关注UnitV2的Linux 系统,最好不要把它定位成一个小电脑(虽然它就是一个小电脑,你可以通过SSH进入系统里),而是当成一个友好的AI摄像头,我理解这样是正确的使用方式。
[*] 善用Jupyter Notebook
UnitV2的出厂Linux镜像中集成了JupyterNotebook开发调试工具, Jupyter Notebook是一款网页形式的开发工具,用户可以直接在网页上编写代码和运行代码。这次我写的连续拍摄取样工具,就是在JupyterNotebook上编写、运行的,非常便捷。这也是M5Stack提供给用户的一个方便的调试工具,用好这一工具,往往事半功倍。
[*]性能和温度
本文尝试用一个完整的工业场景,呈现UnitV2在目标检测方面的性能提升,在K210使用中,同一画面多目标往往会出现漏识别、误识别的现象。在UnitV2得到了大幅提升,多目标识别得到了很大改善。会给玩家更多创意实现的可能。比如下图就是我上次写的井字棋,当时使用了遮罩来提升识别率,本次用UnitV2训练后,同一画面多目标的识别是比较顺畅的。 由于集成度高,发热问题也随之而来,所以UnitV2集成了一个内置风扇,来尽可能控制装置温升,在实际运行过程中,也感受到温度的确比较高。看来在兼顾性能、体积以及温度控制等方面还需要做进一步的努力。 今日小暑,万物勃发。 感谢M5Stack开发的新品给玩家以实现创意的可能。感谢笑笑、社区各位师兄的指导帮助。 感谢arduino.cn提供交流平台。
沧海合十。
附上程序附件供学习交流。
沧海笑1122老师出品必是精品,谢谢分享,学习一下。 topdog 发表于 2021-7-7 23:56
沧海笑1122老师出品必是精品,谢谢分享,学习一下。
谢谢师兄支持 Hello!
First of all congrats to your project!
Second of all can you upload or send me a better resolution picture about the UIFlow Blockly code? On the current image I don't really see the block and it would be really important to me to understand the process.
Thank you! HarciMarci 发表于 2022-9-8 14:02
Hello!
First of all congrats to your project!
Hi,Thank you for your attention
UIFLOW just build a simple framework , and I modified the code in Thonny Ide,You can refer to the code,
Good luck.
页:
[1]