Project#Omron NX CPU OPC UA Server x twincat client / ctrlx client

この記事ではOMRON NX-1 CPUにOPC UA Serverを立ち上げ、次はUaExpert・Beckoff TwinCAT TF6100 PLC OPEN Library・最後はCtrlX Virtual CoreとNode Red Appsの連携でそのServerをアクセスしてみます。よろしくお願いします。

Implementation1

最初の実機はまずNX CPUにOPC UA Serverを立ち上げ、UaExpertから接続確認を行います。

Reference Link

http://soup01.com/ja/category/omron%e3%82%aa%e3%83%a0%e3%83%ad%e3%83%b3/

OMRON Side

Port 1 Configuration

Configuration and Setup>Controller Setup>Operation Settings>Built-in Ethernet/IP Port SettingsからPort1のIPを変更できます。注意するのはOPC UA Serverとして利用できるのはPort1のみです。

Enable Server

次はOPC UA Server Settings>OPC UA ServerをUseにします。

Create User

次はUserを設定します。OPC UA Settings>OPC UA Server Server Settings>右クリック>Security Settingsします。

+Buttonで新しいUserを設定します。

User名とPasswordを追加しましょう。

Create Node

次はOPC UA Server用のNodeを定義します。Programming>Data>Global Variablesをクリックします。

Global VariablesでNetwork PublishのFieldあり、そこから該当する変数をOPC UA Serverに公開するか設定できます。

Nodes

ManaulからNetwork Publish項目にあまり詳しく説明していませんので、Do not Publish・Publish Only・Input・Output・構造体、5つの変数を追加しテストします。

Result

プロジェクトをCPUにDownloadし、ツールをMonitor Modeに切り替えます。

OPC UA Settings>OPC UA Server Settings>右クリック>Server Statusをクリックします。

現在NX CPUのOPC UA Server稼働状況を確認できます。

いまはOPCUA Serverは”Use”の状態でServer operating statusがRunningになっています。よし、OPC UA Serverが稼働していますね。

次はUaExpertから接続状態を確認します。+ButtonでConnection追加します。

Custom Discovery>+ <Double click to Add Server>で新規のServer Connectionを追加します。

URLはOmronのIPアドレスを入れましょう。

Noneで接続します。

次は追加されたServerを選び>接続します。

Done!次はRoot>Objects>new_Controller_0>GlobalVarsまで展開すると最初に追加したNodeが確認できます。それらのNodeを選び右にある空きのところにDropします。

Read OK

まずは読み取りがOkっぽいですね。Do not Publish以外の変数は全部アクセスできます。

Write OK

次は書き込みですね。同じくDo not Publish以外の変数は全部変更できますね。

どうやら関係あるのはDo not Publishだけです。

BadCertificate TimeInvalid..?

もしUaExpertからアクセスするときBadCertificate TimeInvalidエラーが発生した場合、ServerのCertificateをTrusted Folderに移動することができません、そして毎回も同じのエラーが表示されます。

sysmac studio からController>Controller Clockをクリックします。

Controllerの時間調整画面が表示されます。

Synchronize with computerのButtonからControllerの時間を自分のPCと同期します。

最後はApplyすればOkです。

次はControllerのServer証明書を更新します。OPC UA Settings>OPC UA Server Settings>右クリック>Server Certificateします。

Server証明書の管理画面が表示されます。

そこでServer 証明書の有効期限がすでに切れていることがわかります。それはControllerの時間が古いのせいで証明書もその古い日付から生成されたので、UaExpertからはこの期限切れの証明書を信頼できません。

Regenerate Certificateで現在の時間からもう一度証明書を生成します。

OPC UA Server証明書の情報を入力し、OKします。

Yesで進みます。

暫く待ちます…

Done!新しい証明書が発行されました。

もう一度UaExpertからOmronのOPC UA Serverにアクセスすると、Trust Server CertificateのButtonが押せるようになりました。

