OPC-UA

OPC-UA插件有效化

你會從這篇教學中學習到如何利用RoboDKOPC-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 - 图片 1    OPC UA - 图片 2

當你安裝OPC UA插件後,你會看到其插件的相關菜單和按鍵。

OPC UA - 图片 3

新增OPC UA 伺服器

在這篇教學中你會知道如何在RoboDK中起動OPC UA 伺服器然後使用UaExpert軟件Beckhoff TwinCAT3 TF6100來測試其功能。

OPC UA - 图片 4

設定你的OPC UA 伺服器

你可以利用在OPC UA插件去設定自己的OPC UA連接設定,例如接口號碼IP地址,伺服器的使用不使用等等RoboDK 專案OPC UA插件被激活後,你可以從OPC UA-OPC-UA Settings執行這些相關設定。

如圖所示OPC UA設定畫面會表示在你的RoboDK軟件左方。

OPC UA - 图片 5

提示:你可以根據自己的應用來修改OPC UA 伺服器的接口號碼/ IP地址,然後點擊”start”去起動你的OPC UA 伺服器

OPC UA - 图片 6

假若你看到“RoboDK’s OPC UA server running on port 4840”的信息那就代表你的OPC UA 伺服器已經起動成功。

新建工作站

你可以在任何的RoboDK工作站上測試一台或複數的機械人的OPC UA 連接性能

OPC UA - 图片 7

利用UaExpert測試

你可以使用免費軟UaExpert來測試RoboDK OPC UA伺服器的性能。請點擊以下連結下載安裝檔案。

https://www.unified-automation.com/downloads/opc-ua-clients.html.

OPC UA - 图片 8

新增伺服器

執行UaExpert軟件點擊按鈕去新增OPC UA伺服器

OPC UA - 图片 9

展開Custom Discovery菜單,雙擊<Double clicks to Add Server.>來新增伺服器

OPC UA - 图片 10

輸入你的OPC UA伺服器地址。

OPC UA - 图片 11

選擇None作為安全連接選項,點擊OK開始連接OPC UA伺服器。

OPC UA - 图片 12

你在UaExpert新增了OPC UA伺服器。

OPC UA - 图片 13

連接 OPC UA伺服器

現在你可以利用UaExpert嘗試連接OPC UA伺服器。

OPC UA - 图片 14

如果連接成功你會看到OPC UA伺服器內的所有Node Method

OPC UA - 图片 15

Nodes

RoboDK OPC UA伺服器提供不同的node讓其他裝置可以讀寫RoboDK工作站的情報。

RoboDK

你可以使用RoboDK node來取得RoboDK的軟件版本。

OPC UA - 图片 16

如圖所示,我們在這篇教學中使用了RoboDK 64 Bit v5.5.3.23031

OPC UA - 图片 17

SimulationSpeed

你可以使用Simulation Speed node來讀寫RoboDK工作站的仿真速度。

OPC UA - 图片 18

SimulationSpeed的現在值是和RoboDK工作站上的仿真速度設定是一樣,而且你可以直接更改SimulationSpeed node的數值來覆寫這個設定。

OPC UA - 图片 19

Station

你可以使用Station Node來讀取RoboDK工作站的名稱。

OPC UA - 图片 20

如圖所示我們在這篇教學中使用了RoboDK工作站名稱是”New Station(1)”

OPC UA - 图片 21

Station parameters/Station Value

你可以使用Station Parameter Station Value這對Node來讀寫RoboDK工作站的參數。RoboDK OPC UA伺服器會重覆監視Station Parameter,然後根據其現在值去讀取工作站參數的現在值,最後將其值傳送到Station Value Node

OPC UA - 图片 22

你可以右擊view >點擊Station parameters來確認自己工作站的參數

OPC UA - 图片 23

工作站所有默認的參數和其參數值都表示在Constant parameters的表格內。

OPC UA - 图片 24

Stationparameter是等於Parameter,而StationValue是相等於Value

OPC UA - 图片 25

你也可以點擊“Add“來新增屬於自己工作站的參數。

OPC UA - 图片 26

如圖所示,你的工作站新增了一個參數。

輸入參數的名稱和數值,然後點擊Apply保存。

OPC UA - 图片 27

然後你可以利用StationParameterStationValue來讀取這個參數。

OPC UA - 图片 28

Time

你可以使用time node來讀取RoboDK工作站的現在時間。

OPC UA - 图片 29

工作站的現在時間會以DataTime格式的儲存下來。

OPC UA - 图片 30

然後這個Node是不停更新的。

OPC UA - 图片 31

Methods

RoboDKOPC UA伺服器也提供了一系列的methods讓使用者讀寫RoboDK OPC UA伺服器的情報。我們可以右擊Method>點擊Call來執行Method

OPC UA - 图片 32

getItem

你可以使用getItem來讀取RoboDK工作站內物件的指標。

OPC UA - 图片 33

