Project#Rockwell EIP Scanner x Beckhoff TwinCAT EIP Adapter with 8 Assemblies

この記事では私はBeckhoff IPC C6920とTwinCAT3を使って一つのEtherNet/IP Adapterの中に8つのAssembliesを構築し、Rockwell Compact GuardLogix L43S + 1768 ENBAT-A組み合わせのEtherNet/IP ScannerでEtherNet/IP ネットワークを構成します。

TwinCATは一つのIP Addressに最大8個のAssembliesを作成できるってことは、IPの節約になるだけではなく、複数のScannerから様々なデータにアクセスできます。たとえばAssemblies1はZone1、Assemblies2はZone2…のように。そして最後はRockwell側でST言語を使用しIOデータが一致してるかをCheckするプログラムも作成します。

では、始めましょう!

Thanks!

この記事が出来上がるのはベッコフ日本法人ベッコフオートメーション株式会社さまから機材を貸してくださったおかけです。誠にありがとうございます。

ベッコフ日本法人ベッコフオートメーション株式会社

IPC6920-005はベッコフ日本法人ベッコフオートメーション株式会社さまが貸してくださったものです。Beckhoff Automationは1980 年会社設立、PCベースの制御技術をベースにしたオープンオートメーションシステム導入の先頭に立つドイツ企業です。

ベッコフ日本法人ベッコフオートメーション株式会社は、2011年に横浜に本社、2017年に名古屋オフィスを設立しました。

こちらはベッコフ日本法人ベッコフオートメーション株式会社様のホームページです。

どうぞよろしくお願いします。

https://www.beckhoff.com/ja-jp/

Implementation-1

最初のImplementationはBeckhoff TwinCAT側で一つのEtherNet/IP Adapterで8つのAssembliesを作成します。各Assembliyは64 BytesのIn/outデータを占有します。

TwinCAT Side

まずTwinCAT Sideから構築します。

Choose Target

Projectをクリック>Choose Targetします。

いまTwinCATがIPCと繋がっているかを確認しましょう。

Add Ethernet/IP Adapter

I/O>Devices>Add New Itemします。

EtherNet/IP>Ethernet/IP Adapter(Slave)を選び>Okします。

Ethernet/IP Networkで接続してるEthernet Interfaceを選択し>Okします。

Adapter Tabを開き、設定されたInterfaceが正しいかを再確認しましょう。

Sync Task

Sync Taskを開き、Special Sync Task Optionsを設定>Create new I/O Taskします。

Task名を入力>Okします。

Ethernet/IP Adapter用のTaskが作成されました。

Configure The box

次はEthernet/IP Adapter Connectionの設定を行います。

IP

Settings Tabを開き、8000:21、8000:22でIpとNetwork Maskを設定します。

アプリケーションに合わせて入力しましょう。

Append IO Assembly

次はIO Assemblyを追加します。Box>右クリック>Append IO Assemblyで新規Assemblyを追加します。

“Assembly 1(Input/Output)” は作成されました。

Add New Item-INPUT

Default上でTwinCATはInput/Outputデータも自動作成しませんので、手動でDataを作成しましょう。Inputs>右クリック>Add New Itemします。

変数名を入れ、WordをData Type設定>Create Array Typeします。

31 Wordsの配列が定義されました。

Add New Item-OUTPUT

Outputも同じようにデータを追加します。Outputs>右クリック>Add New Itemします。

変数名を入れ、Data Typeを Array[0..31]of WORD設定>Okします。

Output 変数が作成されました。

Add More Assembly!

次はAssemblyをCopyし、同じくBoxで貼り付ければOKです。(注意するのは1つのBoxは同時にMax8 Connectionsに制限されています)

Export EDS

Box1>右クリック>Export EDS FileでEDS FileをExportします。

Choose Yes.

Export 先を設定しましょう。

Done!

Add PLC

次はPLC>Add New Item.でPLCを追加します。

Standard PLC Project>AddでPLCを追加します。

ADD DUT

8つのAssembliesがProjectにあるので、DUTを作成しPLCの変数を定義したほうが手間がかかりません。右クリック>Add>DUTします。

DUT名を入力>Structureを選択>Openします。

DUTの中にProcess InputとProcess Outputのarray[0..31]変数とConnection状態を示すUDINTを定義します。それらの変数はAssemblyのInput/Output/ConnState変数と紐つけます。