ContinueでOKです。

Implementation2

今回はBeckoff TwinCAT TF6100でPLC OPEN OPC UA Client LibraryIからOMRON NX-1 CPUのOPC UA Serverにアクセスしてみます。

Reference Link

Beckhoff#TwinCAT3 TF6100 OPCUA _Part3_PLCOPEN Library

Add PLC

TwinCATで新しいプロジェクトを作成し、PLC>Add New Itemで新しいPLCを追加します。

Standard PLC Projectを選び、Addします。

Add Library

次はOPC UA APIのLibraryを追加します。References>Add libraryクリックします。

Tc3_PLCOpen_OpcUaを検索し追加しましょう。

Done!

Check Namespace

PLC openのAPIを使用するには、まずアクセスしたいNodeのNamespaceを確認する必要があります。Root>Objects>Server>NamespaceArrayを展開します。

そのNamespaceはString Array[5]で中に5つのString変数があります。

Check identifier

次は各NodeのAttributesからIdentifierの項目があり、そのIdentifierはAPIを使用するときに必要です。

DUT

PLCプロジェクトの中で構造体を作成します。

DUT_OPCUA 

こちらはOmron NX1 CPUの構造体 Nodeに合わせて定義したNodeです。

TYPE DUT_OPCUA :
STRUCT
b1:BOOL;
int1:INT;
real1:REAL;
END_STRUCT
END_TYPE

uDUT_Real 

次は実数データと4 Bytesに分解できるようにUnion構造体を定義します。

TYPE uDUT_Real :
UNION
myReal :REAL;
_ar :ARRAY[0..3]OF BYTE;
END_UNION
END_TYPE

MAIN

次はMain Programです。

VAR

PLCOPENのAPIで使用するFunction Block用のInstanceを宣言します。

PROGRAM MAIN
VAR
//UA Connect
UA_Connect:UA_Connect;
SessionConnectInfo :ST_UASessionConnectInfo;
//UA Disconnect
UA_Disconnect:UA_Connect;

//Polling Functionlity
//Get NameIndex
UA_GetNamespaceIndex:UA_GetNamespaceIndex;
nNameSpaceIndex :UINT;
//Get Handle
UA_NodeGetHandle:UA_NodeGetHandle;
NodeID :ST_UANodeID;
nNodeHdl :DWORD;
//UA Read
UA_Read :UA_Read;
stIndexRange : ARRAY [1..nMaxIndexRange] OF ST_UAIndexRange;
nIndexRangeCount : UINT;
stNodeAddInfo : ST_UANodeAdditionalInfo;
nReadData : INT;
cbDataRead : UDINT;
//UA Node Release Handle
UA_NodeReleaseHandle : UA_NodeReleaseHandle;

//
iStep :INT;
bConnect :BOOL;
bDisconnect :BOOL;
ConnectionHdl :DWORD;
myStructureNode :DUT_OPCUA;
cbData_R :UDINT;
myInt :INT;
myReal :uDUT_Real;
_tempByte :BYTE;
TON :TON;
ErrorMessage :STRING;
ErrorID :DWORD;
bReset :BOOL;
END_VAR

VAR CONSTANT
cSererUrl :STRING:=’opc.tcp://192.168.11.18:4840′;
cNameSpace :STRING:=’urn:OMRON:NxOpcUaServer:FactoryAutomation’;
END_VAR

PROGRAM

OPC UA Serverと接続>NameSpaceIndexを取得>NodeのHandleを取得>Node値を読み取る>Loop Backのようなプログラムです。

myInt:=SHL(myStructureNode.int1,8)+SHR(myStructureNode.int1,8);

myReal.myReal:=myStructureNode.real1;

_tempByte:=myReal._ar[0];
myReal._ar[0]:=myReal._ar[1];
myReal._ar[1]:=_tempByte;

_tempByte:=myReal._ar[2];
myReal._ar[2]:=myReal._ar[3];
myReal._ar[3]:=_tempByte;


