OPC-UA

OPC-UA Add-in有効する

このドキュメントではOPC-UA 接続機能 RoboDK に追加する方法について説明します OPC UA 接続を使用するとこのプロトコルをサポートする PLC やその他のデバイスとやり取りできます。この機能をプロジェクトに追加するには、RoboDK OPC-UA アドインを有効にする必要があります。

RoboDK には、OPC UA  Add-InRoboDK プロジェクトに追加できます。

デフォルトでは、RoboDK OPC-UA Add-Inが無効になっています。OPC-UA Add-In有効にすると、RoboDK を起動するたびにそのAdd-Inが表示されます。

こちらの手順でOPC UA Add-inを有効できます:

1.Tools>Add-insを選択します。

2.OPC-UAをダブルクリックします。

OPC-UA 機能追加されたツールバーが表示されます

Note:OPC UA Add-Inの詳細については、RoboDK マーケットプレイスセクションを参照してください。

https://robodk.com/addin/com.robodk.plugin.opc-ua.

OPC UA - 画像 1    OPC UA - 画像 2

ツールバーに OPC-UA ボタンが表示されメニューにも OPC-UA 関連の項目が表示されます。

OPC UA - 画像 3

OPC UA サーバー例

こちらの例ではRoboDK OPC UA Add-Inを導入しOPC UAサーバーを立ち上げ、UaExpertBeckhoff TwinCAT3 TF6100で接続テストを行います。

OPC UA - 画像 4

サーバー設定

OPC UA Add-Inを使用すると、OPC UAサーバーポート・無効・有効またはOPC UAサーバの自動起動などの設定が可能ですOPC UA Add-Inを有効にして、OPC UA-OPC-UA設定を選択すれば設定画面が表示されます。OPC UA設定関連は下図のように示さてています。

OPC UA - 画像 5

Tip:OPC UA サーバーのポートを設定し、Startボタンを押して OPC UA サーバーを起動します。

OPC UA - 画像 6

“RoboDK’s OPC UA server running on port 4840”のメッセイジが表示すれば、RoboDK OPC UA サーバーが正常に起動できました。

Note:.前のセクションで構成した OPC UA ポートが、ファイアウォール、ウイルス対策ソフト、またはシステムに必要なその他のセキュリティ設定で有効になっていることを確認してください。

ステーション作成

RoboDKOPC UAサーバを使用すれば、OPC UAクライアントからRoboDKステーションにある複数のロボット情報を同時アクセスできます。

OPC UA - 画像 7

UaExpertの検証

ソフトUaExpertを使用しRoboDKOPC UAサーバを検証します。

こちらのリングからUaExpertをダウンロードしてください。

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

OPC UA - 画像 8

サーバー追加

UaExpertを起動し、“+”ボタンをクリックしRoboDKOPC UAサーバを追加します。

OPC UA - 画像 9

Custom Discoveryを展開し<Double clicks to Add Server.>からRoboDK OPC UAサーバを追加します。

OPC UA - 画像 10

OPC UAサーバURL欄から先程追加したOPC UAサーバエンドポイントを入力ます。今回のチュートリアルではopc.tcp://127.0.0.1:48440になります。

OPC UA - 画像 11

セキュリティ設定は“None”に設定します。

OPC UA - 画像 12

OPC UAサーバが追加しました。

OPC UA - 画像 13

サーバに接続する

次はUaExpertからRoboDKOPC UAサーバに接続します。

OPC UA - 画像 14

RoboDK OPC UAサーバと接続成功すれば、UaExpertからにノードやメソッドを一覧できます。

OPC UA - 画像 15

ノード

サードパーティーから簡単にRoboDKステーションの情報をOPC UA 経由でアクセスできます。

RoboDK

RoboDKノードは現在RoboDKステーションのソフトウェアバージョンを取得できます。

OPC UA - 画像 16

このチュートリアルで使用してるRoboDKバージョンはRoboDK 64 Bit v5.5.3.23031です。

OPC UA - 画像 17

SimulationSpeed