TYPE DUT_Boxes :
STRUCT
InData AT %I* :ARRAY[0..31]OF WORD;
OutData AT %Q* :ARRAY[0..31]OF WORD;
ConnState AT %I* :UDINT;
END_STRUCT
END_TYPE

ADD GVL

いまはGlobal Variable List(GVL)を作成し変数を定義します。

Boxesの中に8つのAssemblyがありますので、配列長8のDUT_Boxesの変数を定義します。

{attribute ‘qualified_only’}
VAR_GLOBAL
Boxes :ARRAY[1..8]OF DUT_Boxes;
END_VAR

PROGRAM

Main Program中にInput dataをそのままOutput DataにLoopbackするだけです。IOデータ一致性のCheckはRockwell側で行います。

PROGRAM MAIN
VAR
i,j :DINT;
END_VAR


FOR i:=1 TO 8 DO

FOR j:=0 TO 31 DO
GVL.Boxes[i].OutData[j]:=GVL.Boxes[i].InData[j];
END_FOR;

END_FOR

Build

Build>Build Solution でProjectをコンパイルします。

Link Variables

最後は変数をProcess Input/Outputと紐つけます。

Inputs-ConnState

まずはConnState変数をLinkします。その変数は該当するAssemblyのConnection Statusを示しています。

GVL内の1つ目の変数を選び>OK!

Inputs-data

次はInput dataをUser Programと紐つけます。GVLで定義した配列は100%Dataのサイズと同じなので、直接右クリック>Change Linkで一括設定できます。

Outputs-data

最後にOutput DataをUser ProgramとLinkしましょう。GVLで定義した配列は100%Dataのサイズと同じなので、直接右クリック>Change Linkで一括設定できます。

Activate Configuration

Activate ConfigurationでHardware ConfigurationをRuntimeにDownloadします。

OKで進みます。

ライセンスが足りないならYesでライセンス入力画面に切り替えます。

Magic Codeを入力>Okします。

OKでTwinCATを再起動しRun Modeに切り替えます。

Login

LoginでUser ProgramをRuntimeにDownloadします。

Yesで進みます。

Start

StartでProgramをRunします。

Rockwell Side

次はRockwell Sideに着手します。

Import EDS File

下記のLinkからEDS FileのImport方法を参考にしてください。

Rockwell#AB PLC EDS File追加方法

Add TwinCAT Adapter

Hardware ConfigurationにBeckhoff TwinCAT Ethernet/IP Adapterを追加します。

1768-ENBT/Aを右クリック>New Moduleします。

Beckhoffを検索します。

そのAdapterを選び>Createで作成します。

Box1はEthernet/IP Networkに追加されました。

Configure IP Address

先程設定したBeckhoff TwinCAT Etherenet/IP Adapterをクリックします。

Adapter名に名前を設定>IP Addressを入力しましょう。

Connection Tabを開き、いまAssembly1をExclusive ownerとして構築しています。

Configure Connections

General Tabに戻り、Change ボタンをクリックしConnectionを変更します。

Connectionの設定画面が表示されました。

Drop ListからAssembly2 Inputs and Outputs(Exclusive Owner)を使って2つ目のConnectionを作成します。

Done!新しいConnectionが作成されました。

他のConnectionも同じく作りましょう。

General Tabに戻ると、すべてのConnectionも構成されました。

Download

Communication >DownloadでプロジェクトをCPUにDownloadしましょう。

.

Downlaodで進みます。

しばらく待ちます…

Done!CPUをリセットRunします。

Result

RSLogix 5000からI/O OK のLEDは緑色になりました!つまりRockwell PLCとTwinCAT 間でEtherNet/IP 通信も確立しました!

Implementation-2

EtherNet/IP通信を確立したところで、次はRockwell側で簡単なラダーロジックでIOデータ転送したり、Connection Checkしたりしましょう。

Rockwell Side

Controller Tags

Controller Tagsを開くと、RsLogic5000はBox1の通信Tagをすでに自動作成してくれました。

Program

Now we can create some Ladder Program. Open the MainRoutine.

ラダープログラムを作成します。MainRoutineを開きます。

End Lineのところを右クリック>Add Rungで新しいRungを追加します。

A接点をRung0にDropします。

A接点がRung0に追加されました。

ConnectionFaulted 変数と紐付け、通信エラーが発生するとその変数がTrueになります。

次は通信エラーが発生したときTwinCATに転送するデータを0にリセットしたいので、“Move/Logical”からMOV命令をRung0にDropします。

Rung0の一番うしろにMove Blockが追加されました。