CASE iStep OF

0:
IF bConnect THEN

UA_Connect(Execute:=FALSE);
UA_Disconnect(Execute:=FALSE);
UA_GetNameSpaceIndex(Execute:=FALSE);
UA_NodeGetHandle(Execute:=FALSE);
UA_Read(Execute:=FALSE);
UA_NodeReleaseHandle(Execute:=FALSE);
SessionConnectInfo.eSecurityMode:=eUASecurityMsgMode_None;
SessionConnectInfo.eSecurityPolicyUri:=eUASecurityPolicy_None;
SessionConnectInfo.eTransportProfileUri:=eUATransportProfileUri_UATcp;
SessionConnectInfo.tConnectTimeout:=T#1M;
SessionConnectInfo.tSessionTimeout:=T#1M;
IF NOT UA_Connect.Busy
AND NOT UA_Disconnect.Busy
AND NOT UA_GetNameSpaceIndex.Busy
AND NOT UA_NodeGetHandle.Busy
AND NOT UA_NodeGetHandle.Busy
AND NOT UA_NodeReleaseHandle.Busy
THEN
iStep:=10;
bConnect:=FALSE;
end_if;

END_IF
10:
UA_Connect(
Execute:=TRUE
,ServerUrl:=cSererUrl
,SessionConnectInfo:=SessionConnectInfo
,ConnectionHdl=>ConnectionHdl
);
IF UA_Connect.Error THEN
iStep:=999;
END_IF
IF UA_Connect.Done AND NOT ua_Connect.Error THEN
iStep:=20;
UA_Connect(Execute:=FALSE);
ELSIF ua_connect.Error THEN
iStep:=999;
END_IF
20:
UA_GetNamespaceIndex(
Execute:=TRUE
,ConnectionHdl:=ConnectionHdl
,NamespaceUri :=cNameSpace
,NamespaceIndex=>nNameSpaceIndex
);
IF UA_GetNamespaceIndex.Done AND NOT UA_getNamespaceIndex.ErrorTHEN
iStep:=30;
UA_GetNamespaceIndex(execute:=FALSE);
ELSIF UA_getNamespaceIndex.Error THEN
iStep:=999;
END_IF
30:
NodeID.eIdentifierType:=eUAIdentifierType_String;
NodeID.nNamespaceIndex:=nNameSpaceIndex;
NodeID.sIdentifier:=’MyDUTNode’;
UA_NodeGetHandle(
Execute:=TRUE
,ConnectionHdl:=ConnectionHdl
,NodeID:=NodeID
,NodeHdl=>nNodeHdl
);
IF UA_NodeGetHandle.Done AND NOT UA_NodeGetHandle.Error THEN
UA_NodeGetHandle(Execute:=FALSE);
iStep:=40;

