首先视觉固定在机器人的Z轴丝杆中心搭配取料,在这过程中我们遇到了以下几个问题:
1.视觉与机械手标定后,发现视觉Y轴方向与机器人Y轴方向相反
2.建立用户坐标系后,物料进行旋转10度左右,进行拍照抓取发现角度没有问题,X和Y的方向不对
3.建立用户坐标系后,用相机中心和丝杆中心在用户坐标系的1号用户坐标,进行(0,0)原点移动,发现都不在视觉的mark中心,以镜像对称的方式移到了另外一边
4.在机械手标定,物料模板标定,机械手取料点标定的正确下,发现Y轴偏移值不对
针对上面的问题情况,分析出现的原因和采取对应的措施如下:
原因:前三个问题都出现在视觉与机械手标定,当视觉固定在Z轴上时,走九点标点方向就会相反
解决办法:在标定过程中,机械手往相反的方向跑就可以
原因:最后一个问题出现在视觉做mark点模板的时候,识别的特征点不对就会导致机械手取料位置不对
解决办法:重新做mark模板标定
-----------------------------------------------以下是封装的函数--------------------------------------------------------
--- <summary>*用三点示教定义和显示用户坐标系(本地坐标系)\n </summary>
--- <argument name="UF_Idx">用户坐标系编号,范围(1,9)。(type:number)\n </argument>
--- <argument name="select_plane">选择示教平面,0为XY平面,1为XZ平面(type:number)\n</argument>
--- <argument name="Base_point">原点。(type:table)\n</argument>
--- <argument name="X_point">X方向点。(type:table) \n</argument>
--- <argument name="Y_or_Z_point">Y方向或Z方向点。(type:table)\n</argument>
--- <argument name="ActiveTilt">启用倾斜,为1时启用,0或nil则不启用,可省略(type:number)\n</argument>
--- <argument name="ActiveOrthogonality">启用非正交,为1时启用,0或nil则不启用,可省略(type:number)\n</argument>
--- <argument name="XScale">X轴比例尺,单位:μm。可省略(type:number)\n</argument>
--- <argument name="YScale">Y轴或Z轴比例尺,单位:μm。可省略(type:number)\n</argument>
function Local(UF_Idx, select_plane, Base_point, X_point, Y_or_Z_point, ActiveTilt, ActiveOrthogonality, XScale, YScale) --用户坐标系三点示教法
--select_plane:0是XY平面,1是XZ平面。
local tValid = _LUA_NONE_ERR
local TmpValid = {}
local tmpIdx = 1
local TmpUserFrameP = {}
local Pn = {}
--传入参数错误判断
if type(UF_Idx) ~= "number" or type(Base_point) ~= "table" or type(X_point) ~= "table" or type(Y_or_Z_point) ~= "table" or type(select_plane) ~= "number" then
motion.ProgramStop(string.format("Function Local(): Argument input type is error!"))
--print("Function Local(): Argument input type is error!", "\n")
--tValid = _LUA_IP_TYPE_ERR
--return tValid
end
if UF_Idx < 1 or UF_Idx > 9 then
motion.ProgramStop(string.format("Function Local():Value of UF_Idx is out of range!"))
--print("Function Local():Value of UF_Idx is out of range!", "\n")
--tValid = _LUA_IP_OUT_RANGE_ERR
--return tValid
end
if type(ActiveTilt) ~= "nil" then
if type(ActiveTilt) ~= "number" then
motion.ProgramStop(string.format("Function Local(): Type of ActiveTilt is error!"))
--print("Function Local(): Type of ActiveTilt is error!", "\n")
--tValid = _LUA_IP_OUT_RANGE_ERR
--return tValid
else
if ActiveTilt < 0 or ActiveTilt > 1 then
motion.ProgramStop(string.format("Function Local():Value of ActiveTilt is out of range!"))
--print("Function Local():Value of ActiveTilt is out of range!", "\n")
--tValid = _LUA_IP_OUT_RANGE_ERR
--return tValid
end
end
end
if type(ActiveOrthogonality) ~= "nil" then
if type(ActiveOrthogonality) ~= "number" then
motion.ProgramStop(string.format("Function Local(): Type of ActiveOrthogonality is error!"))
--print("Function Local(): Type of ActiveOrthogonality is error!", "\n")
--tValid = _LUA_IP_OUT_RANGE_ERR
--return tValid
else
if ActiveOrthogonality < 0 or ActiveOrthogonality > 1 then
motion.ProgramStop(string.format("Function Local():Value of ActiveOrthogonality is out of range!"))
--print("Function Local():Value of ActiveOrthogonality is out of range!", "\n")
--tValid = _LUA_IP_OUT_RANGE_ERR
--return tValid
end
end
end
--索引值
local function_code_write_teach_buffer_1 = 0x00010013
local function_code_write_teach_buffer_2 = 0x01010013
local function_code_write_teach_buffer_3 = 0x02010013
--功能码
local function_code_write_uf_volatile_teach_Point_1 = 0x00011142 + (UF_Idx*0x01000000) ----------原点
local function_code_write_uf_volatile_teach_Point_2 = 0x00012142 + (UF_Idx*0x01000000) -------X方向点
local function_code_write_uf_volatile_teach_Point_3 = 0x00013142 + (UF_Idx*0x01000000) --Y or Z方向点
local function_code_write_uf_XY_Cal = 0x00000141 + (UF_Idx*0x01000000) ----------------计算XY平面教导点
local function_code_write_uf_XZ_Cal = 0x00001141 + (UF_Idx*0x01000000) ----------------计算XZ平面教导点
local function_code_write_uf_Active_Tile_Or = 0x00012F42 + (UF_Idx * 0x01000000) ---------倾斜与非正交
local function_code_write_uf_Active_Scale = 0x00014142 + (UF_Idx * 0x01000000) -----------X,Y轴比例尺
local function_code_save_uf_to_non_volatile_data = 0x00010D41 + (UF_Idx*0x01000000) ---保存使用者坐标系
--写入原点
for k,v in pairs(Base_point) do
Pn[k] = v
end
setmetatable(Pn, P.mt)
TmpUserFrameP = Pn
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_1)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.x)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_2)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.y)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_3)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.z)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_volatile_teach_Point_1)
tmpIdx = tmpIdx + 1
DELAY(0.004)
--写入X方向点
for k,v in pairs(X_point) do
Pn[k] = v
end
setmetatable(Pn, P.mt)
TmpUserFrameP = Pn
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_1)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.x)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_2)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.y)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_3)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.z)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_volatile_teach_Point_2)
tmpIdx = tmpIdx + 1
DELAY(0.004)
--写入Y方向点
for k,v in pairs(Y_or_Z_point) do
Pn[k] = v
end
setmetatable(Pn, P.mt)
TmpUserFrameP = Pn
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_1)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.x)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_2)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.y)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_3)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, TmpUserFrameP.z)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_volatile_teach_Point_3)
tmpIdx = tmpIdx + 1
DELAY(0.004)
--倾斜与非正交
--TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_1)
--tmpIdx = tmpIdx + 1
--DELAY(0.004)
local tmpActiveTile = 0
local tmpValue = 0
if ActiveTilt == 1 then
tmpActiveTile = 1
else
tmpActiveTile = 0 ---------------ActiveTilt(倾斜)为nil或0
end
local tmpOrthogonality = 0
if ActiveOrthogonality == 1 then
tmpOrthogonality = 2
else
tmpOrthogonality = 0 --ActiveOrthogonality(非正交)为nil或0
end
tmpValue = tmpActiveTile + tmpOrthogonality;
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_1)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, tmpValue)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_Active_Tile_Or)
tmpIdx = tmpIdx + 1
DELAY(0.004)
--X,Y轴比例尺
if (type(XScale) ~= "nil" and type(YScale) ~= "nil") then
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_1)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, XScale)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 07, function_code_write_teach_buffer_2)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 08, YScale)
tmpIdx = tmpIdx + 1
DELAY(0.004)
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_Active_Scale)
tmpIdx = tmpIdx + 1
DELAY(0.004)
elseif (type(XScale) == "nil" and type(YScale) ~= "nil") then
motion.ProgramStop(string.format("Function Local():Value of XScale is nil!"))
--print("Function Local():Value of YScale is nil!")
--tValid = _LUA_IP_NIL
--return tValid
elseif (type(XScale) ~= "nil" and type(YScale) == "nil") then
motion.ProgramStop(string.format("Function Local():Value of YScale is nil!"))
--print("Function Local():Value of XScale is nil!")
--tValid = _LUA_IP_NIL
--return tValid
end
--计算XY或XZ平面教导点
if select_plane == 0 then ------XY平面
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_XY_Cal)
tmpIdx = tmpIdx + 1
DELAY(0.004)
--TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_save_uf_to_non_volatile_data)
--DELAY(0.004)
elseif select_plane == 1 then --XZ平面
TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_write_uf_XZ_Cal)
tmpIdx = tmpIdx + 1
DELAY(0.004)
--TmpValid[tmpIdx] = para.Write(0, 2, 06, function_code_save_uf_to_non_volatile_data)
--DELAY(0.004)
else
motion.ProgramStop(string.format("Function Local():Select a plane error!"))
--print("Function Local():Select a plane error!")
--tValid = _LUA_IP_NIL
--return tValid
end
--for i = 1, tmpIdx do
--if (TmpValid[i] > 0x00) then
--print("Function Local(): Parameters written fail!")
--tValid = _LUA_PARA_W_ERR
--return tValid
--end
--end
return tValid
end
function UF_Model(UF_Idx,X,Y,C) --接收视觉发的值建立用户坐标系(注意:视觉发送过来的角度,单位°)
tcmd, Here = motion.GetFeedbackPosition(1)
P_1 = P.new(X, Y, 0, 0, 0, 0, Here.Elbow, Here.Shoulder, Here.Flip, Here.PS, Here.UF, Here.TF, Here.Coord) --Mark点
P_2_x = 100000 * math.cos(math.rad(C)) --X方向点
P_2_y = 100000 * math.sin(math.rad(C))
P_2 = CopyPoint(P_1)
P_2.x = X + P_2_x
P_2.y = Y + P_2_y
P_3_x = 100000 * math.cos(math.rad(C + 90)) --Y方向点
P_3_y = 100000 * math.sin(math.rad(C + 90))
P_3 = CopyPoint(P_1)
P_3.x = X + P_3_x
P_3.y = Y + P_3_y
--print(P_2_x, ",", P_2_y, ", ", P_3_x, ", ", P_3_y, "\n")
Local(UF_Idx, 0, P_1, P_2, P_3) --生成用户坐标系
end
-------------------------------------------以下是动作流程-----------------------------------------------------------------
-
FreePort.ECM_Close(1) --打开以太网作为客户端
repeat
FreePort.ECM_OpenAsClient(1,"192.168.1.10",60000,nil,CR_LF)
local aa = FreePort.ECM_ChkConnect(1)
DELAY(0.1)
until aa == 0
print('相机连接成功',"\n")
FreePort.ECM_Clear(1)
FreePort.ECM_Tx(1,"M1".."\r")
repeat
tcmd,CCDdata=FreePort.ECM_Rx(1)
until tcmd==0
data=string.split(CCDdata,",")
print(data[1],"\n")
print(data[2],"\n")
print(data[3],"\n")
-------------------------------------有两种方法去建立动态用户坐标系--------------------------------------
-----------第一种:使用自己封装的函数去实现
UF_Model(1,data[1]*1000,data[2]*1000,data[3]*1) --建立用户坐标系
--算出视觉mark模板和机械手取料点之间的XY偏差(还用一种方法,生成用户坐标系后,直接用户 坐标系教导点位直接跑)
X_pianyi = 376761 - 501153
Y_pianyi = -320074 + 249979
Quliao = P.new(X_pianyi,Y_pianyi,-201618,0,0,-92729,1,0,0,0,1,0,1)
MovL(Quliao .. P.Z(-50000))
MovL(Quliao)
------------第二种:使用台达提供的功能指令
UF.Clear(2) --先清除上一个用户坐标系
UF.Update.dXYZABC(2,0,data[1]*1000,data[2]*1000,0,0,0,data[3]*1000) --建立用户坐标系
UF.Retain.dXYZABC(2) --写入用户坐标系
ModbusWrite16(0x1B00,1) ---拍照完成
--生成用户坐标系后,用 用户坐标系教导点位3号点
MovL(Quliao .. P.Z(-50000))
MovL(3)