趣味と興味の覚え書

趣味や興味があって調べたことなどを記しています

Node-REDを使ってOPC UAでPLCの値を読み書き

目標

今回はNode-REDを使ってOPC UAでPLCの値を読み書きしたいと思う。Node-REDでこのような画面を作成し、ラズパイ上のCODESYSの変数の値を読み書きします。 f:id:ritty1224:20211017133613j:plain

簡単に画面の説明から。

  • Browse : OPC UAサーバのアドレス空間探索。変数情報を探すために使用。
  • Main : 変数読み書き。
    • STARTボタン : 変数のモニタ開始
    • Powerスイッチ : 変数gInput001に値を書き込む
    • gInput001 : 変数gInput001のモニタ値
    • gOutput001 : 変数gOutput001のモニタ値
    • Counter : 変数gCounterのモニタ値

構成

今回の構成は以下。Node-REDもラズパイ上で実行したかったが、PCに先に入れてしまったので、ラズパイは諦めた。まあ同じだろう。

Windows 10 (Node-RED, OPC UAクライアント)
l
ラズパイ(CODESYS, OPC UAサーバ)

準備

WindowsPCへのNode-REDのインストール (Node.jsのインストール含む)

Windowsで実行する : Node-RED日本ユーザ会

Node-REDで使用するノードのインストール

  • node-red-contrib-opcua (OPC UAによるデータ交換を行うノード)

node-red-contrib-opcua (node) - Node-RED

node-red-dashboard (node) - Node-RED

上記リンクはnpmによるインストール方法が記載されているが、GUIでもインストール可能。

パレットにノードを追加する : Node-RED日本ユーザ会

Raspberry PI (CODESYS installed)
CODESYSのインストール方法やプログラミングについては以下参照。

やってみよう

手順

  1. CODESYSの開発環境の設定
  2. CODESYSの設定、プログラミング
  3. Node-REDでフローを読み込む
  4. Node-REDで変数読み書き

CODESYSの開発環境の設定

CODESYSには標準でOPC UAサーバが搭載されている。OPC UA機能の設定を行うために必要となるアドオンの追加を行う。CODESYS V3.5 SP17 Pathc1を使用しているが、デフォルトではOPC UA機能の設定ができなかった。

  1. CODESYS Communicationをインストールする
    CODESYS Installerを起動し、CODESYS Communicationのアドオンを追加する。 f:id:ritty1224:20211016141951j:plain

CODESYSの設定、プログラミング

1.新規プロジェクトを作成する。
プロジェクト作成など基本的な操作は以下参照。

2.PLC_PRGを開きプログラムを書く。
gInput001がTrueなら、gOutput001をTrueにしgCounterを毎サイクル10加算する。という簡単なプログラム。

PROGRAM PLC_PRG
VAR 
    gInput001:BOOL;
    gOutput001:BOOL;
    gCounter:UINT;
END_VAR

IF gInput001 = TRUE THEN
    gOutput001:=TRUE;
    gCounter:=gCounter+10;
ELSE
    gOutput001:=FALSE;
    gCounter:=0;
END_IF;

3.シンボル構成オブジェクトを追加する
下図のメニューからシンボル構成オブジェクトを追加する。シンボル構成の追加のダイアログが表示される。「OPC UA機能のサポート」にチェックがついていることを確認して追加する。
f:id:ritty1224:20211016144138j:plain

4.シンボル構成の編集
シンボル構成を開き公開する変数にチェックをつける
f:id:ritty1224:20211017135013j:plain

5.Windows PCから資格情報なしに接続するためにCODESYSへの匿名ログインを許可しておく。 f:id:ritty1224:20211016145542j:plain f:id:ritty1224:20211016145203j:plain

6.CODESYSにプロジェクトをダウンロード CODESYSにログインしプロジェクトをダウンロードし、運転モードにする。

Node-REDでフローを読み込む

1.Node-REDを起動し、右上の三本線アイコンをクリックし、「読み込み」を実行する。

2.以下をコピーし貼り付ける。

