Beckhoff#TwinCAT ADSデバイスとPythonで通信する

ADSはなに?

ADS=Automation Device Specificationのことで、独立したでデバイスやField-bus Interfaceを定義し、アクセスの方法を管理します。そのADS Interfaceは他のADSデバイスとCommunicationすることも可能です。

TwinCATシステムでは各モジュール(TwnCAT PLC・HMIなど)を独自のデバイスとして扱うことできます。Taskことにソフトウェアモジュールがあり、それはServerかClientですね。

Servers

システム内でServersはデバイスのような働き(実物のハードウェアみたいに)、なのでSoftware上でそのような仮想デバイスとIntefaceで通信することが可能ですね。

Clients

プログラム内でServersにリクエストをするのはClientsになります。

それらのObject間でADS Interface経由し”Message router”使用して通信します。それらのMessageはTCP/IP 接続で管理されます。その”Message router”はすべてのTwinCAT デイバスにも存在しており、Server・Client間でコマンドやデータやStatusをやり取りすることが実現します。

ADS device identification

すべてのADSデバイスにも自分独自の2つidentifiersがあります。

  • PortNr
  • NetId

AMS-Ports

PortはClient アプリケーションが初めてADS デバイスをアクセスするときに振り分けられた数字です。ADSデバイスは自分の番号などすでに決めています。

例えば初めてアプリケーションLoginするよく見えるのMessage:

Port851=TC3 PLC Runtime System 1です。

AMS NetId

ネットワーク上のTwinCATデバイスはAMS NetIDに認識されます。そのAMS NetIdは8個のBytes数字に構成されています。最初の4つの数字は自由選択でき、最後の2つ(.1.1)の場合が多くはSubnet Maskとして使用しています。AMS NetIdは必ずかぶらないように注意してください。

NetIdの確認方法1

TwinCAT XAEを起動し、SYSTEM>Routesをクリックします。

NetId ManagementのところにLocal NetIdがあります。

NetIdの確認方法2

Task BAR>Router>Change AMS NetIdします。

同じくAMS Net Idが表示されます。

インストール

今回インストールに関しては2つに分けれています。Anacondaをインストールする部分とpyadsをインストールするところです。別にAnacondaではなく普通のTerminalでPythonをプログラムしたり、VSCodeでやったり、Jupyter notebookでやったりでも構いません。自分にとってAnacondaは便利なのだけです。


Anaconda

まず下記のLinkをアクセスします、ExeをDownloadします。

https://www.anaconda.com/products/individual

Next>します。

ライセンス同意します。

Just Meを選択し、Nextします。

Install Locationを選択し、Next>します。

Checkを外して、Installします。

しばらく待ちます…

終わったらNext>で進みます。

Next>します。

FinishでOK!

環境テスト

Anaconda Navigatorを起動します。

最初はBaseの環境しかありません。

右下でCreateをクリックし、新しい仮想環境を作成します。

仮想環境の名前やPythonのバージョン設定し、Createします。

もちろんTerminalからにも色々な操作できます。

Anaconda Promptを起動します。

以下のコマンドどんな環境存在しているかを一覧できます。

conda info -e

そして以下のコマンドで仮想環境を起動します。

activate env_pyads

pyads 

次はpyadsのインストールですね。

公式LINK:

https://pyads.readthedocs.io/en/latest/index.html

このpyadsはPython上でTwinCAT デバイスと通信することが可能です。そのpyadsはWindows上ではTcAdsDll.dll を使用し、Linuxならadslib.soを使用しています。Linuxの場合はpyads パッケージ含まれています。

以下のコマンドでInstallします。

pip install pyads

環境テスト

パッケージをちゃんインストールできるのかをCheckします。

import pyads

プログラム

パッケージ内の関数たくさんあり全部説明が無理ありますので、使えそうなものを一部拾って説明します。主にDevicesの接続・読み書き・あと変数が変化あったときのお知らせですね。

Connect

最初はTwinCAT PLCと接続し現在のSystem状態を取ってみましょう。

Code

import pyads
from ctypes import sizeof

ads_net_id=’172.16.52.5.1.1′
plc=pyads.Connection(ads_net_id,pyads.PORT_TC3PLC1)

