Skip to content

铜卷位置检测及尺寸测量

项目简介

项目背景

利用云台传感器拍摄图像,对需要进行包装入箱的铜箔卷,检测其在铁托盘上的前后左右及高度位置,为机械臂的抓取提供引导,同时读取产品上的二维码信息以匹配装铜箔的木箱规格; 其次检测木箱规格以及在小车上的左右位置,以核对木箱规格,同时为机械臂抓取铜箔入箱提供位置引导信息。

本地图片

相机选型

SICK云台线扫

检测要求

X向精度 ≤ 0.025mm
Y向精度 ≤ 0.03mm
测量周期 ≤ 2s

解决方案

AI-Vision软件针对3D点云进行处理,首先通过Blob工具进行铜卷定位,输出铜卷的位置等信息,再通过圆柱工具拟合出圆柱,从而进行体积的计算 。

设计思路

本地图片

执行效果展示

  • 工程结果展示:

    本地图片

  • HMI结果展示:

    本地图片

项目流程

一、初始化

  1. 选择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)
  1. 选择加载点云工具,获取点云。

二、预处理

本地图片

  1. 选择3D变换工具,将图像绕x轴反方向旋转90度。

  2. 选择3D裁切工具,将圆柱切割开并输出到IM1中。

本地图片

  1. 选择3D下采样工具,减少点云中点的个数,方便后续操作。

  2. 选择3D离群点滤波工具,过滤掉杂点。

本地图片

三、圆柱高度与位置测量

本地图片

  1. 选择3D斑点工具,分割出15个圆柱。

本地图片

  1. 选择lua语言脚本,绑定上一步算子变量中bolb位置变量,编写lua脚本保存保存圆柱位置至文件中。

  2. 选择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)

AI-Vision,让3D测量更简单