[{"id":"e1e4a455bdf7b20d","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"fd8c6625af5c9311","type":"ui_template","z":"e1e4a455bdf7b20d","group":"b4cbb1eea7449882","name":"","order":6,"width":"6","height":"10","format":"<div layout=\"row\" layout-align=\"space-between\">\n\t<select ng-model=\"item\" ng-options=\"items.item.displayName.text for items in msg.payload\">\n\t\t<option value=\"\">-- Objects Root --</option>\n\t</select>\n</div>\n\n<div layout=\"row\" layout-align=\"space-between\">\n\t<button ng-click=\"send({payload: {actiontype: 'browse', root: item}})\"> Browse </button>\n</div>\n\n<div layout=\"row\" layout-align=\"space-between\">\n    <ul> <li ng-repeat=\"items in msg.payload\"> {{items.item.displayName.text}}: {{items.item.nodeId}} </li>\n    </ul>\n</div>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":430,"y":100,"wires":[["e8facbc9f34c7609"]]},{"id":"e8facbc9f34c7609","type":"OpcUa-Browser","z":"e1e4a455bdf7b20d","endpoint":"a1c9116733215552","item":"","datatype":"","topic":"","items":[],"name":"","x":430,"y":180,"wires":[["fd8c6625af5c9311"]]},{"id":"17a6b19b660e193f","type":"ui_text","z":"e1e4a455bdf7b20d","group":"952cda7cb8019a3d","order":4,"width":0,"height":0,"name":"Output","label":"gOutput001","format":"{{msg.payload}}","layout":"row-spread","className":"","x":730,"y":380,"wires":[]},{"id":"bde88723416b903d","type":"OpcUa-Client","z":"e1e4a455bdf7b20d","endpoint":"a1c9116733215552","action":"write","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","name":"Write","x":550,"y":280,"wires":[[]]},{"id":"62c454e9715eec40","type":"OpcUa-Item","z":"e1e4a455bdf7b20d","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.PLC_PRG.gInput001","datatype":"Boolean","value":"0","name":"gInput","x":350,"y":280,"wires":[["bde88723416b903d"]]},{"id":"6f12e56749684087","type":"ui_switch","z":"e1e4a455bdf7b20d","name":"Power","label":"Power (gInput001)","tooltip":"","group":"952cda7cb8019a3d","order":2,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":150,"y":280,"wires":[["62c454e9715eec40"]]},{"id":"3bcb0fc232647942","type":"OpcUa-Item","z":"e1e4a455bdf7b20d","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.PLC_PRG.gcounter","datatype":"Int32","value":"","name":"gCounter","x":340,"y":480,"wires":[["b59193780ad42b14"]]},{"id":"8fa9cfdda22b99d7","type":"OpcUa-Item","z":"e1e4a455bdf7b20d","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.PLC_PRG.gOutput001","datatype":"Boolean","value":"","name":"gOutput","x":340,"y":360,"wires":[["b4aaf019d6bde6e5"]]},{"id":"753cf4a165d0d134","type":"OpcUa-Item","z":"e1e4a455bdf7b20d","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.PLC_PRG.gInput001","datatype":"Boolean","value":"","name":"gInput","x":330,"y":420,"wires":[["b4aaf019d6bde6e5"]]},{"id":"89aae51628092960","type":"ui_text","z":"e1e4a455bdf7b20d","group":"952cda7cb8019a3d","order":3,"width":0,"height":0,"name":"Input","label":"gInput001","format":"{{msg.payload}}","layout":"row-spread","className":"","x":730,"y":420,"wires":[]},{"id":"7ddd8555903772fc","type":"ui_gauge","z":"e1e4a455bdf7b20d","name":"Counter","group":"952cda7cb8019a3d","order":5,"width":0,"height":0,"gtype":"gage","title":"Counter","label":"units","format":"{{value}}","min":0,"max":"65535","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","className":"","x":740,"y":480,"wires":[]},{"id":"b4aaf019d6bde6e5","type":"OpcUa-Client","z":"e1e4a455bdf7b20d","endpoint":"a1c9116733215552","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"1","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","name":"Subscribe","x":540,"y":400,"wires":[["17a6b19b660e193f","89aae51628092960"]]},{"id":"b59193780ad42b14","type":"OpcUa-Client","z":"e1e4a455bdf7b20d","endpoint":"a1c9116733215552","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"1","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","name":"Subscribe","x":540,"y":480,"wires":[["7ddd8555903772fc"]]},{"id":"ca7543de1070b079","type":"ui_button","z":"e1e4a455bdf7b20d","name":"Monitor","group":"952cda7cb8019a3d","order":1,"width":0,"height":0,"passthru":false,"label":"Start","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"true","payloadType":"bool","topic":"topic","topicType":"msg","x":160,"y":360,"wires":[["8fa9cfdda22b99d7","753cf4a165d0d134","3bcb0fc232647942"]]},{"id":"b4cbb1eea7449882","type":"ui_group","name":"Browse","tab":"ec09a280e1494ca8","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"a1c9116733215552","type":"OpcUa-Endpoint","endpoint":"opc.tcp://192.168.1.94:4840","secpol":"None","secmode":"None","login":false},{"id":"952cda7cb8019a3d","type":"ui_group","name":"Main","tab":"ec09a280e1494ca8","order":2,"disp":true,"width":"6","collapse":false,"className":""},{"id":"ec09a280e1494ca8","type":"ui_tab","name":"ホーム","icon":"dashboard","disabled":false,"hidden":false}]

3.OPC UAのノードのEndpointを設定する
フロー上の「OPC UA Browser」のノードをダブルクリックしEndpointを通信先のデバイスに合わせる。

4.デプロイする Node-REDの画面右上のデプロイボタンを実行する

5.ダッシュボードを起動する
Node-REDの右上にある▽ボタンを押下し、Dashboardを選択する。下図のタブの隣にある四角形から矢印が出ているアイコンをクリックする。目標に書いた画面が表示されればOK。
f:id:ritty1224:20211017161647j:plain

Node-REDで変数読み書き

あとは画面操作のみ。

  1. STARTボタンを押す
    変数のモニタが開始する。

  2. Power (gInput001)スイッチをONにする
    gInput001がTrueになり、gOutput001, gCounterの値が変わる。CODESYSの開発環境でプログラムをモニタしても変数の値が変わっていることが分かる。

調べたこと

  • OPC UAサーバのアドレス空間
    OPC UAのサーバアドレス空間は、PLCOpenとOPC UAで定めたPLC の内部情報を公開するアドレス仕様に従っている。この規格に従っているPLCは同じように内部情報を公開するため、上位系システムのMESやSCADAからの情報取得が容易となっている。アドレス空間はノードで構成されており、これらを識別するNode IDでアクセスが可能。
    詳しくはまだ勉強不足。おもしろそうなので今後勉強していく

  • ダッシュボードのBrowseボタン
    Browseボタンを押下すると下段にアドレス空間のノード情報が表示される。ドロップダウンリストでDeviceSetを選択し、Browseボタンを押す。これによりアドレス空間を探索する。DeviceSet→CODESYS Control for Raspberry Pi MC SL→Resources→Application→Programs→PLC_PRGと探索していくとgInput001, gOutput001, gCounterが見つかる。ns=4;s=・・・の部分がNode ID。変数の読み書きする際に使用する。 f:id:ritty1224:20211017162811j:plain

  • Node-REDのフロー
    Browseで探索した変数のNode IDは、gInputなどのノードのitemプロパティに設定している。画面を操作するとNode IDに従い、OPC UAサーバのアドレス空間の値を読み書きしている。

さいごに

今回、Node-REDとOPC UAを使ってみて思ったこと。
- 制御システムの情報の見える化のための通信ロジックやデータ制御ロジックなどいわゆるビジネスロジックは一切書かずに実現できた。そういう意味では簡単と言える。
- シンプルな画面は公開されているノードを使用することで容易に作ることができる。
- 複雑な画面を作るには、HTMLやJavaScript, CSSなどのスキルが必要
- OPC UAはFAにおけるデータ交換のオープンな国際標準規格として広まっており、様々な業界でOPC UAによる標準化が進んでいる。産業IoTにはこの知識、スキルは必須。

www.fa.omron.co.jp