Appearance
铜卷位置检测及尺寸测量
项目简介
项目背景
利用云台传感器拍摄图像,对需要进行包装入箱的铜箔卷,检测其在铁托盘上的前后左右及高度位置,为机械臂的抓取提供引导,同时读取产品上的二维码信息以匹配装铜箔的木箱规格; 其次检测木箱规格以及在小车上的左右位置,以核对木箱规格,同时为机械臂抓取铜箔入箱提供位置引导信息。
相机选型
SICK云台线扫
检测要求
X向精度 ≤ 0.025mm
Y向精度 ≤ 0.03mm
测量周期 ≤ 2s
解决方案
AI-Vision软件针对3D点云进行处理,首先通过Blob工具进行铜卷定位,输出铜卷的位置等信息,再通过圆柱工具拟合出圆柱,从而进行体积的计算 。
设计思路
执行效果展示
工程结果展示:
HMI结果展示:
项目流程
一、初始化
- 选择
Lua脚本语言
工具,全局变量初始化,创建待接收数据的csv文件。
- 拼接表头字符串,保存初始化csv文件
经验
.. 用于string类型字符串拼接
part1 = "Hello, "
part2 = "world!"
result = part1 .. part2
print(result) # 输出: Hello, world!
,
作为分隔符,分割每个数据项
lua
--初始化全局变量
SetIntVariable('CurrentTime',0)
write = ''
--对文件进行判断,如果当前文件不存在,则生成文件
if FileExists("./H.csv") == false then
write = write .. 'Time,'
for i = 1,15,1 do
write = write .. 'h' .. i .. ","
end
write = write .. '\n'
--"\n"表示换行
end
-- 每行第一列写入当前时间
write = write .. os.date("%Y_%m_%d %H:%M;%S") .. ","
-- 将刚才的内容写入csv文件中
WriteToFile("./H.csv",write)
--生成用于拼接的字符串
write = ''
if FileExists("./Position.csv") == false then
write = write .. 'Time,'
for i = 1,15,1 do
write = write .. 'x' .. i .. ","
write = write .. 'y' .. i .. ","
write = write .. 'z' .. i .. ","
write = write .. ','
end
write = write .. '\n'
end
-- 每行第一列写入当前时间
write = write .. os.date("%Y_%m_%d %H:%M;%S") .. ","
-- 将刚才的内容写入csv文件中
WriteToFile("./Position.csv",write)
- 选择
加载点云
工具,获取点云。
二、预处理
选择
3D变换
工具,将图像绕x轴反方向旋转90度。选择
3D裁切
工具,将圆柱切割开并输出到IM1中。
选择
3D下采样
工具,减少点云中点的个数,方便后续操作。选择
3D离群点滤波
工具,过滤掉杂点。
三、圆柱高度与位置测量
- 选择
3D斑点
工具,分割出15个圆柱。
选择
lua语言脚本
,绑定上一步算子变量中bolb位置变量,编写lua脚本保存保存圆柱位置至文件中。选择
3D圆柱
工具,将铜卷拟合成圆柱
四、数据保存
选择lua语言脚本
,绑定上一步输出的算子变量(圆柱的两顶点坐标),计算得到尺寸信息并保存至文件中。
拼接拟合的圆柱尺寸信息到字符串并将字符串保存到全局变量
保存单个圆柱尺寸信息到全局变量
经验
string.format 用于格式化字符串 %.nf表示将浮点数格式化为保留 n 位小数。
pi = 3.14159 str = string.format("Pi is approximately %.3f", pi) print(str) -- 输出: Pi is approximately 3.141
lua
write = ""
write = write .. string.format("%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f,"
,math.abs(Circle1.Bottom.X - Circle1.Top.X),math.abs(Circle2.Bottom.X - Circle2.Top.X),
math.abs(Circle3.Bottom.X - Circle3.Top.X),math.abs(Circle4.Bottom.X - Circle3.Top.X),
math.abs(Circle3.Bottom.X - Circle5.Top.X),math.abs(Circle6.Bottom.X - Circle3.Top.X),
math.abs(Circle3.Bottom.X - Circle7.Top.X),math.abs(Circle8.Bottom.X - Circle3.Top.X),
math.abs(Circle3.Bottom.X - Circle9.Top.X),math.abs(Circle10.Bottom.X - Circle3.Top.X),
math.abs(Circle3.Bottom.X - Circle11.Top.X),math.abs(Circle12.Bottom.X - Circle3.Top.X),
math.abs(Circle3.Bottom.X - Circle13.Top.X),math.abs(Circle14.Bottom.X - Circle3.Top.X),
math.abs(Circle3.Bottom.X - Circle15.Top.X))
SetFloatVariable("h" .. "1" ,math.floor(1000*math.abs(Circle1.Bottom.X - Circle1.Top.X))/1000)
SetFloatVariable("h" .. "2" ,math.floor(1000*math.abs(Circle2.Bottom.X - Circle2.Top.X))/1000)
SetFloatVariable("h" .. "3" ,math.floor(1000*math.abs(Circle3.Bottom.X - Circle3.Top.X))/1000)
SetFloatVariable("h" .. "4" ,math.floor(1000*math.abs(Circle4.Bottom.X - Circle4.Top.X))/1000)
SetFloatVariable("h" .. "5" ,math.floor(1000*math.abs(Circle5.Bottom.X - Circle5.Top.X))/1000)
SetFloatVariable("h" .. "6" ,math.floor(1000*math.abs(Circle6.Bottom.X - Circle6.Top.X))/1000)
SetFloatVariable("h" .. "7" ,math.floor(1000*math.abs(Circle7.Bottom.X - Circle7.Top.X))/1000)
SetFloatVariable("h" .. "8" ,math.floor(1000*math.abs(Circle8.Bottom.X - Circle8.Top.X))/1000)
SetFloatVariable("h" .. "9" ,math.floor(1000*math.abs(Circle9.Bottom.X - Circle9.Top.X))/1000)
SetFloatVariable("h" .. "10" ,math.floor(1000*math.abs(Circle10.Bottom.X - Circle10.Top.X))/1000)
SetFloatVariable("h" .. "11" ,math.floor(1000*math.abs(Circle11.Bottom.X - Circle11.Top.X))/1000)
SetFloatVariable("h" .. "12" ,math.floor(1000*math.abs(Circle12.Bottom.X - Circle12.Top.X))/1000)
SetFloatVariable("h" .. "13" ,math.floor(1000*math.abs(Circle13.Bottom.X - Circle13.Top.X))/1000)
SetFloatVariable("h" .. "14" ,math.floor(1000*math.abs(Circle14.Bottom.X - Circle14.Top.X))/1000)
SetFloatVariable("h" .. "15" ,math.floor(1000*math.abs(Circle15.Bottom.X - Circle15.Top.X))/1000)
write = write .. "\n"
-- 将数据写入表中
WriteToFile("./H.csv",write)