ELSIF UA_NodeGetHandle.Error THEN
iStep:=999;
END_IF
40:
UA_Read(
Execute:=TRUE
,ConnectionHdl:=ConnectionHdl
,NodeHdl:=nNodeHdl
,cbData:=SIZEOF(myStructureNode)
,stNodeAddInfo:=stNodeAddInfo
,pVariable:=ADR(myStructureNode)
);
IF UA_Read.Done AND NOT UA_Read.Error THEN
UA_Read(
Execute:=FALSE
,cbData_R=>cbData_R
);
iStep:=45;
ELSIF UA_Read.Error THEN
iStep:=999;
END_IF;
45:
TON(in:=TRUE,PT:=T#0.2S);
IF ton.Q THEN
TON(in:=FALSE);
IF  bdisconnect THEN
iStep:=50;
ELSE
istep:=40;
END_IF;

END_IF
50:
UA_NodeReleaseHandle(
Execute:=TRUE
,ConnectionHdl:=ConnectionHdl
,NodeHdl:=nNodeHdl
);
IF UA_NodeReleaseHandle.Done AND NOT UA_NodeReleaseHandle.Error THEN
UA_NodeReleaseHandle(Execute:=FALSE);
iStep:=200;
ELSIF UA_NodeReleaseHandle.Error THEN
iStep:=999;
END_IF

200:
IF bDisconnect THEN
iStep:=210;
bDisconnect:=FALSE;
END_IF
210:
UA_Disconnect(
Execute:=TRUE
,ServerUrl:=cSererUrl
,SessionConnectInfo:=SessionConnectInfo
,ConnectionHdl=>ConnectionHdl
);

IF UA_Disconnect.Error THEN
iStep:=999;
END_IF
IF UA_Disconnect.Done AND NOT UA_Disconnect.Error THEN
iStep:=0;
UA_Disconnect(Execute:=FALSE);
END_IF
999:
IF UA_Connect.Error THEN
ErrorMessage:=’Error in UA_Connect.’;
ErrorID :=UA_Connect.ErrorID;
ELSIF UA_Disconnect.Error THEN
ErrorMessage:=’Error in UA_Disconnect.’;
ErrorID :=UA_Disconnect.ErrorID;
ELSIF UA_GetNamespaceIndex.Error THEN
ErrorMessage:=’Error in UA_GetNamespaceIndex.’;
ErrorID :=UA_GetNamespaceIndex.ErrorID;
ELSIF UA_NodeGetHandle.Error THEN
ErrorMessage:=’Error in UA_NodeGetHandle.’;
ErrorID :=UA_NodeGetHandle.ErrorID;
ELSIF UA_Read.Error THEN
ErrorMessage:=’Error in UA_Read.’;
ErrorID :=UA_Read.ErrorID;
ELSIF UA_NodeReleaseHandle.Error THEN
ErrorMessage:=’Error in UA_NodeReleaseHandle.’;
ErrorID :=UA_NodeReleaseHandle.ErrorID;
END_IF;
IF breset THEN
ErrorMessage:=”;
ErrorID:=0;
END_IF
END_CASE

Result

Done!Omron NX1 CPUのデータを読みました。

構造体で一気変数を取ることになったので、ByteのLittle EndianとBig Endianが異なると現在値がおかしくなります。なので、簡単なSwap プログラムを作成しByteの並び順を変更します。

正しい現在値になりました!

ちなみに、こちらはBig EndianのByte並び順です。

こちらはLittle EndianのByte並び順です。

Implementation3

最後はBosch rexrothのCtrlXとNode Red Appsの連携でOmron Nx-1 CPUのOPC UA Server Nodeを読み取ります。

NODE-RED APP?

Node-Red AppはBosch Rexroth Ctrlx automationから提供されたNode-Red Frameworkで、そのOpen source toolはApach2 2.0ライセンスとIBM社がGraphic開発環境を開発しました。

Bosch rexroth Ctrlx AutomationのNode-Red AppはCtrl storeからDownloaでき、インストールすればCtrlx Nodeも使用でき、より簡単でCtrlx CoreとData Layer上でデータ交換が可能なリます。

  • Node-RED Runtime
  • Flow Editor
  • Dashboard

Reference Link

ctrlX#Part1_Your first Entry with ctrlX-PLC APP!
このシリーズではBosch rexrothのctrlX AUTOMATIONについて紹介します。自分は実機をもっていませんのでどこまでテス...
ctrlx#Part2_Data Layer
前回はCtlx WorksとCtlx PLC Appsをインストールし簡単なPLCアプリケーションを立ち上げました。今回はCtrlx PL...

Omron Side

今回はOmron側の変数を変換できるように簡単なプログラムを作成します。

Delete the Ladder program

まずPOUs>ProgramsでDefault作成されたラダープログラムを削除します。

Yesで進みます。

Add ST Program

Programs>右クリック>Add>STでSTプログラムを追加します。

Internals

こちらはSTプログラムの内部変数です。

myTimerとMyStepは変数の変化 Reflesh用です。

Programs

MyDUTNode.int1:=MyDUTNode.int1+1;


CASE myStep OF

0:
MyDUTNode.b1:=TRUE;
myTimer(In:=True,PT:=T#1s);
IF myTimer.Q THEN
myTimer(In:=False);
myStep:=1;
END_IF;
1:
MyDUTNode.b1:=False;
myTimer(In:=True,PT:=T#1s);
IF myTimer.Q THEN
MyDUTNode.real1:=MyDUTNode.real1+1.1;
myTimer(In:=False);
myStep:=0;
END_IF;

END_CASE;

Task Settings

新しいPOUが追加されたので、Task Settingsから該当するプログラムを割り付ける必要があります。Configuration and Setup>Task Settingsを開きます。

+Buttonで新しい実行POUを追加します。

Done!

ctrlx Side

PLC Side

TwinCATと同じくctrlX 側にもOmron NX1 CPUの構造体Nodeに合わせるように宣言する必要があります。

Add DUT

Applications>Add Object>DUTで構造体を追加します。

Omron NX1 CPUと同じような構造を宣言しましょう。

TYPE DUT_TestFromOPCUA :
STRUCT
b1:BOOL;
int1:INT;
real1:REAL;
END_STRUCT
END_TYPE

GVL

そしてGVLで変数を宣言します。

{attribute ‘qualified_only’}
VAR_GLOBAL
myData:INT;
Node,Node_Buffer:DUT_TestFromOPCUA;
END_VAR

Node-Red APPs

ctrlx Storeからctrlx CORE-NODE-RED AppをDownloadし、自分のVirtualCoreにインストールしてください。

VirtualCoreのWeb serverからNode-Redが追加されたはずです。

中にFlow EditorとDashboardがありますが、Flow Editorを開きNode-Red Flowを追加します。

いつも通りのNode-Red編集画面に変わりました。

Node Installation

OPC UA Nodeをインストールするため、Manage paletteをクリックします。

OPCUAを検索し、node-red-contrib-opcua Nodeをインストールします。

Installで進みます。

Done!OPC UA Nodeが追加されました。

IF Error..

もしNode-redで新しいNodeをインストールするときDNSエラーがあったら、それは

Vritual Coreは実際Internetの接続に問題があるんです。なぜかというとVirtualCoreは仮想環境で稼働していますからね!

npm ERR! request to https://registry.npmjs.org/express failed, reason: getaddrinfo EAI_AGAIN registry.npmjs.org

VirtualCoreを一旦停止し、NetworkをPort Forwardingに設定します。

次はVirtualCoreを起動し、CoreのWeb serverからSettings>Connectivelyを開きます。

Network interfaceのDHCP機能 Enableします。

Enable IP ForwardingをTrueします。そうするとNodeのインストールができると思います。

Port  Configuration

NX-CPUと接続するには、Port 設定はPort Forwardingにし、Extended Accessは実際NX-CPUと接続してるInterface cardを設定しましょう。

VirtualCoreのIP addressは該当するInterface card:8443に変わります。

次はVirtualCoreを起動し、CoreのWeb serverからSettings>Connectivelyを開きます。

DHCPをEnableします。

Enable IP forwardingをTrueします。

Flow-1Test with ctrlX Node

Setupが終わったらまずCtrlx Nodeをテストしてみます。そのNodeを使用することによりCtrlX Virtual CoreのData Layerに簡単にアクセスできます。

Data Layer RequestをFlowに追加します。

Add Inject Node

周期でCtrlX Requset Nodeをリクエスト発行するようにInject Nodeを追加します。

InjectとCtrlX Requset Nodeを繋がります。

Add Debug Node

CtrlX Requsetの結果も確認したいので、Debug Nodeを追加します。

DebugのInputとCtrlX RequsetのOutputと繋がります。

Ctrlx Request Ndoe

最後はCtrlx Nodeを編集し、Device FieldはVritual CoreのIP:8443を入力しましょう。

Path 

Path FieldからCtrlXのData Layerの変数をBrowseできます。

(ある意味では仮のConnection Testで設定したパラメータが正しいかを確認)

Done!設定が間違ってないようです。

アクセスしたい変数を選んだら、自動的にPathが設定されます。

Payload

Payloadは実際Ctrlx Nodeにリクエストを送信するときのPayload Formatを設定できます。DefaultあValue Onlyです。

今回の記事ではValue+ Type(Json)を設定します。

Method-Read

Methodは該当するPathのリクエスト種類を設定できます。SUB/PUB/WRITE/READなど様々な方法が用意されています。

MethodをRead選択します。

Doneで設定を保存します。

Done!データが読み取れました!

CtrlX Nodeの下にautherlicatedと緑四角が表示され、それは接続してるだと示しています。

Method-Write

今度はCtrlx Data Layerの変数に新たな値を書き込みます。

MethodをWRITEに設定します。

Function Nodeを追加します。Inject Nodeが一回Function Nodeを通ってからCtrlx NodeにInputと繋がります。

Function の中に簡単なjavascriptを追加します。

var m={};
m.payload={“type”:”int16″,”value”:1234};

Done!データが正常に書き込まれました!

Node.int1の現在値も1234に変わりました。

Connect with Omron OPC UA Server

Ctrlx Nodeのテストが終わったところで、次はOmron NX1 CPUと接続しにいきます。

Add OpcUa -Client Node

Node-Red FlowからOpcUa – Client Ndoeを追加します。

Endpointなどの設定はOmron NX1 CPUに合わせて設定しましょう。

もしEndpointが変更が必要の場合、鉛筆ICONをクリックしてください。

Security Settingsなどの接続設定を変更できます。

Add inject Node

Inject Nodeを追加します。

今回はNX-CPUのOPC UA Serverにある構造体変数MyDUTNodeにアクセスしたいので、UaExpertからそのNodeIDを確認します。

Inject Ndoeにmsg.topicを追加し、先ほど調べたNodeIDを入れます。そしてRepeat 設定をIntervalに変更し、周期が1sだと設定します。

Done!

Add Function Node

Function  Ndoeを追加し、OPC UA Serverにアクセスし取得したデータをそれらのNode経由でCtrlx Data Layerに書き込む前の簡単な前処理です。

Write_node_b1
var m = {};
m.payload = { “type”: “bool8”, “value”: msg.payload.b1 };
return m;
write_node_int1
var m = {};
m.payload = { “type”: “int16”, “value”: msg.payload.int1 };
return m;
write_node_real1
var m = {};
m.payload = { “type”: “float”, “value”: msg.payload.real1 };
return m;

Add ctrlX Request

Ctrlx Nodeを追加します。

Function Nodeの出力をCtrlx Nodeの入力と繋がります。

Ctrlx Nodeの接続設定はFlow-1 Testingを参照してやりましょう。

Add debug Node

最後はDebug Ndoeを追加し結果を確認できるようにします。

出力するのはPayloadだけでよいでしょう。

Done!

最後はCtrlX Nodeの出力をDebugの入力と繋がります。

Finally Flow

こちらは全体的のFlowです。

Result

OPC UA Client Nodeの下に緑四角とActive readingのメッセージが表示されたらOKです!

データも正常に読み書きできました。

IF can not connect

もしどうしても接続できないなら、Firewallのルールに問題があるかもしれません。

Outbound RulesでPort 4840をEnableします。

Inputboud RulesもPort 4840をEnableします。

Footer_Basic

Please Support some devices for my blog

Amazon Gift List

Find ME

Twitter:@3threes2
Email:soup01threes*gmail.com (* to @)
YoutubeChannel:https://www.youtube.com/channel/UCQ3CHGAIXZAbeOC_9mjQiWQ

シェアする

  • このエントリーをはてなブックマークに追加

フォローする