print(‘Connecting to TwinCAT PLC..’)
plc.open()
print(‘Current connection status:’,plc.is_open)
print(‘Current Status:’,plc.read_state())

print(‘Closing the Connections..’)
plc.close()
print(‘Current Status:’,plc.is_open)

Result

Connecting to TwinCAT PLC..
Current connection status: True
Current Status: (5, 0)
Closing the Connections..
Current Status: False

pyads.Connection

pyads.Connectionでは必要なパラメタはNetIDとPortです。確認する方法も先程で説明しました。それでConnectionを作ります。


plc.open()

TwinCAT message routerと接続しますね。

plc.is_open

True=いまConnectionがOKです。

plc.read_state()

現在のADS デバイス状態を読み出します。

戻り値は(int,int)で(adsState,deviceState)ですね。

先のExampleだとCurrent Status: (5, 0)はadsState=5,deviceState=0になります。

こちらはADS Return Code=0、つまりERR_NOERRORです。


adsState=5、つまりいまRUNしてる状態ですね。

Read Devices

Code

次はTwinCAT PLCの変数を読み込んでみましょう。

import pyads
from ctypes import sizeof

ads_net_id=’172.16.52.5.1.1′
plc=pyads.Connection(ads_net_id,pyads.PORT_TC3PLC1)

print(‘Connecting to TwinCAT PLC..’)
plc.open()
print(‘Current connection status:’,plc.is_open)
print(‘Current Status:’,plc.read_state())

print(‘Reading Devices..’)
var=plc.read_by_name(data_name=’GVL.i32′,plc_datatype=pyads.PLCTYPE_DINT)
print(‘GVL.i32 is’,var)

print(‘Closing the Connections..’)
plc.close()
print(‘Current Status:’,plc.is_open)

Result

Connecting to TwinCAT PLC..
Current connection status: True
Current Status: (5, 0)
Reading Devices..
GVL.i32 is 319
Closing the Connections..
Current Status: False

read_by_name

その関数を使って変数値を読み込みます。

基本はdata_nameだけでOKです。data_nameは変数名のことですね

plc_datatypeは戻り値のデータタイプをCheckするかどうかですね。Noneならなにもしません。

Read Devices As List

次はまとめて変数を読み込む方法を紹介します。

code

import pyads
from ctypes import sizeof

ads_net_id=’172.16.52.5.1.1′
plc=pyads.Connection(ads_net_id,pyads.PORT_TC3PLC1)

print(‘Connecting to TwinCAT PLC..’)
plc.open()
print(‘Current connection status:’,plc.is_open)
print(‘Current Status:’,plc.read_state())

print(‘Reading Devices List..’)
varList=[‘GVL.i32′,’GVL.var1′,’GVL.var2′,’GVL.var3’]
vardata=plc.read_list_by_name(varList)
for k,v in vardata.items():
    print(k,’:’,v)

print(‘Closing the Connections..’)
plc.close()
print(‘Current Status:’,plc.is_open)

Result

Connecting to TwinCAT PLC..
Current connection status: True
Current Status: (5, 0)
Reading Devices List..
GVL.i32 : 319
GVL.var1 : 1
GVL.var2 : 2
GVL.var3 : 3
Closing the Connections..
Current Status: False

read_list_by_name

やってることはread_by_nameとあまりわかりませんが、data_namesは文字列の配列に変わってたことですね。

そのListに読み込みたい変数を入れます。

このように:

varList=[‘GVL.i32′,’GVL.var1′,’GVL.var2′,’GVL.var3’]

そして戻り値は辞書になります。

Write Devices

変数を書き込むにも読み込むとあまり変わりません。

Code

import pyads
from ctypes import sizeof

ads_net_id=’172.16.52.5.1.1′
plc=pyads.Connection(ads_net_id,pyads.PORT_TC3PLC1)

print(‘Connecting to TwinCAT PLC..’)
plc.open()
print(‘Current connection status:’,plc.is_open)
print(‘Current Status:’,plc.read_state())

plc.write_by_name(data_name=’GVL.i32′,value=100,plc_datatype=pyads.PLCTYPE_DINT)

