今回はTF6420のLibraryを使用しPostgreSQL DBと接続し、TwinCATが提供しているAPIを使用しDBのデータを更新したり取得します。
さ、はじめよう!
Reference Link
Function Block
今回は記事内で使用したFunction Blockを紹介します。今回はPostgreSQL DBに”UPDATE”と”SELECT”コマンドを使用するので赤枠のFlowでプログラムを作成します。
- UPDATEなどSQL DB Serverからデータをしないコマンドの場合は、
- FB_SQLDatabase.Connect()でSQL DBと接続する
- FB_SQLDatabase.CreateCmd()でFB_SQLCommand を初期化する
- FB_SQLCommand.Execute()でSQLDBにコマンドを送信する
- FB_SQLDatabase.Disconnected()でSQLDBの接続を切断します。
- SELECTなどSQL DB Serverからデータを取得するコマンドの場合は、
- FB_SQLDatabase.Connect()でSQL DBと接続する
- FB_SQLDatabase.CreateCmd()でFB_SQLCommand を初期化する
- FB_SQLCommand.ExecuteDataRetrun()でSQLDBにコマンドを送信する
- FB_SQL_Result.Read()でSQLDBから取ったデータを読み込む
- FB_SQL_Result.Release()でSQLDBから取ったデータをBufferから削除
- FB_SQLDatabase.Disconnected()でSQLDBの接続を切断します。
FB_SQLDatabaseEvt
こちらのFunction Blockを使用しSQL データベースの接続を管理できます。
VAR_INPUT
Variable | Type | Description |
sNetID | T_AmsNetID | ADS Command対象となるデバイスのAMSネットワークID |
tTimeout | TIME | Functionの実行がキャンセルされるまでの時間を設定します |
VAR_OUTPUT
Variable | Type | Description |
bBusy | BOOL | 1=Function Block実行中 |
bError | BOOL | 1=Function Blockエラーあり |
ipTcResult | Tc3_EventLogger.I_TcMessage | Function Blockの実行状態を提供できるTwinCAT 3 EventLogger Messsage Interface |
Method:Connect
データベースと接続します。
METHOD Connect : BOOL VAR_INPUT hDBID: UDINT := 1; END_VAR |
VAR_INPUT
Variable | Type | Description |
hDBID | UDINT | 使用するデータベースのIDを設定します |
RetureValue
Variable | Type | Description |
Connect | BOOL | True=Methodが実行完了の(エラーがある場合もTrueになります) |
Method:CreateCmd
こちらのMethodを使用し既に開いているデータベース接続で、コマンド生成などの FB_SQLCommandEvt のInterfaceを初期化します。
ManualにはFunction Block FB_SQLCommand の初期化は同じのサイクルで完了できると書きましたが、Bug防止のためBusy Flagの立ち上げ>そしてまたたち下げの変化をMonitorしたほうがよいだ思います。
VAR_INPUT pSQLCommand: POINTER TO FB_SQLCommandEvt; END_VAR |
VAR_INPUTS
Variable | Type | Description |
pSQLCommand | POINTER TO FB_SQLCommand | 初期化完了された、新しいFunction Block FB_SQLCommandEvtのInstance取得する |
ReturnValue
Variable | Type | Description |
CreateCmd | BOOL | True=Methodが実行完了の(エラーがある場合もTrueになります) |
FB_SQLCommandEvt
Function block for executing SQL commands. Before it can be used it has to be initialized with the function block FB_SQLDatabaseEvt.
VAR_INPUT
Variable | Type | Description |
sNetID | T_AmsNetID | ADS Command対象となるデバイスのAMSネットワークID |
tTimeout | TIME | Functionの実行がキャンセルされるまでの時間を設定します |
VAR_OUTPUT
Variable | Type | Description |
bBusy | BOOL | 1=Function Block実行中 |
bError | BOOL | 1=Function Blockエラーあり |
ipTcResult | Tc3_EventLogger.I_TcMessage | Function Blockの実行状態を提供できるTwinCAT 3 EventLogger Messsage Interface |
Method:Execute
FB_SQLDatabaseで既にオープンされているデータベース接続を介して、 SQL コマンドをデータベースに送信します。
METHOD Execute : BOOL VAR_INPUT pSQLCmd: POINTER TO BYTE; cbSQLCmd: UDINT; END_VAR |
VAR_INPUT
Variable | Type | Description |
pSQLCmd | POINTER TO BYTE | 実行するSQLコマンドの文字列変数Memory Pointer(ADR関数を使用すればよい) |
cbSQLCmd | UDINT | 実行するSQLコマンドの長さ(SIZEOF関数を使用すればよい) |
ReturnValue
Variable | Type | Description |
Execute | POINTER TO BYTE | Methodの実行Statusを示す戻り値になります。 |
Method:ExecuteDataReturn
FB_SQLDatabaseで既にオープンされているデータベース接続を介して、 SQL コマンドをデータベースに送信します。 Function Block FB_SQLResult のInstanceは、返されたレコードを読むために転送されたものです。
METHOD ExecuteDataReturn : BOOL VAR_INPUT pSQLCmd: POINTER TO BYTE; cbSQLCmd: UDINT; pSQLDBResult: POINTER TO FB_SQLResult; END_VAR |
VAR_INPUT
Variable | Type | Description |
pSQLCmd | POINTER TO BYTE | 実行するSQLコマンドの文字列変数Memory Pointer(ADR関数を使用すればよい) |
cbSQLCmd | UDINT | 実行するSQLコマンドの長さ(SIZEOF関数を使用すればよい) |
pSQLDBResult | POINTER TO FB_SQLResult | Function Block FB_SQLResult のInstanceを返す |
ReturnValue
Variable | Type | Description |
ExecuteDataReturn | POINTER TO BYTE | Methodの実行Statusを示す戻り値になります。 |
FB_SQLResultEvt
このFunction BlockはCachedされたレコードの読み取りに使用されます。
VAR_INPUT
Variable | Type | Description |
sNetID | T_AmsNetID | ADS Command対象となるデバイスのAMSネットワークID |
tTimeout | TIME | Functionの実行がキャンセルされるまでの時間を設定します |
VAR_OUTPUT
Variable | Type | Description |
bBusy | BOOL | 1=Function Block実行中 |
bError | BOOL | 1=Function Blockエラーあり |
ipTcResult | Tc3_EventLogger.I_TcMessage | Function Blockの実行状態を提供できるTwinCAT 3 EventLogger Messsage Interface |
Method:Read
こちらのMethodはTwinCAT Database ServerにCachedされたデータから、指定した数のレコードを読み出します。
VAR_INPUT
Variable | Type | Description |
nStartIndex | UDINT | 最初に読み込まれるレコードのIndexを設定する |
nRecordCount | UDINT | 読み込むレコード数を設定する |
pData | POINTER TO BYTE | レコードを書き込む構造体配列のMemory Pointer(ADR関数から取得できる) |
cbData | UDINT | 構造体配列のサイズをバイト数で設定する(SIZEOF関数から取得できる) |
bWithVerifying | BOOL | True=戻されたデータはpData構造体配列と比較し、調整する |
bDataRelease | BOOL | キャッシュされたデータをリリースする |
ReturnValue
Variable | Type | Description |
Read | BOOL | True=Methodが実行完了の(エラーがある場合もTrueになります) |
Implementation
こちらは今回の構成です。PostgreSQL ServerはRaspberry Pi4上でアクセスし、Beckhoff C6920からTF6420を使用しアクセスします。
Configuration
TF6420のData Serverを設定します。
Add New DataServer Project
TwinCAT IDEやVisual Studioから右クリック>Add>New Projectします。
Empty TwinCAT Database Server Projectを選び、Nextします。
TwinCAT Database Server Projectの名前を設定し、Createで進みます。
TcDbServerが作成しました。
Add PostgreSQL Database
TcDbServerを右クリック>Add New Databaseします。
DBが追加されました。
DBID=1で、このIDはPLCのAPIを使用するときに、非常に大事なパラメータです。
Database Type
Database TypeのDrop-listからデータベースの種類を設定します。
今回はPostgreSQLを使用します。
Done!
Host
HostはPostgreSQL DBがインストールされたデバイスのIPを設定します。
今回は192.168.5.144です。
Database
DatabaseはPostgreSQL内のDB名に合わせてください。
VSCODEのPostgreSQL Pluginからも確認できますが、今回はxa5を使用します。
Done!
Port
PostgreSQLのDefault通信Portは5432です。
Authentication
次は認証方法を設定します。DefaultはNoneです。
AuthenticationのDrop-listからUsername/Passwordを選択します。
Username/Passwordを設定するとUsernameとPasswordの入力Fieldが表示します。
Login情報を入力してください。
Connecton String
Connection Stringには先程設定したパラメータに沿ってConnection pathが表示されます。
CHECK Connection
CHECKボタンをクリックしTwinCATとDatabaseの接続をテストしましょう。
IF NO License..
0x724のエラーが表示されたらライセンスを生成しましょう。
SYSTEM>Licenseします。
TF6420をCheckします。
7 Days Trial LicenseのボタンをクリックしTrialライセンスを生成します。
Magic codeを入力します。
Done!
Activate ConfigurationでプロジェクトをDownloadしましょう。
OKで進みます。
Run Modeに切り替えましょう。
RESULT
もう一回接続テストを行います。今回はConfiguration check succededが表示されます。つまり接続OKです!
Activate Configuration
DB構成をTwinCAT Database ServerにDownloadします。
DB>右クリック>Activate Configurationします。
ADD PLC
次はPLCプロジェクトを追加するため、PLC>右クリック>Add New Itemします。
Standard PLC Projectを選び>Addします。
Add Library
TF6420のDatabaseライブラリをプロジェクトに追加するため、References>右クリック>Add libraryします。
Tc3_Databaseを追加します。
Done!
Program
次はプログラムを作成します。
DUT_SQL
こちらの構造体はDatabaseのXA5 にあるtags Tableのデータに合わせたものです。
TYPE DUT_SQL : STRUCT tagname:STRING(255); tagvalue:STRING(255); END_STRUCT END_TYPE |
VSCodeのPostgreSQL Plug-inからtagnameとtagvalueにも文字列があります。
How to get the size?
下記のコマンドで各Rowの変数サイズを確認できます。
SELECT tagvalue ,char_length(tagvalue) FROM tags; |
このように505=3など、文字の数に沿ったByte数になります。
FC_SQL_UpdateCommands
こちらのFunctionは自動的にSQLのUpdateコマンドを生成します。
FUNCTION FC_SQL_UpdateCommands : STRING(255) VAR_INPUT iValue:INT; iTag:STRING; END_VAR VAR END_VAR FC_SQL_UpdateCommands:=’UPDATE tags SET tagvalue = ‘; FC_SQL_UpdateCommands:=CONCAT(STR1:=FC_SQL_UpdateCommands,STR2:=INT_TO_STRING(iValue)); FC_SQL_UpdateCommands:=CONCAT(STR1:=FC_SQL_UpdateCommands,STR2:=’ ‘); FC_SQL_UpdateCommands:=CONCAT(STR1:=FC_SQL_UpdateCommands,STR2:=’WHERE tagname = ‘); FC_SQL_UpdateCommands:=CONCAT(STR1:=FC_SQL_UpdateCommands,STR2:=iTag); |
MAIN
こちらは実際のプログラム制御Flowになります。
- Step0=パラメータ初期化
- Step10=PostgreSQL DBと接続します
- Step20=FB_SQLCommandEvtを初期化します。
- Step30‐45=PostgreSQL DBにUpdateコマンドを送信する
- Step50=PostgreSQLにSelectコマンドを送信する
- Step60=Selectコマンドから取得されたデータをPLC変数に転送する
- Step70=1秒待ち、またStep20に戻る
PROGRAM MAIN VAR FB_SQLDatabaseEvt:FB_SQLDatabaseEvt(sNetID := ”, tTimeout := T#5S); FB_SQLCommandEvt:FB_SQLCommandEvt(sNetID := ”, tTimeout := T#5S); FB_SQLResultEvt :FB_SQLResultEvt(sNetID := ”, tTimeout := T#5S); tags:ARRAY[0..99]OF DUT_SQL; iStep:INT; SQL_Commands:ARRAY[1..4]OF STRING(255); iCounter:INT:=0; i:INT; isubstep:INT; iErrorCounet :INT; sSelectDataCommand :STRING(255); TON_Process :TON; END_VAR CASE iStep OF 0: TON_Process(IN:=FALSE); iCounter:=1; iStep:=10; 10: FB_SQLDatabaseEvt.Connect( hDBID:=1 ); IF FB_SQLDatabaseEvt.bError THEN iErrorCounet:=iErrorCounet+1; iStep:=9991; END_IF IF FB_SQLDatabaseEvt.bConnected THEN iStep:=20; END_IF 20: FB_SQLDatabaseEvt.CreateCmd( pSQLCommand:=ADR(FB_SQLCommandEvt) ); IF FB_SQLDatabaseEvt.bError THEN iErrorCounet:=iErrorCounet+1; iStep:=9992; END_IF TON_Process(IN:=NOT FB_SQLDatabaseEvt.bBusy AND NOT FB_SQLDatabaseEvt.bError); IF TON_Process.Q THEN TON_Process(IN:=FALSE); iStep:=30; iCounter:=iCounter+1; IF iCounter>100 THEN iCounter:=1; END_IF END_IF 30: SQL_Commands[1]:=FC_SQL_UpdateCommands(iCounter,’$’Application/GVL_FactoryIO/qCounter1$’;’); SQL_Commands[2]:=FC_SQL_UpdateCommands(iCounter*10+1,’$’Application/GVL_FactoryIO/qCounter2$’;’); SQL_Commands[3]:=FC_SQL_UpdateCommands(iCounter*10+2,’$’Application/GVL_FactoryIO/qCounter3$’;’); SQL_Commands[4]:=FC_SQL_UpdateCommands(iCounter*10+3,’$’Application/GVL_FactoryIO/iFactoryIORunning$’;’); iStep:=40; isubstep:=0; i:=1; 40: IF FB_SQLCommandEvt.Execute(pSQLCmd:=ADR(SQL_Commands[i]),cbSQLCmd:=SIZEOF(SQL_Commands[i])) THEN IF FB_SQLCommandEvt.bError THEN iErrorCounet:=iErrorCounet+1; iStep:=9994; END_IF END_IF; IF FB_SQLCommandEvt.bBusy THEN isubstep:=1; END_IF IF NOT FB_SQLCommandEvt.bBusy AND isubstep=1 THEN iStep:=45; isubstep:=0; END_IF 45: i:=i+1; IF i >= 5 THEN iStep:=50; isubstep:=0; ELSE iStep:=40; END_IF 50: sSelectDataCommand:=’SELECT * FROM “tags” LIMIT 1000;’; IF FB_SQLCommandEvt.ExecuteDataReturn(pSQLCmd:=ADR(sSelectDataCommand),cbSQLCmd:=SIZEOF(sSelectDataCommand),pSQLDBResult:=ADR(FB_SQLResultEvt)) THEN IF FB_SQLCommandEvt.bError THEN iErrorCounet:=iErrorCounet+1; END_IF IF FB_SQLResultEvt.nDataCount >0 AND NOT FB_SQLCommandEvt.bBusy THEN iStep:=60; END_IF END_IF 60: IF FB_SQLResultEvt.Read( nStartIndex:=0 ,nRecordCount:=4 ,pData:=ADR(tags) ,cbData:=SIZEOF(tags) ,bWithVerifying:=TRUE ,bDataRelease:=TRUE ) THEN IF FB_SQLResultEvt.bError THEN iErrorCounet:=iErrorCounet+1; iStep:=9995; END_IF IF FB_SQLResultEvt.nDataCount=0 THEN iStep:=70; END_IF; END_IF; 70: TON_Process(IN:=TRUE,PT:=T#1S); IF TON_Process.Q THEN TON_Process(IN:=FALSE); iStep:=20; END_IF END_CASE |
Result
Done!PostgreSQL DBから最新のデータを取得しPLC変数に転送できました。
VSCODEのPostgreSQL Plug-inからDBの最新データを取得します。
SELECT * FROM “tags” LIMIT 1000; |
Done!TwinCATがUpdateしたデータも確認できましたね。
Download
下記のLinkから記事のプロジェクトをDownloadしてください。
https://github.com/soup01Threes/TwinCAT3/blob/main/TwinCATestWithSQL.tnzip