你會從這篇教學中學習到如何利用RoboDK的OPC-UA 插件和其他支持OPC-UA客戶端介面的裝置通信。你需要做的只是在RoboDK軟件中有效其插件,然後新增其功能到你專案。
RoboDK 提供了OPC-UA 插件讓用家新增OPC-UA連接功能到你的專案,在默認設定中,RoboDK會無效這個插件,而你需要手動將它有效化。當插件有效化後,每次起動RoboDK時你就會看到這個插件的相關設定。
請追隨以下的步驟來使用OPC-UA 插件。
1.從菜單中選擇Tools>-Add-ins
2.雙擊OPC-UA.
你會看到在工具列上新增了OPC-UA功能的按鍵.
https://robodk.com/addin/com.robodk.plugin.opc-ua.
當你安裝OPC UA插件後,你會看到其插件的相關菜單和按鍵。
在這篇教學中你會知道如何在RoboDK中起動OPC UA 伺服器,然後使用UaExpert軟件和Beckhoff TwinCAT3 TF6100來測試其功能。
你可以利用在OPC UA插件去設定自己的OPC UA連接設定,例如接口號碼或IP地址,,伺服器的使用不使用等等。當RoboDK 專案OPC UA插件被激活後,你可以從OPC UA-OPC-UA Settings執行這些相關設定。
如圖所示,OPC UA的設定畫面會表示在你的RoboDK軟件左方。
提示:你可以根據自己的應用來修改OPC UA 伺服器的接口號碼/ IP地址,然後點擊”start”去起動你的OPC UA 伺服器。
假若你看到“RoboDK’s OPC UA server running on port 4840”的信息,那就代表你的OPC UA 伺服器已經起動成功。
你可以在任何的RoboDK工作站上測試一台或複數的機械人的OPC UA 連接性能。
你可以使用免費軟UaExpert來測試RoboDK OPC UA伺服器的性能。請點擊以下連結下載安裝檔案。
https://www.unified-automation.com/downloads/opc-ua-clients.html.
執行UaExpert軟件,點擊+按鈕去新增OPC UA伺服器。
展開Custom Discovery菜單,雙擊<Double clicks to Add Server.>來新增伺服器。
輸入你的OPC UA伺服器地址。
選擇None作為安全連接選項,點擊OK開始連接OPC UA伺服器。
你在UaExpert新增了OPC UA伺服器。
現在你可以利用UaExpert嘗試連接OPC UA伺服器。
如果連接成功,你會看到OPC UA伺服器內的所有Node 和Method。
RoboDK OPC UA伺服器提供不同的node讓其他裝置可以讀寫RoboDK工作站的情報。
你可以使用RoboDK node來取得RoboDK的軟件版本。
如圖所示,我們在這篇教學中使用了RoboDK 64 Bit v5.5.3.23031。
你可以使用Simulation Speed node來讀寫RoboDK工作站的仿真速度。
SimulationSpeed的現在值是和RoboDK工作站上的仿真速度設定是一樣,而且你可以直接更改SimulationSpeed node的數值來覆寫這個設定。
你可以使用Station Node來讀取RoboDK工作站的名稱。
如圖所示,我們在這篇教學中使用了RoboDK工作站名稱是”New Station(1)”。
你可以使用Station Parameter 和Station Value這對Node來讀寫RoboDK工作站的參數。RoboDK OPC UA伺服器會重覆監視Station Parameter,然後根據其現在值去讀取工作站參數的現在值,最後將其值傳送到Station Value Node。
你可以右擊view >點擊Station parameters來確認自己工作站的參數。
工作站所有默認的參數和其參數值都表示在Constant parameters的表格內。
Stationparameter是等於Parameter,而StationValue是相等於Value。
你也可以點擊“Add“來新增屬於自己工作站的參數。
如圖所示,你的工作站新增了一個參數。
輸入參數的名稱和數值,然後點擊Apply保存。
然後你可以利用StationParameter和StationValue來讀取這個參數。
你可以使用time node來讀取RoboDK工作站的現在時間。
工作站的現在時間會以DataTime格式的儲存下來。
然後這個Node是不停更新的。
RoboDKOPC UA伺服器也提供了一系列的methods讓使用者讀寫RoboDK OPC UA伺服器的情報。我們可以右擊Method>點擊Call來執行Method。
你可以使用getItem來讀取RoboDK工作站內物件的指標。
getItem需要Device Name作為InputArguments,你可以想像, Device Name是任何被配置在RoboDK工作站的其物件名稱,然後OutputArguments就會輸出指定物件的指標。
我們會在Item Name輸入“ABB_RB1”作為InputArguments,然後你會取得工作站中ABB 機械人的指標。
如果你輸入了無效Item Name,Method 的執行結果會是0。
getJonits會根據Item ID來讀取其工作站內機械人的關節情報(配列格式)。
Item ID是工作站物件的指標值,你可以使用剛才所介紹的getItem()來讀取其現在值。
所以我們要先從getItem()中取得工作站內的“ABB_RB1”指標值。
然後你只需要將那個指標值剪報到getJoints method的Item ID上,然後執行method;你就會取得機械人關節的現在值。(配列格式)
getJonits會根據Item ID來讀取其工作站內機械人的關節情報(文字格式)。
利用這個method時,我們不再需要工作站物件的指標,取而代之的是工作站其物件的名稱(文字格式)。
我們現在嘗試利用getJonits method來讀取ABB_RB1現時的關節值。
執行method前,我們只需然在Robot name參數中輸入“ABB_RB1”,其機械人現時的關節值就會自動返回。
我們可以使用setJointsStr method來設定機械人的關節位置(文字列格式)。
在Robot name參數中輸入ABB_RB1然後在Joints參數中輸入你想設定的關節位置,然後執行。
例子:-0.000000,0.000000,-0.000000,-0.000000,-0.0,-0.000000
新增TwincCAT3專案,然後選擇I/O>右擊>點下Add New Item。
從OPC菜單中選擇Virtual OPC UA Device然後點擊OK。
OPC UA Virtual 被新增在你的專案中。
現在我們需要在TwinCAT專案中新加RoboDK OPC UA 伺服器。選擇Device 1 >右擊>點擊Add New Item。
從菜單中選擇OPC UA Client(Module)然後OK。
你的專案中追加了OPC UA 客戶介面。
打開OPC UA 客戶介面然後點擊“Select Endpoint”去設定你要讀取的OPC UA伺服器。
輸入你的OPC UA伺服器地址然後點擊Update。
點擊 “Add Nodes” 你就可以用瀏覽其OPC 伺服器的Node和Method。
如果TwinCAT和OPC 伺服器是已經連接,你就可以瀏覽到所有的情報。
選擇所有的Methods然後按下OK。
RoboDK OPC 伺服器中所有的method都追加了在你的專案中。
設定你自動生成程式的預設名稱。
點擊“Create Plc Code”。
OpcUaClient檔案夾會被新增到你的PLC專案中,然後你會找到所有的RoboDK Method會被自動轉換成IEC61131-3 功能塊格式。
.以下是利用剛才自動生成的功能塊編寫PLC程式來讀寫RoboDK OPC UA 伺服器的程式例子。
PROGRAM MAIN
VAR
bConnected :BOOL;
StationPointer :DINT;
iStep :INT;
bStart :BOOL;;
i :INT;
TON :TON;
bReset :BOOL;
bWrite :BOOL;
TON2 :TON;
bShow :BOOL:=TRUE;
bVis :BOOL:=True;
END_VAR
VAR
Robot_name :STRING(80):='ABB_RB1';
Item_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;
debug :BOOL;
URL :STRING:='http://192.168.3.42:8091';
END_VAR
bConnected:=OPCUA_VirtualClient_RoboDK_Station.bConnected;
CASE 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]:='';
END_FOR
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
THEN
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
THEN
iStep:=cStepGetJoints;
END_IF
cStepGetJoints:
IF OPCUA_VirtualClient_RoboDK_Station.getJoints.bDone
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy
THEN
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
THEN
iStep:=cStepGetJointsStr;
END_IF;
cStepGetJointsStr:
IF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bDone
AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy
THEN
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
THEN
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:
IF (
OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bDone
AND NOT
OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy
)
OR NOT bWrite
THEN
iStep:=cStepSetJointsStrReset;
ELSIF OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError
THEN
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
THEN
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;
ELSE
iStep:=cStepSetJointStrDelay;
END_IF;
END_IF
cStepGetItemError:
Item_ID:=0;
iStep:=cStepWaitReset;
cStepGetJointsError:
FOR i :=0 TO 11 DO
arrJoints[i]:=-99999.99;
END_FOR
iStep:=cStepWaitReset;
cStepGetJointsStrError:
strJoints:='';
iStep:=cStepWaitReset;
cStepWaitReset:
IF bReset THEN
iStep:=cStepInit;
bReset:=FALSE;
END_IF;
END_CASE
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
EXIT;
END_IF
END_FOR
FOR i :=1 TO 6 DO
arrJointsFromStr[i]:=STRING_TO_LREAL(aSplit[i]);
END_FOR;
//
OPCUA_VirtualClient_RoboDK_Station.getItem(
bExecute:=iStep=cStepGetItem
,Item_Name:=Robot_name
);
OPCUA_VirtualClient_RoboDK_Station.getJoints(
bExecute:=iStep=cStepGetJoints
,Item_ID:=Item_ID,Joints=>arrJoints
);
OPCUA_VirtualClient_RoboDK_Station.getJointsStr(
bExecute:=iStep=cStepGetJointsStr
,Robot_name:=Robot_name,Joints=>strJoints
);
IF bWrite THEN
OPCUA_VirtualClient_RoboDK_Station.setJointsStr(
bExecute:=TRUE
,Robot_name:=Robot_name,Joints:=strJointsCommand);
END_IF;
在以下的教學中你會了解到如何在RoboDK軟件中增設OPC UA客戶介面。
你會看到現在工作站內的所有參數,請按下“Clear All”把它們全部刪除。
我們會新增另一個RoboDK專案來測試OPC UA客戶介面功能。
在這一節,我們會展示如何在RoboDK軟件中新增OPC UA客戶介面,請輸入你需要連接的OPC UA伺服器的URL和接口號碼。例如:opc.tcp://127.0.0.1:48441
點擊“Connect”開始連接。
如果你看到” Server variables retrieved. Right Click the station item and select ‘Station parameters’ to see the variables.”的信息,那就代表連接成功。
右擊你的工作站,點擊“Station parameters。
請查詢nodes章節尋找相關的資訊。
當你使用RobDK OPC UA 客戶介面去讀寫OPC UA伺服器的情報後,你也可以使用RoboDK-Python-API去讀取這些情報。
請點擊以下連結去安裝RoboDK Python-API。
https://robodk.com/doc/en/PythonAPI/intro.html#how-to-install
或者手動安裝RoboDK Python-API:
pip install robodk
RoboDK Python API去讀取工作站的情報。
from robodk import robolink # RoboDK API
RDK = robolink.Robolink()
from robodk import * # RoboDK API
from robolink import * # Robot toolbox
itemlist = RDK.ItemList()
if itemlist:
# Get all Station Parameters
print('Vaild Paramaters are configurated in your Station..')
StationParameters=RDK.getParams()
for StationParameter in StationParameters:
print("Station Parameters %s : %s"%(StationParameter[0],str((StationParameter[1]))))
else:
print('No Parameter list..')
這是其腳本的執行結果:
Vaild Paramaters are configurated in your Station..
Station Parameters RoboDK : RoboDK 64 bit v5.5.3.23031
Station Parameters time : 02/14/2023 03:58:29.191.000.000
Station Parameters SimulationSpeed : 13.8551
Station Parameters Station : MyTestStation