今回の記事ではPyPlcnextRscのAPIを使用し、AXC F 2152 CPUの変数(単体変数・配列・構造体)を読み書きする操作をサンプルコード付きで説明します。よろしくおねがいします。このAPIは非常に便利なので、よかったら試してみてください。
Reference Link
https://pyplcnextrsc.readthedocs.io/en/latest/index.html
The Access Path
PyPlcnextRscを使用しPLCNEXTの変数を読み取りのに、変数のAccess Pathを明確にする必要があります。例えば今回のExampleではまずPLCnext(2)をクリックします。
自分のCyclic TaskにはOB11といLocal Programがあります。
Component nameのところにArp.Plc.Eclrという名称があり、それはAccess Pathの一部になります。
Implementation-1 Read Variable
Implementation-1ではPLCNEXT Runtime内にあるいくつかの変数をリクエスト分けて読み取ってみます。ExampleにはBOOL TypeのMyBoolDatat・16Bitの整数MyInt・文字列 TypeのMyStringがTargetです。
Script Example
こちらはScriptです。
MyBoolDataのアクセスPathは:Arp.Plc.EclrOB11/MyBoolData、
MyStringのアクセスPathは:Arp.Plc.EclrOB11/OB11.MyString、
MyIntのアクセスPathは:Arp.Plc.EclrOB11/OB11.MyInt、になります。
そしてReadSingle() Methodを使用し変数の現在値を読み取ります。
from PyPlcnextRsc import Device, ConsoleSupplierExample , RscVariant from PyPlcnextRsc.Arp.Device.Interface.Services import IDeviceInfoService,IDeviceStatusService from PyPlcnextRsc.Arp.Plc.Gds.Services import IDataAccessService,WriteItem from PyPlcnextRsc.common.tag_type import IecType PLCNEXTIPADDRESS=’127.0.0.1′ PLCNEXTBASICPATH=’Arp.Plc.Eclr/’ with Device(PLCNEXTIPADDRESS, secureInfoSupplier=ConsoleSupplierExample) as device: device_info_service = IDeviceInfoService(device) device_status_service = IDeviceStatusService(device) info_items = [ “General.ArticleName”, “General.ArticleNumber”, “General.SerialNumber”, “General.Firmware.Version”, “General.Hardware.Version”, “Interfaces.Ethernet.1.0.Mac” ] status_items = [ “Status.Cpu.0.Load.Percent”, “Status.Memory.Usage.Percent”, “Status.ProgramMemoryIEC.Usage.Percent”, “Status.DataMemoryIEC.Usage.Percent”, “Status.Board.Temperature.Centigrade”, “Status.Board.Temperature.Centigrade”, “Status.Board.Humidity” ] for identifier, result in zip(info_items, device_info_service.GetItems(info_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) for identifier, result in zip(status_items, device_status_service.GetItems(status_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) data_access_service=IDataAccessService(device) Bool_port_name=PLCNEXTBASICPATH+”OB11.MyBoolData” String_port_name=PLCNEXTBASICPATH+”OB11.MyString” int_port_name=PLCNEXTBASICPATH+”OB11.MyInt” value=data_access_service.ReadSingle(Bool_port_name).Value.GetValue() print(value) print(data_access_service.ReadSingle(String_port_name).Value.GetValue()) print(data_access_service.ReadSingle(int_port_name).Value.GetValue()) data_access_service.WriteSingle(WriteItem(Bool_port_name,RscVariant.of(True))) data_access_service.WriteSingle(WriteItem(String_port_name,RscVariant.of(‘abcdef’))) |
Result
Done!変数の現在値が取りました。
Implementation-2 Try to write other variable
次はWriteItem() Methodを使用しInt変数を書き込んでみます。
data_access_service.WriteSingle(WriteItem(int_port_name,RscVariant.of(1234))) |
ですが、エラーがReturnされています。
Traceback (most recent call last): File “/opt/plcnext/RoboDKTesting/myapps.py”, line 58, in <module> data_access_service.WriteSingle(WriteItem(int_port_name,RscVariant.of(1234))) File “/opt/plcnext/.local/lib/python3.10/site-packages/PyPlcnextRsc/common/objects/rsc_variant.py”, line 74, in of raise InvalidOperationException(“Use __init__ to create RscVariant with its’ RscType instead !”) PyPlcnextRsc.common.exceptions.InvalidOperationException: Use __init__ to create RscVariant with its’ RscType instead ! |
Why?
こちらのLINKからWriteItem() MethodのSource Codeが見れます↓
中にBool・Strucutre・String以外にすべてのData TyoeもExceptionになります。どうやら書き込みのTargetに明確なData Typeを指定する必要があるようです。例えば整数12を書き込むだけではその12は16Bit?32Bit?Sign?Unsignなどが曖昧なので、受け付けません。
Implementation-3 Array Operation
先程のImplemenationでは整数を書き込めなかったんですね。ですが、配列のINTなら問題ありません。次はそのMethodなどを紹介します。
Create Array
配列のData Typeを作成し、Runtime内でLocal変数を宣言します。
Script Example
今回はDataTypeStore.fromString()関数を使います。()のパラメータはアクセスしたい変数のデータタイプをそのままPLCNEXTからCOPYしてもいいし、もう一つテキストから読む関数もあり、あの関数を使っても構いません。
TypeStore = DataTypeStore.fromString( “”” TYPE MyIntArray : ARRAY[0..10] OF INT; END_TYPE “”” ) |
TypeStore.NewSchemaInstance()から変数のInstanceを宣言します。
MyIntArrayData = TypeStore.NewSchemaInstance(“MyIntArray”) |
最後は配列の読み書きを行います。
read_item = data_access_service.Read((MyArray_port_name,))[0] print(read_item) print(read_item.Value) data_access_service.Write((WriteItem(MyArray_port_name, RscVariant.of(MyIntArrayData)),)) |
こちらはScriptの全体です。
from PyPlcnextRsc import Device, ConsoleSupplierExample , RscVariant from PyPlcnextRsc.Arp.Device.Interface.Services import IDeviceInfoService,IDeviceStatusService from PyPlcnextRsc.Arp.Plc.Gds.Services import IDataAccessService,WriteItem from PyPlcnextRsc.common.tag_type import IecType from PyPlcnextRsc.tools import DataTypeStore PLCNEXTIPADDRESS=’127.0.0.1′ PLCNEXTBASICPATH=’Arp.Plc.Eclr/’ TypeStore = DataTypeStore.fromString( “”” TYPE MyIntArray : ARRAY[0..10] OF INT; END_TYPE “”” ) with Device(PLCNEXTIPADDRESS, secureInfoSupplier=ConsoleSupplierExample) as device: device_info_service = IDeviceInfoService(device) device_status_service = IDeviceStatusService(device) info_items = [ “General.ArticleName”, “General.ArticleNumber”, “General.SerialNumber”, “General.Firmware.Version”, “General.Hardware.Version”, “Interfaces.Ethernet.1.0.Mac” ] status_items = [ “Status.Cpu.0.Load.Percent”, “Status.Memory.Usage.Percent”, “Status.ProgramMemoryIEC.Usage.Percent”, “Status.DataMemoryIEC.Usage.Percent”, “Status.Board.Temperature.Centigrade”, “Status.Board.Temperature.Centigrade”, “Status.Board.Humidity” ] for identifier, result in zip(info_items, device_info_service.GetItems(info_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) for identifier, result in zip(status_items, device_status_service.GetItems(status_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) #Create Data access services data_access_service=IDataAccessService(device) #Create Port Bool_port_name=PLCNEXTBASICPATH+”OB11.MyBoolData” String_port_name=PLCNEXTBASICPATH+”OB11.MyString” int_port_name=PLCNEXTBASICPATH+”OB11.MyInt” MyArray_port_name=PLCNEXTBASICPATH+”OB11.MyIntArray1″ #Print the values print(data_access_service.ReadSingle(Bool_port_name).Value.GetValue()) print(data_access_service.ReadSingle(String_port_name).Value.GetValue()) print(data_access_service.ReadSingle(int_port_name).Value.GetValue()) data_access_service.WriteSingle(WriteItem(Bool_port_name,RscVariant.of(True))) data_access_service.WriteSingle(WriteItem(String_port_name,RscVariant.of(‘abcdef’))) #Array operation MyIntArrayData = TypeStore.NewSchemaInstance(“MyIntArray”) MyIntArrayData[:] = [i * 2 for i in range(11)] read_item = data_access_service.Read((MyArray_port_name,))[0] print(read_item) print(read_item.Value) data_access_service.Write((WriteItem(MyArray_port_name, RscVariant.of(MyIntArrayData)),)) |
Result
Terminal上でScriptを実行すると、データはエラーなく読み書きできました。
PLCNEXTからも結果の確認ができます。
Implementation-4 Structure
次は少し構造体にアクセスしてみます。PLCNEXTのプロジェクトに構造体を宣言してください。今回の例ではMyStructData_1で、INT・BOOL・Real・LReal Typeの要素が含まれています。
Create Structure
PLCNEXTの中にSTRUCTのデータタイプを定義し、Runtime内でLocal変数を宣言します。
Script Example
DataTypeStore.fromString()はPLCNEXTで定義した構造体をそのまま貼り付ければよです。
TypeStore = DataTypeStore.fromString( “”” TYPE MyIntArray : ARRAY[0..10] OF INT; MyStructData_1 : STRUCT Field1_INT : INT; Field2_BOOL : BOOL; Field3_Real : REAL; Field4_LReal :LREAL; END_STRUCT END_TYPE “”” ) |
次は変数のInstanceを宣言します。
MyTestStruct_port_name=PLCNEXTBASICPATH+”OB11.MyTestStruct” |
data_access_service.Read()とread_struct_item.Valueから変数の現在値を取得します。
# MyTestStructData = TypeStore.NewSchemaInstance(“MyStructData_1”) read_struct_item = data_access_service.Read((MyTestStruct_port_name,))[0] print(‘———————‘) print(read_struct_item.Value) |
こちらはScriptの全体です。
from PyPlcnextRsc import Device, ConsoleSupplierExample , RscVariant from PyPlcnextRsc.Arp.Device.Interface.Services import IDeviceInfoService,IDeviceStatusService from PyPlcnextRsc.Arp.Plc.Gds.Services import IDataAccessService,WriteItem from PyPlcnextRsc.common.tag_type import IecType from PyPlcnextRsc.tools import DataTypeStore IPADDRESS=’192.168.1.194′ PORT=20500 ROBOTNAME=’Fanuc_Robot’ PLCNEXTIPADDRESS=’127.0.0.1′ PLCNEXTBASICPATH=’Arp.Plc.Eclr/’ TypeStore = DataTypeStore.fromString( “”” TYPE MyIntArray : ARRAY[0..10] OF INT; MyStructData_1 : STRUCT Field1_INT : INT; Field2_BOOL : BOOL; Field3_Real : REAL; Field4_LReal :LREAL; END_STRUCT END_TYPE “”” ) with Device(PLCNEXTIPADDRESS, secureInfoSupplier=ConsoleSupplierExample) as device: device_info_service = IDeviceInfoService(device) device_status_service = IDeviceStatusService(device) info_items = [ “General.ArticleName”, “General.ArticleNumber”, “General.SerialNumber”, “General.Firmware.Version”, “General.Hardware.Version”, “Interfaces.Ethernet.1.0.Mac” ] status_items = [ “Status.Cpu.0.Load.Percent”, “Status.Memory.Usage.Percent”, “Status.ProgramMemoryIEC.Usage.Percent”, “Status.DataMemoryIEC.Usage.Percent”, “Status.Board.Temperature.Centigrade”, “Status.Board.Temperature.Centigrade”, “Status.Board.Humidity” ] for identifier, result in zip(info_items, device_info_service.GetItems(info_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) for identifier, result in zip(status_items, device_status_service.GetItems(status_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) #Create Data access services data_access_service=IDataAccessService(device) #Create Port Bool_port_name=PLCNEXTBASICPATH+”OB11.MyBoolData” String_port_name=PLCNEXTBASICPATH+”OB11.MyString” int_port_name=PLCNEXTBASICPATH+”OB11.MyInt” MyArray_port_name=PLCNEXTBASICPATH+”OB11.MyIntArray1″ MyTestStruct_port_name=PLCNEXTBASICPATH+”OB11.MyTestStruct” #Print the values print(data_access_service.ReadSingle(Bool_port_name).Value.GetValue()) print(data_access_service.ReadSingle(String_port_name).Value.GetValue()) print(data_access_service.ReadSingle(int_port_name).Value.GetValue()) data_access_service.WriteSingle(WriteItem(Bool_port_name,RscVariant.of(True))) data_access_service.WriteSingle(WriteItem(String_port_name,RscVariant.of(‘abcdef’))) #Array operation MyIntArrayData = TypeStore.NewSchemaInstance(“MyIntArray”) MyIntArrayData[:] = [i * 2 for i in range(11)] read_item = data_access_service.Read((MyArray_port_name,))[0] print(read_item) print(read_item.Value) data_access_service.Write((WriteItem(MyArray_port_name, RscVariant.of(MyIntArrayData)),)) # MyTestStructData = TypeStore.NewSchemaInstance(“MyStructData_1”) read_struct_item = data_access_service.Read((MyTestStruct_port_name,))[0] print(‘———————‘) print(read_struct_item.Value) |
Result
PLCNEXTからも結果の確認ができます。
Terminal上でScriptを実行すると、データはエラーなく読みました。
Implementation-5 Write the structure
次は構造体の変数に現在値を書き込みます。
# MyTestStructData = TypeStore.NewSchemaInstance(“MyStructData_1”) MyTestStructData.Field1_INT=459 MyTestStructData.Field2_BOOL=True MyTestStructData.Field3_Real=3.14 MyTestStructData.Field4_LReal=991.41155 read_struct_item = data_access_service.Read((MyTestStruct_port_name,))[0] print(‘———————‘) print(read_struct_item.Value) |
Script Example
構造体変数のInstanceにPLCNEXTと定義した変数名とデータタイプをあわせて適当な値を書き込みます。
# MyTestStructData = TypeStore.NewSchemaInstance(“MyStructData_1”) MyTestStructData.Field1_INT=459 MyTestStructData.Field2_BOOL=True MyTestStructData.Field3_Real=3.14 MyTestStructData.Field4_LReal=991.41155 |
data_access_service.Write()を使用し書き込みのリクエストを送信します。
data_access_service.Write((WriteItem(MyTestStruct_port_name, RscVariant.of(MyTestStructData)),)) |
こちらはScriptの全体です。
from PyPlcnextRsc import Device, ConsoleSupplierExample , RscVariant from PyPlcnextRsc.Arp.Device.Interface.Services import IDeviceInfoService,IDeviceStatusService from PyPlcnextRsc.Arp.Plc.Gds.Services import IDataAccessService,WriteItem from PyPlcnextRsc.common.tag_type import IecType from PyPlcnextRsc.tools import DataTypeStore PLCNEXTIPADDRESS=’127.0.0.1′ PLCNEXTBASICPATH=’Arp.Plc.Eclr/’ TypeStore = DataTypeStore.fromString( “”” TYPE MyIntArray : ARRAY[0..10] OF INT; MyStructData_1 : STRUCT Field1_INT : INT; Field2_BOOL : BOOL; Field3_Real : REAL; Field4_LReal :LREAL; END_STRUCT END_TYPE “”” ) with Device(PLCNEXTIPADDRESS, secureInfoSupplier=ConsoleSupplierExample) as device: device_info_service = IDeviceInfoService(device) device_status_service = IDeviceStatusService(device) info_items = [ “General.ArticleName”, “General.ArticleNumber”, “General.SerialNumber”, “General.Firmware.Version”, “General.Hardware.Version”, “Interfaces.Ethernet.1.0.Mac” ] status_items = [ “Status.Cpu.0.Load.Percent”, “Status.Memory.Usage.Percent”, “Status.ProgramMemoryIEC.Usage.Percent”, “Status.DataMemoryIEC.Usage.Percent”, “Status.Board.Temperature.Centigrade”, “Status.Board.Temperature.Centigrade”, “Status.Board.Humidity” ] for identifier, result in zip(info_items, device_info_service.GetItems(info_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) for identifier, result in zip(status_items, device_status_service.GetItems(status_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) #Create Data access services data_access_service=IDataAccessService(device) #Create Port Bool_port_name=PLCNEXTBASICPATH+”OB11.MyBoolData” String_port_name=PLCNEXTBASICPATH+”OB11.MyString” int_port_name=PLCNEXTBASICPATH+”OB11.MyInt” MyArray_port_name=PLCNEXTBASICPATH+”OB11.MyIntArray1″ MyTestStruct_port_name=PLCNEXTBASICPATH+”OB11.MyTestStruct” #Print the values print(data_access_service.ReadSingle(Bool_port_name).Value.GetValue()) print(data_access_service.ReadSingle(String_port_name).Value.GetValue()) print(data_access_service.ReadSingle(int_port_name).Value.GetValue()) data_access_service.WriteSingle(WriteItem(Bool_port_name,RscVariant.of(True))) data_access_service.WriteSingle(WriteItem(String_port_name,RscVariant.of(‘abcdef’))) #Array operation MyIntArrayData = TypeStore.NewSchemaInstance(“MyIntArray”) MyIntArrayData[:] = [i * 2 for i in range(11)] read_item = data_access_service.Read((MyArray_port_name,))[0] print(read_item) print(read_item.Value) data_access_service.Write((WriteItem(MyArray_port_name, RscVariant.of(MyIntArrayData)),)) # MyTestStructData = TypeStore.NewSchemaInstance(“MyStructData_1”) MyTestStructData.Field1_INT=459 MyTestStructData.Field2_BOOL=True MyTestStructData.Field3_Real=3.14 MyTestStructData.Field4_LReal=991.41155 read_struct_item = data_access_service.Read((MyTestStruct_port_name,))[0] print(‘———————‘) print(read_struct_item.Value) data_access_service.Write((WriteItem(MyTestStruct_port_name, RscVariant.of(MyTestStructData)),)) |
Result
Terminal上でScriptを実行すると、データはエラーなく読み書きできました。
Implementation-6 Encode the RsvVariant to Python object
最後はRsvVariantをPython Scriptで使用できるObjectに変換します。
Script Example
こちらのScriptからRsvVariantをPython Objectに変換します。
complexStruct_Received = TypeStore.ReceiveAsSchemaInstance(“MyStructData_1”, read_struct_item.Value) print(“Field1_INT is:”+str(complexStruct_Received.Field1_INT)) print(“Field2_BOOL is “+str(complexStruct_Received.Field2_BOOL)) print(“Field3_Real is “+str(complexStruct_Received.Field3_Real)) print(“Field4_LReal is “+str(complexStruct_Received.Field4_LReal)) |
こちらはScriptの全体です。
from PyPlcnextRsc import Device, ConsoleSupplierExample , RscVariant from PyPlcnextRsc.Arp.Device.Interface.Services import IDeviceInfoService,IDeviceStatusService from PyPlcnextRsc.Arp.Plc.Gds.Services import IDataAccessService,WriteItem from PyPlcnextRsc.common.tag_type import IecType from PyPlcnextRsc.tools import DataTypeStore PLCNEXTIPADDRESS=’127.0.0.1′ PLCNEXTBASICPATH=’Arp.Plc.Eclr/’ TypeStore = DataTypeStore.fromString( “”” TYPE MyIntArray : ARRAY[0..10] OF INT; MyStructData_1 : STRUCT Field1_INT : INT; Field2_BOOL : BOOL; Field3_Real : REAL; Field4_LReal :LREAL; END_STRUCT END_TYPE “”” ) with Device(PLCNEXTIPADDRESS, secureInfoSupplier=ConsoleSupplierExample) as device: device_info_service = IDeviceInfoService(device) device_status_service = IDeviceStatusService(device) info_items = [ “General.ArticleName”, “General.ArticleNumber”, “General.SerialNumber”, “General.Firmware.Version”, “General.Hardware.Version”, “Interfaces.Ethernet.1.0.Mac” ] status_items = [ “Status.Cpu.0.Load.Percent”, “Status.Memory.Usage.Percent”, “Status.ProgramMemoryIEC.Usage.Percent”, “Status.DataMemoryIEC.Usage.Percent”, “Status.Board.Temperature.Centigrade”, “Status.Board.Temperature.Centigrade”, “Status.Board.Humidity” ] for identifier, result in zip(info_items, device_info_service.GetItems(info_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) for identifier, result in zip(status_items, device_status_service.GetItems(status_items)): print(identifier.rjust(40) + ” : ” + str(result.GetValue())) #Create Data access services data_access_service=IDataAccessService(device) #Create Port Bool_port_name=PLCNEXTBASICPATH+”OB11.MyBoolData” String_port_name=PLCNEXTBASICPATH+”OB11.MyString” int_port_name=PLCNEXTBASICPATH+”OB11.MyInt” MyArray_port_name=PLCNEXTBASICPATH+”OB11.MyIntArray1″ MyTestStruct_port_name=PLCNEXTBASICPATH+”OB11.MyTestStruct” #Print the values print(data_access_service.ReadSingle(Bool_port_name).Value.GetValue()) print(data_access_service.ReadSingle(String_port_name).Value.GetValue()) print(data_access_service.ReadSingle(int_port_name).Value.GetValue()) data_access_service.WriteSingle(WriteItem(Bool_port_name,RscVariant.of(True))) data_access_service.WriteSingle(WriteItem(String_port_name,RscVariant.of(‘abcdef’))) #Array operation MyIntArrayData = TypeStore.NewSchemaInstance(“MyIntArray”) MyIntArrayData[:] = [i * 2 for i in range(11)] read_item = data_access_service.Read((MyArray_port_name,))[0] print(read_item) print(read_item.Value) data_access_service.Write((WriteItem(MyArray_port_name, RscVariant.of(MyIntArrayData)),)) # MyTestStructData = TypeStore.NewSchemaInstance(“MyStructData_1”) MyTestStructData.Field1_INT=459 MyTestStructData.Field2_BOOL=True MyTestStructData.Field3_Real=3.14 MyTestStructData.Field4_LReal=991.41155 read_struct_item = data_access_service.Read((MyTestStruct_port_name,))[0] print(‘———————‘) print(read_struct_item.Value) data_access_service.Write((WriteItem(MyTestStruct_port_name, RscVariant.of(MyTestStructData)),)) complexStruct_Received = TypeStore.ReceiveAsSchemaInstance(“MyStructData_1”, read_struct_item.Value) print(“Field1_INT is:”+str(complexStruct_Received.Field1_INT)) print(“Field2_BOOL is “+str(complexStruct_Received.Field2_BOOL)) print(“Field3_Real is “+str(complexStruct_Received.Field3_Real)) print(“Field4_LReal is “+str(complexStruct_Received.Field4_LReal)) |
Result
CPU内部変数の現在値がPLCNEXT Engineeringソフトから確認できます。
同じの値が読みましたね!