在本示例中,您将学习如何启用 OPC UA插件并将 RoboDK 转换为 OPC UA 服务器。我们将使用 UaExpert 软件和 Beckhoff TwinCAT3 TF6100 浏览一些设置。
OPC UA插件允许您配置一些设置,如服务器端口。您还可以选择激活服务器、停用服务器或使用 RoboDK 自动启动服务器。
启用 OPC UA 插件后,选择 OPC UA-OPC-UA 设置来配置 OPC UA 设置。
OPC UA 设置屏幕显示在左侧,如下图所示。
提示:您可以更改 OPC UA 服务器的端口,按 "Start(开始)"按钮更改 OPC UA 服务器的端口。
如果您看到类似 "RoboDK 的 OPC UA 服务器在 4840 端口运行 "的信息,则表示 RoboDK 中的 OPC UA 服务器已启动。
注意:请确保上一节中配置的 OPC UA 端口已在 Windows 防火墙、反病毒软件或系统要求的任何其他安全设置中启用。
您可以与拥有一个或多个机器人的任何 RoboDK 站测试 OPC UA 连接性。
您可以使用UaExpert 软件测试与 RoboDK OPC UA 服务器的连接性。
您可以从统一自动化网站https://www.unified-automation.com/downloads/opc-ua-clients.html 下载免费版 UaExpert 软件。
启动 UaExpert,点击 "+"按钮,插件 RoboDK OPC UA 服务器。
展开 "自定义发现",选择 <双击添加服务器.> 选项,添加 RoboDK OPC UA 服务器。
输入上一步配置的 OPC UA 服务器 URL opc.tcp://127.0.0.1:48440。
以 "无 "安全性连接 OPC UA 服务器。
服务器已配置。
现在,您可以从 UaExpert 连接到 RoboDK OPC UA 服务器。
建立连接后,您可以看到节点和方法。
RoboDK OPC UA 服务器内有一些节点,可让您交换有关您的工作站的一些基本信息。
RoboDK 节点是提供 RoboDK 软件实际版本的节点。
本例中使用的版本为 RoboDK 64 Bit v5.5.3.23031。
仿真速度是一个节点,显示实际仿真速度并允许用户覆盖当前仿真速度。
节点值参考模拟速度的滑动条。
可以从该节点读取当前的模拟结果,并可以覆盖模拟速度。
站节点(Station Node)是一个允许用户获取 RoboDK 中当前站名称的节点。
如下所示,"站 "节点在 RoboDK 中引用了您的 "站名"。
站参数(Station Parameter)和站值(Station Value)是一对设置节点,允许用户获取或设置站内的任何参数。RoboDK OPC UA 服务器将持续监控 "StationParameter "的实际值,并从 "Station Value "节点返回该 "StationParameter "的值。
注意:如果站参数不存在,则返回空字符串。
右键单击 RoboDK 管理站 > 管理站参数,即可查看管理站参数。
在常量参数字段中,可以看到默认台站参数及其值。
台站参数指的是 "参数 "字段,台站值指的是 "值 "字段。
点击 "插件 "按钮,我们就可以创建自己的参数。
添加了一个新的站参数。
输入参数名称和参数值,然后按应用保存。
您还可以获得自己的站点参数。
时间节点是一个可以获取 RoboDK 管理站当前时间的节点。
返回 DataTime 格式的值。
这个节点会不断更新。
RoboDK OPC UA 服务器还提供了一些方法,允许用户动态访问 RoboDK 工作站的数据。
我们只需右击 "方法">"调用 "即可执行该方法。
getItem 是一种允许用户获取 Item 指针的方法。
对于 InputArguments(输入参数),设备名称是必需的,您可以将设备名称想象为您的站名、机器人名称等。项目 ID 是输出参数,用于返回该设备的指针。
在本例中,我收到了 ABB 机器人的项目 ID(指针),其名称为 "ABB_RB1"。
如果项目名称无效或在站内不存在,则返回 0。
getJonits 是一种允许用户根据项目 ID 从站台获取机器人关节值的方法。
Item ID 是 Item 的指针值,可以通过 getItem() 方法获取。
我们将通过 "ABB_RB1 "项目名称获取项目 ID,并返回一个 UInt64 值。
在上一个方法中传递项目 ID 时,会返回关节值。
getJointsStr 是一种允许用户根据字符串值获取关节值的方法。
我们可以在此方法中传递机器人名称(字符串)。
在 "我的工作站 "中,ABB_RB1 是我的机器人名称。
我们只需在机器人名称参数中输入 "ABB_RB1",然后调用该方法--以字符串格式返回关节值。
setJointsStr 是一个允许用户根据字符串值设置机器人关节值的方法。
在机器人名称中,传递的是 ABB_RB1,我们只需在关节参数中传递一个包含关节值的字符串即可。
For example:-0.000000,0.000000,-0.000000,-0.000000,-0.0,-0.000000
您可以使用 Beckhoff TwinCAT 3 软件测试与 RoboDK OPC UA 服务器的连接性。
首先,您可以通过选择 I/O>Devices>Add New Item(I/O>设备>添加新项目)来创建 OPC UA 客户端。
从 OPC >OK 中选择虚拟 OPC UA 设备。
插入 OPC UA 虚拟。
我们需要添加一个 OPC UA 客户端来访问 RoboDK OPC UA 服务器。
选择设备 1 >右键单击 >添加新插件。
选择 "OPC UA 客户端(模块)",然后确定。
插入 OPC UA 客户端。
打开 OPC UA 客户端 > 进入设置选项卡 > 点击 "选择端点 "配置要访问的 OPC UA 服务器端点。
输入 RoboDK OPC UA 服务器 URL 并更新。
按 "Add Nodes(添加节点)"浏览 OPC UA Server 内部的节点。
如果 TwinCAT 与 OPC UA 服务器之间的连接已建立,则可以浏览 OPC UA 服务器的详细信息。
选择所有方法,然后确定。
方法会插入到您的 "配置 "中。
在此字段中配置您的名称前缀。
按 "创建 PLC 代码",从 TwinCAT 创建 PLC 代码。
在项目中创建 OpcUaClient 文件夹,并以 IEC61131-3 功能块格式创建所有 RoboDK 方法。
本节展示了 Beckhoff TwinCAT PLC 与 RoboDK OPC UA 服务器通信的示例程序。
主程序
VAR
bConnected BOOL;
站点指针 :DINT;
iStep :INT;
bStart :BOOL;;
i :INT;
吨 :TON;
bReset :BOOL;
bWrite :BOOL;
TON2 :TON;
bShow BOOL:=TRUE;
bVis BOOL:=True;
END_VAR
VAR
机器人名称 :string(80):='abb_rb1';
项目 ID :ULINT;
arrJoints :array[0..11]of lreal;
strJoints :string(80):='';
arrJointsFromStr:ARRAY[1...11]OF LREAL;
sSeparator :string(1) := ',';
arrJointsCommand:ARRAY[1...11]OF LREAL;
strJointsCommand:STRING(80);
END_VAR
VAR CONSTANT
cStepWaitCmd :INT:=0;
cStepInit :INT:=5;
cStepGetItem :INT:=10;
cStepGetItemReset :INT:=20;
cStepGetItemError :INT:=990;
cStepGetJoints :INT:=30;
cStepGetJointsReset :INT:=40;
cStepGetJointsError :INT:=991;
cStepGetJointsStr :INT:=50;
cStepGetJointsStrReset:INT:=60;
cStepGetJointsStrError:INT:=992;
cStepSetJointStrDelay :INT:=69;
cStepSetJointsStr :INT:=70;
cStepSetJointsStrReset:INT:=80;
cStepSetJointsStrError:INT:=993;
cStepEnd :INT:=300;
cStepWaitReset :INT:=999;
END_VAR
VAR
aSplit :ARRAY[1..11] OF STRING(80);
bResultSplit :BOOL;
调试 :BOOL;
URL :STRING:='http://192.168.3.42:8091';
END_VAR
bConnected:=OPCUA_VirtualClient_RoboDK_Station.bConnected;
案例 iStep OF
cStepWaitCmd:
IF bStart THEN
iStep:=cStepInit;
bStart:=FALSE;
END_IF
cStepInit:
StationPointer:=0;
FOR i :=1 TO 11 DO
arrJoints[i]:=0.0;
arrJointsFromStr[i]:=0.0;
aSplit[i]:='';
结束
IF NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy
AND NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.setJoints.bBusy
AND NOT OPCUA_VirtualClient_RoboDK_Station.setJoints.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy
AND NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError
然后
iStep:=cStepGetItem;
END_IF
iStep:=cStepGetItem;
cStepGetItem:
IF OPCUA_VirtualClient_RoboDK_Station.getItem.bDone THEN
iStep:=cStepGetItemReset;
Item_ID:=OPCUA_VirtualClient_RoboDK_Station.getItem.Item_ID;
ELSIF OPCUA_VirtualClient_RoboDK_Station.getItem.bError THEN
iStep:=cStepGetItemError;
END_IF
cStepGetItemReset:
IF NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy
然后
iStep:=cStepGetJoints;
END_IF
cStepGetJoints:
IF OPCUA_VirtualClient_RoboDK_Station.getJoints.bDone
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy
然后
iStep:=cStepGetJointsReset;
ELSIF OPCUA_VirtualClient_RoboDK_Station.getJoints.bError THEN
iStep:=991;
END_IF
cStepGetJointsReset:
IF NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy
然后
iStep:=cStepGetJointsStr;
END_IF;
cStepGetJointsStr:
IF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bDone
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy
然后
iStep:=cStepGetJointsStrReset;
ELSIF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError THEN
iStep:=cStepGetJointsStrError;
END_IF
cStepGetJointsStrReset:
IF NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy
然后
iStep:=cStepSetJointStrDelay;
END_IF;
cStepSetJointStrDelay:
strJointsCommand:=''; strJointsCommand:=CONCAT(LREAL_TO_STRING(arrJointsCommand[1]),strJointsCommand);
strJointsCommand:=CONCAT(strJointsCommand,',');
strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[2]));
strJointsCommand:=CONCAT(strJointsCommand,',');
strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[3]));
strJointsCommand:=CONCAT(strJointsCommand,',');
strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[4]));
strJointsCommand:=CONCAT(strJointsCommand,',');
strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[5]));
strJointsCommand:=CONCAT(strJointsCommand,',');
strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[6]));
ton2(in:=true,pt:=t#0.2s);
IF TON2.Q THEN
ton2(in:=false);
iStep:=cStepSetJointsStr;
END_IF
cStepSetJointsStr:
如果 (
OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bDone
而不是
OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy
)
OR NOT bWrite
然后
iStep:=cStepSetJointsStrReset;
ELSIF OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError
然后
iStep:=cStepSetJointsStrError;
END_IF
cStepSetJointsStrReset:
bWrite:=FALSE;
OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bExecute:=FALSE;
IF NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError
AND NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy
然后
iStep:=cStepEnd;
END_IF;
cStepEnd:
ton(in:=true,pt:=t#0.1s);
IF TON.Q THEN
ton(in:=false);
IF NOT debug THEN
iStep:=10;
否则
iStep:=cStepSetJointStrDelay;
END_IF;
END_IF
cStepGetItemError:
Item_ID:=0;
iStep:=cStepWaitReset;
cStepGetJointsError:
FOR i :=0 TO 11 DO
arrJoints[i]:=-99999.99;
结束
iStep:=cStepWaitReset;
cStepGetJointsStrError:
strJoints:='';
iStep:=cStepWaitReset;
cStepWaitReset:
IF bReset THEN
iStep:=cStepInit;
bReset:=FALSE;
END_IF;
结束
aSplit[1] := strJoints;
FOR i:=1 TO 7 DO
bResultSplit := FindAndSplit(
pSeparator := ADR(sSeparator)
pSrcString := ADR(aSplit[i])
,pLeftString:= ADR(aSplit[i])
,nLeftSize := SIZEOF(aSplit[i])
,pRightString:= ADR(aSplit[i+1])
,nRightSize := SIZEOF(aSplit[i+1])
,bSearchFromRight := FALSE );
IF NOT bResultSplit THEN
退出;
END_IF
结束
FOR i :=1 TO 6 DO
arrJointsFromStr[i]:=STRING_TO_LREAL(aSplit[i]);
END_FOR;
//
OPCUA_VirtualClient_RoboDK_Station.getItem(
bExecute:=iStep=cStepGetItem
项目名称:=机器人名称
);
OPCUA_VirtualClient_RoboDK_Station.getJoints(
bExecute:=iStep=cStepGetJoints
,Item_ID:=Item_ID,Joints=>arrJoints
);
OPCUA_VirtualClient_RoboDK_Station.getJointsStr(
bExecute:=iStep=cStepGetJointsStr
,机器人名称:=Robot_name,关节=>strJoints
);
IF bWrite THEN
OPCUA_VirtualClient_RoboDK_Station.setJointsStr(
bExecute:=TRUE
,Robot_name:=Robot_name,关节:=strJointsCommand);
END_IF;