Appearance
连接器Pin针正位度检测
项目简介
项目背景
汽车连接器外形复杂,部分PIN针会被外壳包围,且PIN针十分微小,针尖细,具有高反射性,检测难度高。经过质检的PIN针直接影响后续产品的装配,导致最终产品在使用时出现连接不稳定、接触不良或直接报废。
相机选型
LMI激光线扫相机 Gocator2430
检测要求
测量精度 ≤ 0.02mm
测量重复性 ≤ 0.004mm
测量周期 ≤ 1s
解决方案
AI-Vision采用Pin针匹配集成算子,一键得出所有的Pin高度并判断是否符合标准,降低了用户的使用难度同时提升工程运行速度。
设计思路
执行效果展示
工程结果展示:
左边部分:
右边部分:
HMI结果展示:
项目流程
一、初始化
- 选择
Lua脚本语言
工具,全局变量初始化,创建待接收数据的csv文件。
经验
.. 用于string类型字符串拼接
part1 = "Hello, "
part2 = "world!"
result = part1 .. part2
print(result) # 输出: Hello, world!
,
作为分隔符,分割每个数据项
lua
--生成用于拼接的字符串
write = ""
--定义csv的列头内容
csvHead = "Time,"
for i=1,196,1 do
csvHead = csvHead .. "pin" .. i .. ","
end
csvHead = csvHead .. "\n"
--创建y文件,脚本第一次运行时,没有就创建
if FileExists("./196pin_X.csv") == false then
PrintToFile("./196pin_X.csv", csvHead)
end
--创建y文件
if FileExists("./196pin_Y.csv") == false then
PrintToFile("./196pin_Y.csv", csvHead)
end
--创建H文件
if FileExists("./196pin_H.csv") == false then
PrintToFile("./196pin_H.csv", csvHead)
end
--创建SideX文件
if FileExists("./196pin_SideX.csv") == false then
PrintToFile("./196pin_SideX.csv", csvHead)
end
--创建SideY文件
if FileExists("./196pin_SideY.csv") == false then
PrintToFile("./196pin_SideY.csv", csvHead)
end
--创建SideH文件
if FileExists("./196pin_SideH.csv") == false then
PrintToFile("./196pin_SideH.csv", csvHead)
end
--创建Result文件
if FileExists("./196pin_Result.csv") == false then
PrintToFile("./196pin_Result.csv", csvHead)
end
选择
加载点云
工具,获取点云。选择
3D裁切
工具,将点云复制一份到IM1(IM0不动,后面可以再次使用)。选择
3D变换
工具,将点云进行90度的旋转。选择
3D裁切
工具,将IM1点云复制到IM3,用于右边部分定位及Pin针测量。
二、预处理
选择
多点定位
工具,选择4个边界的pin针,通过4个Pin针的位置计算出中心位置,根据中心位置进行点云XY位置调整。选择
3D区域
工具,根据现场要求选择区域,合并成一个大的区域并输出到寄存器中。选择
3D平面
工具,绑定3D区域
工具输出的区域,拟合平面。
三、三个区域Pin针测量
- 选择
3D裁切
工具复制IM3点云到IM6:用于右边第二部分的Pin针测量
提示
使用并行调用子程序时,每个子程序需要在不同的IM执行。
选择
3D离群点滤波
工具,去除待测Pin针区域周围的噪点。选择
3D方形探针
工具,选择中间一行pin针,根据选取到的pin针的中心点坐标,拟合一条直线。
选择
3D位置调整
工具,根据上一步输出的直线,调整点云XY位置。选择
Pin针配方创建工具
,设置box框选待检测区域Pin针,设置Pin针参数,输出当前Pin针区域的配方文件。
- 选择
Pin针匹配2
工具,设置box框选待检测区域Pin针,设置Pin针参数,设置配方比对并选择上一步输出的配方文件。
右边部分处理逻辑和左半部分的一样,可参考该节的流程。
四、结果保存csv及数据库中
- 数据保存到csv文件:选择
lua语言脚本
工具
绑定三个
Pin针匹配
工具输出的结果变量,绑定判断是否保存csv的全局变量编辑lua脚本,设置七个变量,分别用来拼接位置信息,高度信息,Pin针间隔信息,测量结果。
保存结果到csv文件
经验
string.format 用于格式化字符串 %.nf表示将浮点数格式化为保留 n 位小数。
pi = 3.14159 str = string.format("Pi is approximately %.3f", pi) print(str) -- 输出: Pi is approximately 3.141
lua
-- 保存到csv
--获取当前时间
time = os.date("%Y_%m_%d %H:%M:%S") .. ","
write_x = time
write_y = time
write_h = time
write_sidex = time
write_sidey = time
write_sideh = time
write_result = time
--获取1-105pin的数据
for i = 1, 105, 1 do
-- 获取保存到csv数据
--string.format中已经有了"%f,"格式,不需要再单独添加","
write_x = write_x .. string.format("%.3f,", Pin_1_105.pin_position_x[i])
write_y = write_y .. string.format("%.3f,", Pin_1_105.pin_position_y[i])
write_h = write_h .. string.format("%.3f,", Pin_1_105.pin_position_height[i])
write_sidex = write_sidex .. string.format("%.3f,", Pin_1_105.pin_position_side_x[i])
write_sidey = write_sidey .. string.format("%.3f,", Pin_1_105.pin_position_side_y[i])
write_sideh = write_sideh .. string.format("%.3f,", Pin_1_105.pin_position_side_height[i])
write_result = write_result .. Pin_1_105.pin_result[i] .. ","
end
--获取106-111pin的数据
for i = 1, 6, 1 do
-- 获取保存到csv数据
write_x = write_x .. string.format("%.3f,", Pin_106_111.pin_position_x[i])
write_y = write_y .. string.format("%.3f,", Pin_106_111.pin_position_y[i])
write_h = write_h .. string.format("%.3f,", Pin_106_111.pin_position_height[i])
write_sidex = write_sidex .. string.format("%.3f,", Pin_106_111.pin_position_side_x[i])
write_sidey = write_sidey .. string.format("%.3f,", Pin_106_111.pin_position_side_y[i])
write_sideh = write_sideh .. string.format("%.3f,", Pin_106_111.pin_position_side_height[i])
write_result = write_result .. Pin_106_111.pin_result[i] .. ","
end
--获取112-196pin的数据
for i = 1, 85, 1 do
-- 获取保存到csv数据
write_x = write_x .. string.format("%.3f,", Pin_112_196.pin_position_x[i])
write_y = write_y .. string.format("%.3f,", Pin_112_196.pin_position_y[i])
write_h = write_h .. string.format("%.3f,", Pin_112_196.pin_position_height[i])
write_sidex = write_sidex .. string.format("%.3f,", Pin_112_196.pin_position_side_x[i])
write_sidey = write_sidey .. string.format("%.3f,", Pin_112_196.pin_position_side_y[i])
write_sideh = write_sideh .. string.format("%.3f,", Pin_112_196.pin_position_side_height[i])
write_result = write_result .. Pin_112_196.pin_result[i] .. ","
end
--保存到csv,每个检测结束后都添加一个换行符
write_x = write_x
write_y = write_y
write_h = write_h
write_sidex = write_sidex
write_sidey = write_sidey
write_sideh = write_sideh
write_result = write_result
--HMI来控制是否保存csv文件
if isSaveCSV == 1 then
WriteLineToFile("./196pin_X.csv", write_x)
WriteLineToFile("./196pin_Y.csv", write_y)
WriteLineToFile("./196pin_H.csv", write_h)
WriteLineToFile("./196pin_SideX.csv", write_sidex)
WriteLineToFile("./196pin_SideY.csv", write_sidey)
WriteLineToFile("./196pin_SideH.csv", write_sideh)
WriteLineToFile("./196pin_Result.csv", write_result)
end
- 保存结果用于HMI显示:选择
lua语言脚本
工具
绑定三个
Pin针匹配
工具输出的结果变量创建空数组分别用于存储Pin针高度,OKNG数据以及所有输出数据到数据库
循环获取三个
Pin针匹配
工具输出结果,保存数据到创建的空数组;保存用于存储所有数据数组在全局变量,用于HNI调用显示;高度数据及OKNG结果写入数据库
经验
table.insert 是 Lua 中用于向表中插入元素的函数 table.insert(table1, [pos,] value) table1:需要插入元素的表。 pos(可选):插入位置。如果不提供,默认将值追加到表的末尾。 value:要插入的值。
local table1 = {"w", "b"} table.insert(table1, "v") -- 在末尾插入 "v" print(table1) -- 输出: ["w","b","v",] print(table1[1]) -- 输出: w
lua
-- HMI显示
--定义方法:判断数组中是否有指定数据。
function tableContains(tab, val)
for index, value in ipairs(tab) do
if value == val then
return true
end
end
return false
end
-- 定义存数据库的变量
local sqlData = {}
local dataResult = {}
local currentTable = {}
--获取1-105pin的数据
for i = 1, 105, 1 do
--保存测量变量,用于HMI显示,取哪几个pin的数据,需要根据实际情况来写if的条件
if i % 21 == 0 or i % 21 == 1 then
SetFloatVariable("value_h" .. tostring(i), Pin_1_105.pin_position_height[i])
pinRecipe = GetRecipeSet(i - 1)
local table1 = {}
table1["PinIndex"] = "H" .. tostring(i)
table1["PinHightStd"] = string.format("%.3f", pinRecipe.PinHight)
table1["PinHightMax"] = pinRecipe.PinHightMax
table1["PinHightMin"] = pinRecipe.PinHightMin * -1
table1["PinHight"] = string.format("%.3f", Pin_1_105.pin_position_height[i])
table1["result"] = Pin_1_105.pin_result[i]
--数组中插入数据 OK 高度 目前所有变量
table.insert(dataResult, Pin_1_105.pin_result[i])
table.insert(sqlData, Pin_1_105.pin_position_height[i])
table.insert(currentTable, table1)
end
end
--获取106-111pin的数据
for i = 1, 6, 1 do
SetFloatVariable("value_h" .. tostring(i + 105), Pin_106_111.pin_position_height[i])
pinRecipe = GetRecipeSet(i + 105 - 1)
local table1 = {}
table1["PinIndex"] = "H" .. tostring(i + 105)
table1["PinHightStd"] = string.format("%.3f", pinRecipe.PinHight)
table1["PinHightMax"] = pinRecipe.PinHightMax
table1["PinHightMin"] = pinRecipe.PinHightMin * -1
table1["PinHight"] = string.format("%.3f", Pin_106_111.pin_position_height[i])
table1["result"] = Pin_106_111.pin_result[i]
table.insert(dataResult, Pin_106_111.pin_result[i])
table.insert(sqlData, Pin_106_111.pin_position_height[i])
table.insert(currentTable, table1)
end
--获取112-196pin的数据
for i = 1, 85, 1 do
--保存测量变量,用于HMI显示
if i % 17 == 0 or i % 17 == 1 then
SetFloatVariable("value_h" .. tostring(i + 111), Pin_112_196.pin_position_height[i])
pinRecipe = GetRecipeSet(i + 111 - 1)
local table1 = {}
table1["PinIndex"] = "H" .. tostring(i + 111)
table1["PinHightStd"] = string.format("%.3f", pinRecipe.PinHight)
table1["PinHightMax"] = pinRecipe.PinHightMax
table1["PinHightMin"] = pinRecipe.PinHightMin * -1
table1["PinHight"] = string.format("%.3f", Pin_112_196.pin_position_height[i])
table1["result"] = Pin_112_196.pin_result[i]
table.insert(dataResult, Pin_112_196.pin_result[i])
table.insert(sqlData, Pin_112_196.pin_position_height[i])
table.insert(currentTable, table1)
end
end
--保存实时显示到HMI的数据
--println(ConvertTableToJson(currentTable))
SetStringVariable("alltable", ConvertTableToJson(currentTable))
--保存到数据库的数据表头
fileds = { "h1", "h21", "h22", "h42", "h43", "h63", "h64", "h84", "h85", "h105", "h106", "h107", "h108", "h109",
"h110", "h111", "h112", "h128", "h129", "h145", "h146", "h162", "h163", "h179", "h180", "h196", "OKNG" }
--脚本开头设置的方法使用:用来判断数组中是否有该数据
if tableContains(dataResult, "NG") then
table.insert(sqlData, 0)
else
table.insert(sqlData, 1)
end
--数据写入数据库中(高度结果)
WriteHmiData("196pin_H", fileds, sqlData)
经验提炼
核心步骤:
创建配方
根据配方匹配点云并判断结果