Simulation Speedは現在RoboDK ステーションのシミュレーションスピードを取得や変更できるノードです。

OPC UA - 画像 18

Simulation SpeedノードはスライドバーにあるSimulation Speedになります。

OPC UA - 画像 19

Station

Station Nodeは現在RoboDKのステーション名を取得できます。

OPC UA - 画像 20

下図のように、このチュートリアルに使用してるステーション名は“New Station(1)”になります。

OPC UA - 画像 21

Station parameters/Station Value

サードパーティStation ParameterStation Valueノードを組み合わせて使用することによって、RoboDKステーション内にあるステーションパラメータをアクセスできます。サードパーティOPC UA サーバーは、StationParameterの実際の値を継続的に監視し、ステーション値ノードからそのStationParameterの値を返します。

Note:該当する “StationParameter”が存在しない場合、“StationValue”値は空文字列になります。

OPC UA - 画像 22

RoboDKステーションパラメータを確認するには、RoboDK ステーションを右クリック>Station parametersをクリックします。

OPC UA - 画像 23

Constant parametersからステーションのデフォルトパラメータを確認できます。

OPC UA - 画像 24

StationParameterParameters” フィールドに該当し、StationValueValue” フィールドに該当します。

OPC UA - 画像 25

“Add”ボタンをクリックし、RoboDKステーションに新規のパラメータを作成することも可能です。

OPC UA - 画像 26

新しいステーションパラメータが追加されました。

OPC UA - 画像 27

ステーションパラメータ名とその現在値を入力し、Applyタボンをクリックして保存します。

OPC UA - 画像 28

該当するステーションパラメータも取得できます。

OPC UA - 画像 29

Time

RoboDKステーションの現在時間はTimeノードから取得できます。

OPC UA - 画像 30

RoboDKステーションの現在時間はTimeフォーマットとしてノードに格納されました。

OPC UA - 画像 31

そのTimeノードは周期で更新されています。

OPC UA - 画像 32

メソッド

RoboDK OPC UA Serverではいくつかのメソッドが提供しており、サードパーティがダイナミック的にRoboDKステーションの情報をアクセスできます。

UaExpertからメソッドを右クリック>Callでメソッドを実行できます。

OPC UA - 画像 33

getItem

getItem は、ユーザーがアイテムのメモリポインターを取得するメソッドです。

OPC UA - 画像 34

InputArgumentsのデバイス名はRoboDKステーションのロボットやターゲットなどに該当します。OutputArgumentsItemIDはそのアイテムのメモリポインターになります。

OPC UA - 画像 35

こちらの例ではItem Name“ABB_RB1”を入力しメソッドを呼び出せば、ステーションにある“ABB_RB1”というアイテムのメモリポインターが取得しました。

OPC UA - 画像 36

Item Nameは無効やステーション存在しないの場合、Item ID値は0になります。

OPC UA - 画像 37

getJoints

getJonitsはアイテム ID に基づいて、ユーザーがステーションからロボットのジョイント値を取得できるメソッドです。

OPC UA - 画像 38

ID RoboDKステーションにあるアイテムのポインター値でありgetItem メソッドから取得できます

OPC UA - 画像 39

“ABB_RB1”ItemIDgetItemメソッドから取得できるUIn64フォーマットの整数です。

OPC UA - 画像 40

先ほどgetItemメソッドで取得したItem ID を渡しメソッドを実行すればJoints の値が返ってきます。

OPC UA - 画像 41

getJointsStr

getJointsStr は、ユーザーが文字列フォーマットのジョイント値を取得できるメソッドです。

OPC UA - 画像 42

このメソッドRobot nameはステーション内のロボット名 (文字列) に該当します。

OPC UA - 画像 43

こちらのステーションではロボット名はABB_RB1です。

OPC UA - 画像 44

Robot nameパラメーターにABB_RB1を渡してメソッドを呼び出すだけで、文字列フォーマットのジョイント値が返されます。

OPC UA - 画像 45

setJointsStr

setJointsStr ロボットのジョイントを文字列値から設定できるようにするメソッドです