Source パラメータを0に入力し、DestパラメータをBox1_Ass1:O1:Data[4]に入力します。

次に、ConnectionFaultedはFalseするときTwinCATに与えを転送したいので、End Rungを右クリック>Add Rungで新しいRungを追加します。

Rung1が追加されました!

今度はB接点をRung1にDropします。

同じくConnectionFaulted変数と紐つけます。

もしConnectionFaultedがFalseであれば、TwinCATへの出力をずっと加算するようにしたいので、“Compute/Math”からAdd命令をDropします。

ADD Blockが追加され、Soruce AをAssign Box1_ASS1:O1で、Source Bは定数1、Destは Assign Box1_ASS1:O1:Data[4]に割り付けます。

Result

ProjectをCPUにDownloadし結果を見てみましょう。Connectionが確立すると変数はずっと加算されています。

TwinCAT側をみると、InData[0] の現在値もCycleで更新されていますね。

Implementation-3

最後はRockwell側でSTプログラムを作成、IO Dataの一致性をCheckしていきます。

Rockwell Side

Instruction Memo

これからは今回使用する命令のメモです。

TONR

TONR はリセット可能なDelay On Timerです。

Input Parameters
NameData TypeDescription
EnableInBOOLFunction Block:False=命令は実行せず、出力も更新しません。DefaultはTrueです。
Structured Text:命令を実行する。
TimerEnableBOOLTrue=Timerは時間をCount始めるDefaultはFalseです。
PREDINTTimerの設定値。単位は1msec です。
ResetBOOLTimerをリセットする
Output Parameters
NameData TypeDescription
EnableOutBOOL命令は正常に実行されています。
ACCBOOL現在の加算時間値(milliseconds.)
ENDINTTrue=Timerは有効中
TTBOOLTrue=Timer実行中
DNBOOLDelay Timer ON
StatusDINTStatus of the function block.Function blockの状態になります。Status.01:命令実行中にエラー発生Status.02:Timer設定値は無効
Flow

Example
TONR_01.Preset := 500;
TONR_O1.Reset := reset;
TONR_01.TimerEnable := limit_switch1;
TONR(TONR_01)
timer_state := TONR_01.DN;

COP

これは三菱のBMOVと同じだと思っていただければと思います。

Parameters
NameData TypeDescription
SourceSINT/INT/DINT/REAL/structureCopy元
DestinationSINT/INT/DINT/REAL/structureCopy先
LengthDINTnumber of Destination elements to copyCopyするデータのTotol長さ
Example
COP(array_4[0],array_5[0],10);
COP(timer_1,array_timer[5],1);

Add New Routine

IO データを検証するプログラムはST言語で実装します。MainProgram>右クリック>New Routineをクリックします。

Routine名を入力し、TypeをStructured Text選び>Okします。

新しいRoutineが作成されました。

Change Routine

次はMainTaskの中の呼び出しのプログラムを変更します。

MainProgramを右クリック>Propertiesします。

元に”MainRoutine”がAssgined Routineのところに設定されていましたが、MySTProgramに変更しましょう。

MainのFieldからMySTProgramをそのまま選択すればOKです。

Done!

MySTProgram

次はプログラムを作成します。

Program Tags

こちらの変数はプログラム内で使用します。

  • bCheck:Checkプログラムをトリガーする
  • bError: True=IO Data不一致
  • bOK:True=IO Data一致
  • bResetTagValue:Output Dataをリセットする
  • bSetTagValue:Output Dataをセットする
  • iCounter:For loopで使用するCounter 変数
  • iStep:the Case step制御用の変数
  • MyTimer:IO DataをCheckするまでのDelay Timer
  • Value:書き込みデータのベース
  • TimeSetting:IO Data をCheckするのDelay時間

PROGRAM

プログラムはまずAdapter(TwinCAT)と接続状態を確認>出力データを書き込み>Delay>Input DataとOutput Dataは一致するかCheck>Loop Backだけです。





if not Box1_Ass1:I1.ConnectionFaulted  and not Box1_Ass1:I2.ConnectionFaulted  and not Box1_Ass1:I3.ConnectionFaulted and not Box1_Ass1:I4.ConnectionFaulted and not Box1_Ass1:I5.ConnectionFaulted  and not Box1_Ass1:I6.ConnectionFaulted and not Box1_Ass1:I7.ConnectionFaulted and not Box1_Ass1:I8.ConnectionFaulted then ConnectionOK:=1; else ConnectionOK:=0;
end_if;
if TimeSetting <=0 then TimeSetting:=100;
end_if;
MyTimer.EnableIn:=1;MyTimer.TimerEnable:=iStep= 30 or iStep = 65;MyTimer.PRE:=TimeSetting;
TONR(MyTimer);

