Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9707

今さら OPC DA で接続してみる

$
0
0
OPC クライアントのアプリケーション(OPC DA Classic)を C#で作成した時のメモです。 OPC Server に [接続]して [タグ値の読込] [タグへの値書込]と[クローズ] をおこないました。 出来る限り,C#コードの説明を中心に,関連事項は簡素化してます。 準備したもの OPC Server と PLC PLCをOPC ServerにEthernetで接続しタグの現在値を表示できるようにします。 ・OPC Server: たけびしDeviceXPlore v6.4.0.1(x86)デモ版をインストール。(1時間動きます) ・PLC: 三菱電機 FX5UCPU。 ・GX Works3 でPLCの内蔵Ethernetポートを設定します。 (GX Works3 Version1 1.066U を使いました) ・OPC Serverを操作して PLCとの接続, 数点のタグを登録します。 (OPC Server と GX Works3 の操作は,説明書を参照しました) ・OPC Serverをインストールすると同時にインストールされるOPC Clientを使ってタグの値の 読込/書込の操作を行っておくとアプリケーション作成の理解に手助けとなります。 C# ・Visual Studio 2017 で 新規プロジェクト [Windows フォームアプリケーション(.NET Framework) Visual C#] を作成しました。 ・[プロジェクト] -> [参照の追加] を選択して表示される [参照マネージャー] から [タイプライブラリ]を選択し[OPC DA Automation Wrapper] にチェックを入れて[OK]します。 (VS2019では [OPC DA Automation Wrapper]は表示されませんでした。) ・Form1のコード Form1.cs を開きます。 using OPCAutomation を追加します。 オブジェクトブラウザーでOPCAutomationが確認できます。 using System; using System.xxxxxxx; // // using OPCAutomation; ・OPC ServerをインストールしたPCとC#で作成のOPC Client アプリケーションは同じPCで 起動してください。別のPCで起動する場合,接続のための設定が必要となります。 参考コード (ひとつの例に過ぎません。間違いがあったらお知らせ頂くと有り難いです) OPCServer object を 宣言 // OPC Server object public OPCServer ConnectedOPCServer; // OPCGroups object public OPCGroup ConnectedGroup; 引数にOPC Server の情報を入れて, sProgID="Takebishi.Dxp.6"; OPC ServerのID sNode="XXX.XXX.XXX.XXX"; ipアドレス さて, OPC Server へ Connect で [接続]...。 public bool StartOpc(string sProgID, string sNode) { sErrMsg = ""; try { ConnectedOPCServer = new OPCServer(); ConnectedOPCServer.Connect(sProgID, sNode); } catch (Exception ex) { sErrMsg = ex.Message; return true; } return false; } グループ名のAdd 次にグループ名をAddします。そして,OPC Serverに既に登録されているタグ名をAdd します。 ・引数 sIOGroup="Group1"; として OPCGroups.Add(sIOGroup) しました。 グループ名は,識別できる文字列を設定します。 public bool AddGroupOPC(string sIOGroup) { sErrMsg = ""; try { ConnectedGroup = ConnectedOPCServer.OPCGroups.Add(sIOGroup); ConnectedGroup.UpdateRate = 1000; } catch (Exception ex) { sErrMsg = ex.Message; return true; } return false; } TAG名称のAdd ・OPCItems.AddItems には配列(OPCItemIDs)でTAG名を渡します。 この他にもパラメータとして渡す配列が必要です。(全部で6コ) また,これらの配列は基数が[1]から処理されます。配列に値を設定する場合, その添字には注意が必要です。 ・OPC Serverに,タグを3つ登録し名称を, [1運転], [2停止], [3出力]としました。 それぞれ PLCレジスタは M0, M1, M100 に設定しています。 一方,PLC側に M0, M1, M100で自己保持回路をセットし,M100 の接点を Y0 に接続しています。 ・配列の宣言,割付です。タグの数はiNumOfItem=4として設定します。 public int iNumOfItem { get; set; } public Array OPCItemIDs; public Array ClientHandles; public Array ItemServerHandles; public Array ItemServerErrors; public Array RequestedDataTypes; public Array AccessPaths; // ・ // ・ OPCItemIDs = Array.CreateInstance(typeof(string), iNumOfItem); ClientHandles = Array.CreateInstance(typeof(Int32), iNumOfItem); ItemServerHandles = Array.CreateInstance(typeof(Int32), iNumOfItem); ItemServerErrors = Array.CreateInstance(typeof(Int32), iNumOfItem); RequestedDataTypes = Array.CreateInstance(typeof(Int16), iNumOfItem); AccessPaths = Array.CreateInstance(typeof(string), iNumOfItem); // ・ // ・ ・OPCItemIDsにタグ名称を設定します。配列[1]からの扱いとなります。タグ名称には [Device1.]を付加しておきます。([Device1.]は,OPC Serverに依る文字列ですが設定も可能です) OPCItemIDs.SetValue("Device1.1運転", 1); OPCItemIDs.SetValue("Device1.2停止", 2); OPCItemIDs.SetValue("Device1.3出力", 3); ・それでは,OPCItems.AddItems にパラメータを渡します。 public bool AddItemOPC() { sErrMsg = ""; try { ConnectedGroup.OPCItems.DefaultIsActive = true; ConnectedGroup.OPCItems.AddItems(iNumOfItem - 1, ref OPCItemIDs, ref ClientHandles, out ItemServerHandles, out ItemServerErrors, RequestedDataTypes, AccessPaths); } catch (Exception ex) { sErrMsg = ex.Message; return true; } return false; } タグへの値書込と読込 ・これには同期と非同期の2つの方式があります。今回は,同期の方式のみを扱います。 非同期はデリゲートを設定して動作完了時に呼び出しされることになります。 次回の機会に扱うことにします。 ・配列に値を代入して引数としますので宣言, 割付けします。 public Array aryValues; public Array aryErrors; // ・ // ・ aryValues = Array.CreateInstance(typeof(object), iNumOfItem); aryErrors = null; // ・ // ・ 同期書込 ・引数:タグのID(sIdItem)="1",書込値(sValWrt)="1"で書込むとタグ名称[1運転]の値が[ON] となります。PLCのラダーが処理して,[3出力]:ON, PLCの[Y0]:ON となります。 すると同時に,PLC本体前面の[Y0]位置LEDが点灯するはずです。同様に, 引数:タグのID(sIdItem)="2",書込値(sValWrt)="1"で書込むとタグ名称[2停止]の値が[ON] となります。PLCのラダーが処理して[3出力]:OFF,PLCの[Y0]:OFFとなります。 今度は,PLC本体前面の[Y0]位置LEDが消灯するはずです。 ・実際に,sIdItem="1", sValWrt="1" としてSyncWrt_OPCに引数を設定したところ, PLCの[Y0]位置のLEDが点灯しました。 public void SyncWrt_OPC(string sIdItem, string sValWrt) { sErrMsg = ""; int iIdItem = Convert.ToInt32(sIdItem); Array.Clear(aryValues, 0, aryValues.Length); aryValues.SetValue(sValWrt, iIdItem); try { ConnectedGroup.SyncWrite(iIdItem, ref ItemServerHandles, ref aryValues, out aryErrors); } catch (Exception ex) { sErrMsg = ex.Message; } } ・次に,sIdItem="2", sValWrt="1" で試ました。PLCの[Y0]位置のLEDが消灯しました。 同期読込 ・引数:タグのID(sIdItem)="1" とすれば RdValueにはタグの値, shQualitiesに品質, dtTimeStampにタイムスタンプが入ってきます。 public bool SyncRead_OPC(string sIdItem, ref string RdValue, ref short shQualities, ref DateTime dtTimeStamp) { sErrMsg = ""; int iIdItem = Convert.ToInt32(sIdItem); System.Array aryRdValues; System.Array aryErrors; object obQualities = new object(); object obTimeStamp = new object(); int iNumItems = 1; try { Array SyncServerHandles = Array.CreateInstance(typeof(Int32), iNumOfItem); SyncServerHandles.SetValue(ItemServerHandles.GetValue(iIdItem), 1); // SyncServerHandles[1]に書込む ConnectedGroup.SyncRead((short)OPCDataSource.OPCDevice, iNumItems, ref SyncServerHandles, out aryRdValues, out aryErrors, out obQualities, out obTimeStamp); var RdError = aryErrors.GetValue(1); bool bErr = Object.Equals(RdError, 0); if (!bErr) { return true; } var vdRdValue = aryRdValues.GetValue(1); RdValue = Convert.ToString (vdRdValue); var aryQualities = (Array)obQualities; shQualities = (short)aryQualities.GetValue(1); var aryTimeStamp = (Array)obTimeStamp; dtTimeStamp = (DateTime)aryTimeStamp.GetValue(1); } catch (Exception ex) { sErrMsg = ex.Message; return true; } return false; } クローズ処理 ・引数 sGrpName="Group1"として OPCItemsをRemove, OPCGroupsをRemovesして Disconnect()します。 public bool FinishOpc(string sGrpName) { sErrMsg = ""; try { if (ConnectedGroup != null) { ConnectedGroup.OPCItems.Remove(iNumOfItem - 1, ref ItemServerHandles, out aryErrors); ConnectedOPCServer.OPCGroups.Remove(sGrpName); ConnectedGroup.IsSubscribed = false; } ConnectedOPCServer.Disconnect(); } catch (Exception ex) { sErrMsg = ex.Message; return false; } return true; } 終わり ・OPC Classic で 単純な[接続],[読込],[書込],[クローズ]を行ってみました。 OPC Server のタグの登録するにあたって(余談) ・OPC Serverにタグを登録する際,PLCの説明書でPLCデバイスの種類と目的を確認 してください。 OPC Serverのタグ登録ではPLCデバイス種類を X,Y,M,B... と簡単に選択できますが,PLC側では デバイスの種類は用途によって大きく異なります。例えば, PLC:FX5UCPUのデバイス種類 の[Y]の目的は出力です。OPCタグを[Y]に割付けるとOPCタグ値の1/0 がPLCの出力端子に ON/OFFとしてそのまま出力されます。 (最終の出力はIOリフレッシュがあるのでPLC側プログラムに依ります) PLCが設置される"XX盤"ではOPCのタグといえども外部信号には違いありません。外部信号は 端子台からPLCへ結線されるものです。ところが結線は不可能なので,OPCタグの登録には 慎重さが必要となります。OPCタグをいきなり[Y]に割付したりして... たとえが古いですが,操作盤の[遠方]<->[手元]のセレクタを[遠方]にした途端にマグネットが どうなるか... 推して知るべし です。 参照した資料 https://www.codeproject.com/Articles/490072/DA-1-OPC-Wrapper-DLL-and-Client-Example Data Access Automation Interface Standard Version 2.02 February 4, 1999

Viewing all articles
Browse latest Browse all 9707

Trending Articles