getItem需要Device Name作為InputArguments,你可以想像, Device Name是任何被配置在RoboDK工作站的其物件名稱,然後OutputArguments就會輸出指定物件的指標。

OPC UA - 图片 34

我們會在Item Name輸入“ABB_RB1”作為InputArguments,然後你會取得工作站中ABB 機械人的指標。

OPC UA - 图片 35

如果你輸入了無效Item NameMethod 的執行結果會是0

OPC UA - 图片 36

getJoints

getJonits會根據Item ID來讀取其工作站內機械人的關節情報(配列格式)。

OPC UA - 图片 37

Item ID是工作站物件的指標值你可以使用剛才所介紹的getItem()來讀取其現在值。

OPC UA - 图片 38

所以我們要先從getItem()中取得工作站內的“ABB_RB1”指標值。

OPC UA - 图片 39

然後你只需要將那個指標值剪報到getJoints methodItem ID上,然後執行method;你就會取得機械人關節的現在值。(配列格式)

OPC UA - 图片 40

getJointsStr

getJonits會根據Item ID來讀取其工作站內機械人的關節情報(文字格式)。

OPC UA - 图片 41

利用這個method時,我們不再需要工作站物件的指標,取而代之的是工作站其物件的名稱(文字格式)。

OPC UA - 图片 42

我們現在嘗試利用getJonits method來讀取ABB_RB1現時的關節值。

OPC UA - 图片 43

執行method前,我們只需然在Robot name參數中輸入“ABB_RB1”,其機械人現時的關節值就會自動返回。

OPC UA - 图片 44

setJointsStr

我們可以使用setJointsStr method來設定機械人的關節位置(文字列格式)

OPC UA - 图片 45

Robot name參數中輸入ABB_RB1然後在Joints參數中輸入你想設定的關節位置,然後執行。

例子:-0.000000,0.000000,-0.000000,-0.000000,-0.0,-0.000000

OPC UA - 图片 46

使用Beckhoff TwinCAT3連接

新增伺服器

新增TwincCAT3專案,然後選擇I/O>右擊>點下Add New Item

OPC UA - 图片 47

OPC菜單中選擇Virtual OPC UA Device然後點擊OK

OPC UA - 图片 48

OPC UA Virtual 被新增在你的專案中。

OPC UA - 图片 49

現在我們需要在TwinCAT專案中新加RoboDK OPC UA 伺服器。選擇Device 1 >右擊>點擊Add New Item

OPC UA - 图片 50

從菜單中選擇OPC UA Client(Module)然後OK

OPC UA - 图片 51

你的專案中追加了OPC UA 客戶介面。

OPC UA - 图片 52

設定OPCUA 伺服器

打開OPC UA 客戶介面然後點擊“Select Endpoint”去設定你要讀取的OPC UA伺服器。

OPC UA - 图片 53

輸入你的OPC UA伺服器地址然後點擊Update

OPC UA - 图片 54

新增RoboDK 伺服器method

點擊 “Add Nodes” 你就可以用瀏覽其OPC 伺服器的NodeMethod

OPC UA - 图片 55

如果TwinCATOPC 伺服器是已經連接你就可以瀏覽到所有的情報。

OPC UA - 图片 56

選擇所有的Methods然後按下OK

OPC UA - 图片 57

RoboDK OPC 伺服器中所有的method都追加了在你的專案中。

OPC UA - 图片 58

自動生成RoboDK Method

設定你自動生成程式的預設名稱。

OPC UA - 图片 59

點擊“Create Plc Code”

OPC UA - 图片 60

OpcUaClient檔案夾會被新增到你的PLC專案中,然後你會找到所有的RoboDK Method會被自動轉換成IEC61131-3 功能塊格式。

OPC UA - 图片 61

PLC 程式例子

.以下是利用剛才自動生成的功能塊編寫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;

OPC UA Client Example

在以下的教學中你會了解到如何在RoboDK軟件中增設OPC UA客戶介面。

OPC UA - 图片 62

你會看到現在工作站內的所有參數,請按下“Clear All”把它們全部刪除。

OPC UA - 图片 63

介面測試

我們會新增另一個RoboDK專案來測試OPC UA客戶介面功能。

OPC UA - 图片 64

新增客戶介面

在這一節我們會展示如何在RoboDK軟件中新增OPC UA客戶介面,請輸入你需要連接的OPC UA伺服器的URL和接口號碼。例如:opc.tcp://127.0.0.1:48441

OPC UA - 图片 65

點擊“Connect”開始連接。

如果你看到” Server variables retrieved. Right Click the station item and select ‘Station parameters’ to see the variables.”的信息,那就代表連接成功。

OPC UA - 图片 66

右擊你的工作站,點擊“Station parameters

OPC UA - 图片 67

Nodes

請查詢nodes章節尋找相關的資訊。

OPC UA - 图片 68

使用RoboDK API測試

當你使用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