case iStep of 
0: if ConnectionOK and not bError then iStep:=10; end_if; 10: bOK:=0; bSetTagValue:=1; iStep:=20; 20: if not bSetTagValue then iStep:=30; end_if; 30: if MyTimer.Dn then iStep:=40; end_if; 40: bCheck:=1; if bOK  then iStep:=50; bCheck:=0; end_if; if bError then iStep:=999; end_if; 50: bResetTagValue:=1; iStep:=60; 60: if not bResetTagValue then iStep:=65; end_if; 65: if MyTimer.Dn then iStep:=70; bOK:=0; end_if; 70: bCheck:=1; if bOK then iStep:=10; bCheck:=0; end_if; if bError then iStep:=999; end_if; 999: bCheck:=0; bOK:=0; iStep:=0;end_Case;

if bCheck and not bError then
for iCounter:=4 to 67 do if Box1_Ass1:O1.Data[iCounter] <> Box1_Ass1:I1.Data[iCounter]then bError:=1; elsif Box1_Ass1:O2.Data[iCounter] <> Box1_Ass1:I2.Data[iCounter] then bError:=1; elsif Box1_Ass1:O3.Data[iCounter] <> Box1_Ass1:I3.Data[iCounter] then bError:=1; elsif Box1_Ass1:O4.Data[iCounter] <> Box1_Ass1:I4.Data[iCounter] then bError:=1; elsif Box1_Ass1:O5.Data[iCounter] <> Box1_Ass1:I5.Data[iCounter] then bError:=1; elsif Box1_Ass1:O6.Data[iCounter] <> Box1_Ass1:I6.Data[iCounter] then bError:=1; elsif Box1_Ass1:O7.Data[iCounter] <> Box1_Ass1:I7.Data[iCounter] then bError:=1; elsif Box1_Ass1:O8.Data[iCounter] <> Box1_Ass1:I8.Data[iCounter] then bError:=1; end_If; end_for; if not bError then bOK:=1; end_if;
end_if;

if bSetTagValue or bResetTagValue then for iCounter:=4 to 67 by 2 do if bSetTagValue then COP(iCounter,Box1_Ass1:O1.Data[iCounter],2);
Value:=iCounter*10; COP(Value,Box1_Ass1:O2.Data[iCounter],2); Value:=iCounter*20; COP(Value,Box1_Ass1:O3.Data[iCounter],2); Value:=iCounter*30; COP(Value,Box1_Ass1:O4.Data[iCounter],2); Value:=iCounter*40; COP(Value,Box1_Ass1:O5.Data[iCounter],2);
Value:=iCounter*50; COP(Value,Box1_Ass1:O6.Data[iCounter],2);
Value:=iCounter*60; COP(Value,Box1_Ass1:O7.Data[iCounter],2);
Value:=iCounter*70; COP(Value,Box1_Ass1:O8.Data[iCounter],2); end_if; if bResetTagValue then Value:=0; COP(iCounter,Box1_Ass1:O1.Data[iCounter],2); COP(iCounter,Box1_Ass1:O2.Data[iCounter],2); COP(iCounter,Box1_Ass1:O3.Data[iCounter],2); COP(iCounter,Box1_Ass1:O4.Data[iCounter],2); COP(iCounter,Box1_Ass1:O5.Data[iCounter],2); COP(iCounter,Box1_Ass1:O6.Data[iCounter],2); COP(iCounter,Box1_Ass1:O7.Data[iCounter],2); COP(iCounter,Box1_Ass1:O8.Data[iCounter],2); end_if; end_for; bSetTagValue:=0; bResetTagValue:=0;end_if;

Result

TwinCAT3 Side

こちらはTwinCAT側の結果です。ConnState=0、つまり接続OKで、入力データは常に更新されています。

Rockwell Side

Rockwell側でも出力を更新しずつエラーがありません。

If Error..

もしIO Data不一致の場合、bError=Trueになり、Stepも0に戻ります。

Source Project

こちらのLinkから記事のプロジェクトをDownloadしてください。

https://github.com/soup01Threes/TwinCAT3/blob/main/TwinCAT_EIP_Rockwell.tnzip

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

シェアする

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

フォローする