print(‘Reading Devices List..’)
varList=[‘GVL.i32′,’GVL.var1′,’GVL.var2′,’GVL.var3’]
vardata=plc.read_list_by_name(varList)
for k,v in vardata.items():
    print(k,’:’,v)

print(‘Closing the Connections..’)
plc.close()
print(‘Current Status:’,plc.is_open)

Result

Connecting to TwinCAT PLC..
Current connection status: True
Current Status: (5, 0)
Reading Devices List..
GVL.i32 : 100
GVL.var1 : 1
GVL.var2 : 2
GVL.var3 : 3
Closing the Connections..
Current Status: False

write_by_name

value値は書き込みたい値になりますね。

Write Devices as list

次はまとめて変数を書き込みましょう。

Code

import pyads
from ctypes import sizeof

ads_net_id=’172.16.52.5.1.1′
plc=pyads.Connection(ads_net_id,pyads.PORT_TC3PLC1)

print(‘Connecting to TwinCAT PLC..’)
plc.open()
print(‘Current connection status:’,plc.is_open)
print(‘Current Status:’,plc.read_state())

varList=[‘GVL.i32′,’GVL.var1′,’GVL.var2′,’GVL.var3’]
varWriteList={
    ‘GVL.i32’:20
    ,’GVL.var1′:99
    ,’GVL.var2′:32
    ,’GVL.var3′:88
}

plc.write_list_by_name(data_names_and_values=varWriteList)

print(‘Reading Devices List..’)
varList=[‘GVL.i32′,’GVL.var1′,’GVL.var2′,’GVL.var3’]
vardata=plc.read_list_by_name(varList)
for k,v in vardata.items():
    print(k,’:’,v)

print(‘Closing the Connections..’)
plc.close()
print(‘Current Status:’,plc.is_open)


Result

Connecting to TwinCAT PLC..
Current connection status: True
Current Status: (5, 0)
Reading Devices List..
GVL.i32 : 20
GVL.var1 : 99
GVL.var2 : 32
GVL.var3 : 88
Closing the Connections..
Current Status: False

write_list_by_name


data_names_and_valuesは辞書タイプだけは注意しましょう。

Noifications

最後はnotificationsです。ADSはnotificationsをSupportします。つまりCallback関数を渡すことができ、変数値は変化してるときに実行することが可能になります。

code

import pyads
from ctypes import sizeof

ads_net_id=’172.16.52.5.1.1′
plc=pyads.Connection(ads_net_id,pyads.PORT_TC3PLC1)

print(‘Connecting to TwinCAT PLC..’)
plc.open()
print(‘Current connection status:’,plc.is_open)
print(‘Current Status:’,plc.read_state())

@plc.notification(pyads.PLCTYPE_DINT)
def callback(handle, name, timestamp, value):
    print(handle, name, timestamp, value)

attr = pyads.NotificationAttrib(sizeof(pyads.PLCTYPE_DINT))
handles = plc.add_device_notification(‘GVL.i32’, attr, callback)

#do some things

plc.del_device_notification(*handles)
plc.close()

Result

Connecting to TwinCAT PLC..
Current connection status: True
Current Status: (5, 0)
handle: 26
name: GVL.i32
timestamp: 2021-10-02 00:41:39.946000
value: 555

add_device_notification

Device notificationを追加します。必要なのは変数名・NotificationAttrib・CallBack関数です。

NotificationAttrib

このNotificationの設定ですね。

Lengthさえ入れればOKです。

del_device_notification

最後はNotification使わなくなったら削除する関数です。

はーい、お疲れ様です。

もしなにか質問あれば、メール・コメント・Twitterなどでもどうぞ!

Twitterのご相談:@3threes2

メールのご相談:soup01threes*gmail.com (*を@に)

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

シェアする

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

フォローする

コメント

  1. グエン トゥ より:

    ADS通信の説明ありがとうございます。
    質問ですが
    ADS通信でSlaveのState Machine(例: OP->Init)変更方法ありますか。

    • gomamenotes より:

      お世話になります。

      BeckhoffのTwinCATライブラリにはTc2_EtherCATがあり、中にFB_EcReqSlaveStateのFBを使用すればEtherCAT Slaveの状態を変更できます。
      (もちろんSlaveが100%受け付けるかは別です。)