OPC UA - 画像 46

Robot nameには ABB_RB1 が渡されJoints パラメータにジョイント値を含む文字列を渡すだけです。

:-0.000000,0.000000,-0.000000,-0.000000,-0.0,-0.000000

OPC UA - 画像 47

Beckhoff TwinCAT3の実装

OPC UAサーバ追加

OPC UA クライアントを追加します。I/O>Devices>右クリック>Add New Itemします。

OPC UA - 画像 48

OPC UA>Virtual OPC UA Deviceを選択し>Okで追加します。

OPC UA - 画像 49

OPC UA Virtualが追加されました。

OPC UA - 画像 50

次はRoboDK OPC UA ServerをアクセスするためにOPC UA クライアントを追加します。Device1を右クリック>Add New Itemします。

OPC UA - 画像 51

OPC UA Client(Module)を選択し>Okします。

OPC UA - 画像 52

OPC UA クライアントが追加されました。

OPC UA - 画像 53

OPC UAサーバ設定

OPC UA クライアントをダブルクリックしSettingsタブを開きます。“Select Endpoint”をクリックしOPC UAサーバの接続情報を設定します。

OPC UA - 画像 54

RoboDK OPC UA サーバーのエンドポイントを入力し、Updateボタンで更新します。

OPC UA - 画像 55

RoboDK OPC UA メソッド追加

Add NodesボタンをクリックしOPC UAサーバーにあるノードやメソッドをプロジェクトに追加します

OPC UA - 画像 56

TwinCATOPC UAサーバが接続してる状態であれば、該当するサーバーの情報をアクセスできます。

OPC UA - 画像 57

全てのメソッドを選択し>Okで確定します。

OPC UA - 画像 58

RoboDK OPC UA サーバーのメソッドがプロジェクトに追加されました。

OPC UA - 画像 59

RoboDKメソッド自動作成

Prefixからメソッドの名前を設定します。

OPC UA - 画像 60

“Create Plc Code”PLCプログラムを自動作成しましょう。

OPC UA - 画像 61

OpcUAClient フォルダあプロジェクトに追加され、中にRoboDKメソッドもIEC61131-3 Function Blockフォーマットとして格納しています。

OPC UA - 画像 62

PLC プログラム例

こちらのセクションではBeckhoff TwinCAT PLCRoboDK 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 クライアント例

こちらの例ではRoboDK ステーションでOPC UAクライアントを立ち上げ、OPC UAサーバーをアクセスします。

Note:既存のステーションにある古いステーションパラメータを削除できます。ステーションのルート位置を右クリック>Station Parametersをクリックします。

OPC UA - 画像 63

既存のステーションにあるパラメータが表示され、“Clear All”ボタンでをクリックして全てのステーションパラメータを削除します。

OPC UA - 画像 64

OPC UAクライアントインタフェース実装

RoboDKステーションの中にOPC-UAサーバーを立ち上げます。

OPC UA - 画像 65

OPC UAクライアント追加

こちらのセクションではOPC UAクライアントを追加する方法を説明します。エンドポイントURLOPC UAサーバのURLを入力してください。例えば:opc.tcp://127.0.0.1:48441(ポート番号とIPアドレスはアプリケーションに合わせてください)

OPC UA - 画像 66

ConnectボタンをクリックしてOPC UAサーバと接続します。Server variables retrieved. Right Click the station item and select ‘Station parameters’ to see the variablesが表示すれば、OPC UAサーバの接続は成功しました。

OPC UA - 画像 67

ステーションを右クリッククリックし>Station Parametersをクリックします。

OPC UA - 画像 68

ノード

各ノードの情報はnodesセクションから確認できます。

OPC UA - 画像 69

RoboDK APIの実装

OPC UAサーバからノードデータを取得でれば、RoboDK-Python APIからそれらのデータをアクセスできます。

インストレーション

こちらのリングからRoboDK-Python APIの詳しい情報を確認できます。

https://robodk.com/doc/en/PythonAPI/intro.html#how-to-install

もしかくは手動でrobodkパッケージをインストールします

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