Copper Coil Position Detection and Dimension Measurement
Project Introduction
Project Background
Using pan-tilt sensors to capture images, detect the front, back, left, right and height position of copper foil rolls that need to be packaged into boxes on iron pallets, providing guidance for robotic arm gripping, while reading the QR code information on the product to match the wooden box specifications for copper foil; Secondly, detect wooden box specifications and their left and right positions on the trolley to verify the box specifications, while providing position guidance information for robotic arm to grip copper foil into boxes.

Camera Selection
SICK Pan-tilt Line Scan
Detection Requirements
X-axis accuracy ≤ 0.025mm
Y-axis accuracy ≤ 0.03mm
Measurement cycle ≤ 2s
Solution
AI-Vision software processes 3D point clouds, first using Blob tool for copper coil positioning, outputting copper coil position information, then using cylinder tool to fit cylinders for volume calculation.
Design Concept

Execution Result Display
Project result display:

HMI result display:

Project Process
I. Initialization
- Select
Lua Script Languagetool, initialize global variables, create CSV files to receive data.
- Concatenate header strings, save initialization CSV files
Experience
.. Used for string concatenation
part1 = "Hello, "
part2 = "world!"
result = part1 .. part2
print(result) # Output: Hello, world!
, as separator, split each data item
-- Initialize global variables
SetIntVariable('CurrentTime',0)
write = ''
-- Check file, if current file does not exist, generate file
if FileExists("./H.csv") == false then
write = write .. 'Time,'
for i = 1,15,1 do
write = write .. 'h' .. i .. ","
end
write = write .. '\n'
-- "\n" indicates line break
end
-- Write current time to first column of each row
write = write .. os.date("%Y_%m_%d %H:%M;%S") .. ","
-- Write the content to CSV file
WriteToFile("./H.csv",write)
-- Generate string for concatenation
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 current time to first column of each row
write = write .. os.date("%Y_%m_%d %H:%M;%S") .. ","
-- Write the content to CSV file
WriteToFile("./Position.csv",write)- Select
Load Point Cloudtool to obtain point cloud.
II. Preprocessing

Select
3D Transformtool, rotate image 90 degrees in reverse direction around x-axis.Select
3D Croptool, cut the cylinder and output to IM1.

Select
3D Downsampletool, reduce number of points in point cloud for easier subsequent operations.Select
3D Outlier Filtertool, filter out noise points.

III. Cylinder Height and Position Measurement
- Select
3D Blobtool, segment 15 cylinders.

Select
Lua Script, bind blob position variables in operator variables from previous step, write Lua script to save cylinder positions to file.Select
3D Cylindertool, fit copper coils into cylinders

IV. Data Saving
Select Lua Script, bind operator variables output from previous step (two top coordinates of cylinder), calculate dimension information and save to file.
Concatenate fitted cylinder dimension information to string and save string to global variable
Save individual cylinder dimension information to global variable
Experience
string.format is used for formatting strings %.nf formats floating-point numbers to n decimal places.
pi = 3.14159 str = string.format("Pi is approximately %.3f", pi) print(str) -- Output: Pi is approximately 3.141
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"
-- Write data to table
WriteToFile("./H.csv",write)