Presentation is loading. Please wait.

Presentation is loading. Please wait.

EPICS Integration of PLC based systems

Similar presentations


Presentation on theme: "EPICS Integration of PLC based systems"— Presentation transcript:

1 EPICS Integration of PLC based systems
Krisztián Löki ICS/Hardware & Integration Group

2 The “standard” approach
Send/Receive protocol via TCP/IP Fixed sized data blocks for each direction All PVs for each direction are bundled together Each PV has its own byte offset The PLC periodically sends its data block The IOC sends its data block only when changed The IOC and the PLC exchange data (process variables) over the network. For each direction (IOC to PLC and PLC to IOC), there is one fixed size data block that bundles all process variables for this direction. The process variables are identified by their bytes offset in the data block. The PLC must be set up to send its data periodically. Data blocks are always transferred completely. That means all process variables in that block are transferred, even if they have not changed since the last cycle. There is no way to write or read only a sub-set of process variables. Krisztián Löki, HW&I Group

3 Problems with the “standard” approach
“One-shot” PVs are not supported (out-of-the-box) Data block layout is not verified “One-shot” in the sense that it’s not the value that matters but the fact that the PV was written to. Typically these are commands. Because all PVs for the IOC -> PLC direction are bundled together, there is no way to distinguish a “resend” from a legitimate “rewrite”. There is no mechanism to make sure that the PLC and the IOC interpret the data block the same way. The PLC continuously sends its data block and if the expects more there might be a timeout. But if it expects less then during the next read it will happily continue with the rest of the data block and the beginning of the current one. Krisztián Löki, HW&I Group

4 Krisztián Löki, HW&I Group
The ESS approach Keeps the “standard” approach for the PLC -> IOC direction Defines data blocks (on the PLC side) as array of words Uses Modbus for the IOC -> PLC direction Keeps the data block/array approach Uses absolute addressing Sends individual values, not the whole data block The first 10 words are reserved Layout identifier (checksum) is placed here Heartbeat (counter) is placed here Having an array makes it easy to have generic functions that read/write those arrays. Modbus uses Function code 16; “Write Multiple Registers”, limited to at most 2 words at a time. Modbus driver was modified to enable writing single bits (coils) with function code 16 (it is now merged upstream). Layout identifier is a 32 bit number; can be a version number or a checksum. If the received identifier doesn’t match the local one the PLC discards the received data and the IOC puts the PVs into INVALID state. Heartbeat is a good way to have a constantly changing (in a deterministic way) value to make sure that everything works as expected. Krisztián Löki, HW&I Group

5 Krisztián Löki, HW&I Group
The ESS approach The IOC->PLC array is (logically) split in two Command part Parameter part Command part is zero-initialized after readout “One-shot” PVs Since Modbus only sends individual values and only when needed (changed or triggered) clearing the command part after processing is enough to make sure that commands are not interpreted more than once. There is no need to add any logic on the IOC side to clear for example a bo record Krisztián Löki, HW&I Group

6 A problem still remains…
The layout of the data blocks Has to be agreed on between the PLC programmer and the integrator Offsets have to be correct Making changes is painful Krisztián Löki, HW&I Group

7 Automate integration (the fundamentals)
Determine controls relationships Abstract similar devices into device types Define device type interfaces Status variables Command variables Parameter variables Just walk the “controls tree” Determine what devices the PLC controls (or monitors) directly or indirectly (the PLC controls a special purpose controller that in turn controls other devices). Devices similar in the sense that they expose the same interface to EPICS. Defining the interface is basically just listing all the variables, their type, description, string representation if applicable. No need to (actually there is no way to) specify the offset in the date block / position in the array. Visiting every node of the controls tree and looking at the attached interfaces the PLC <-> IOC interface can be determined Krisztián Löki, HW&I Group

8 Automate integration (on the PLC side)
Every device has its own word array Starts at word boundary of the main array Enables the concatenation of device arrays to build the main array Enables easy decomposition of the main array into individual device arrays Every device has its own instance data block containing the arrays and the individual variables Starting at word boundary greatly simplifies things; makes it easy to generate and use the same offsets (on EPICS side) and serializer/deserializer (on the PLC side). If the interface of the device type is verified to work then it is enough to verify that every device of this type has the correct base offset in the main array. The PLC programmer can reference these “interface” variables by their name and don’t have to worry about where they are defined in the array. Krisztián Löki, HW&I Group

9 Krisztián Löki, HW&I Group
PLC Factory A tool to generate the EPICS database PLC code Siemens SCL Beckhoff TwinCat 3 IOC startup script much more (via Python interface) Based on the “Controls and Configuration DataBase” (CCDB) it generates everything. CCDB has all the device types and the associated interfaces, all the devices in the system, has the controls relationships specified. IOC startup script contains the length of the PLC->IOC data block, the endiannes of the PLC (Siemens is BigEndian, Beckhoff is LittleEndian) Metadata can be added to the interface; for example a table defining messages for error codes. This information can be used to generate a CS-Studio script to display the message along with the code. Krisztián Löki, HW&I Group

10 Krisztián Löki, HW&I Group
Interface Definition define_status_block() add_digital("NTY-O-SX", PV_NAME="OpenR", PV_DESC="The valve is OPEN", PV_ONAM="Open") add_digital("NTY-C-SX", PV_NAME="ClosedR", PV_DESC="The valve is CLOSED", PV_ONAM="Closed") add_digital("NTY-O-SX-ST", PV_NAME="OpenValidR", PV_DESC="The OPEN signal reading is valid", PV_ONAM="Valid", PV_ZNAM="Invalid") add_digital("NTY-C-SX-ST", PV_NAME="ClosedValidR", PV_DESC="The CLOSED signal reading is valid", PV_ONAM="Valid", PV_ZNAM="Invalid") add_enum("MPSVac-NTY-ST", "BYTE", PV_NAME="StatR", PV_DESC="The status of the valve", PV_ZRST="Closed", PV_ONST="Open", PV_TWST="Error", PV_TWSV="MAJOR") add_digital("NTY-CC", PV_NAME="CableR", PV_DESC="The cable is connected", PV_ONAM="Connected", PV_ZNAM="Not connected") add_digital("NTY-CC-ST", PV_NAME="CableValidR", PV_DESC="Cable connected signal reading is valid", PV_ONAM="Valid", PV_ZNAM="Invalid") add_enum("MPSVac-NTY-CC-ST", "BYTE", PV_NAME="CableStatR", PV_DESC="The status of the cabling", PV_ZRST="Not connected", PV_ONST="Connected", PV_TWST="Error", PV_TWSV="MAJOR") add_digital("NTY-VBP", PV_NAME="VBPR", PV_DESC="Vacuum Beam Permit", PV_ONAM="Permitted", PV_ZNAM="Not permitted") add_digital("NTY-VBP-ST", PV_NAME="VBPValidR", PV_DESC="The VBP signal reading is valid", PV_ONAM="Valid", PV_ZNAM="Invalid") add_enum("MPSVac-NTY-VBP-ST", "BYTE", PV_NAME="VBPStatR", PV_DESC="The status of Vacuum Beam Permit", PV_ZRST="Not OK", PV_ONST="OK", PV_TWST="Error", PV_TWSV="MAJOR") add_digital("NTY-VBP-CC", PV_NAME="VBPCableR", PV_DESC="The VBP cable is connected", PV_ONAM="Connected", PV_ZNAM="Not connected") add_digital("NTY-VBP-CC-ST", PV_NAME="VBPCableValidR", PV_DESC="The VBP cable signal reading is valid", PV_ONAM="Valid", PV_ZNAM="Invalid") add_enum("MPSVac-NTY-VBP-CC-ST", "BYTE", PV_NAME="VBPCableStatR“, PV_DESC="The status of the VBP cabling", PV_ZRST="Not connected", PV_ONST="Connected", PV_TWST="Error", PV_TWSV="MAJOR") The syntax is the same as for a Python script; in fact it is interpreted line-by-line with Python’s eval() function but with a very restricted environment. define_status_block() / define_command_block() / define_parameter_block() digital is bi/bo in EPICS and bool on the PLC analog is ai/ao in EPICS but PLC type has to be specifed enum is mbbi/mbbo in EPICS but the same as an analog on the PLC The first parameter is the name of the variable on the PLC, the second parameter is the PLC type of the variable (for digital it is not allowed) PV_foo can be used to set specific fields of the EPICS record. If not specified PV_NAME is the same as the PLC name Krisztián Löki, HW&I Group

11 Krisztián Löki, HW&I Group
EPICS database #<<<--- add_digital("NTY-O-SX", PV_NAME="OpenR", PV_DESC="The valve is OPEN", PV_ONAM="Open") record(bi, "DTL-010:MPSVac-VVS-10000:OpenR") { field(SCAN, "I/O Intr") field(DTYP, "S7plc") field(INP, T=UINT16 B=0") field(DISS, "INVALID") field(DISV, "0") field(SDIS, "MPS-Vac:Ctrl-PLC-001:PLCHashCorrectR") field(DESC, "The valve is OPEN") field(ONAM, "Open") } #<<<--- add_digital("NTY-C-SX", PV_NAME="ClosedR", PV_DESC="The valve is CLOSED", PV_ONAM="Closed") record(bi, "DTL-010:MPSVac-VVS-10000:ClosedR") field(INP, T=UINT16 B=1") field(DESC, "The valve is CLOSED") field(ONAM, "Closed") Krisztián Löki, HW&I Group

12 Krisztián Löki, HW&I Group
Data blocks as Arrays //########## EPICS->PLC datablock ########## DATA_BLOCK "EPICSToPLC" { S7_Optimized_Access := 'FALSE' } VERSION : 0.1 STRUCT "Word" : Array[0..10] of Word; END_STRUCT; BEGIN END_DATA_BLOCK //########## PLC->EPICS datablock ########## DATA_BLOCK "PLCToEPICS" NON_RETAIN "Word" : Array[0..80] of Word; These are the global data blocks. PLCToEPICS is sent to the IOC periodically, EPICSToPLC is written to by Modbus Krisztián Löki, HW&I Group

13 SCL Device Type Function Block
FUNCTION_BLOCK "DEVTYPE_MPS_VAC-VVS" VAR_INPUT "NTY-O-SX" : BOOL; //EPICS Status variable: OpenR "NTY-C-SX" : BOOL; //EPICS Status variable: ClosedR "NTY-O-SX-ST" : BOOL; //EPICS Status variable: OpenValidR "NTY-C-SX-ST" : BOOL; //EPICS Status variable: ClosedValidR "MPSVac-NTY-ST" : BYTE; //EPICS Status variable: StatR "NTY-CC" : BOOL; //EPICS Status variable: CableR "NTY-CC-ST" : BOOL; //EPICS Status variable: CableValidR "MPSVac-NTY-CC-ST" : BYTE; //EPICS Status variable: CableStatR "NTY-VBP" : BOOL; //EPICS Status variable: VBPR "NTY-VBP-ST" : BOOL; //EPICS Status variable: VBPValidR "MPSVac-NTY-VBP-ST" : BYTE; //EPICS Status variable: VBPStatR "NTY-VBP-CC" : BOOL; //EPICS Status variable: VBPCableR "NTY-VBP-CC-ST" : BOOL; //EPICS Status variable: VBPCableValidR "MPSVac-NTY-VBP-CC-ST" : BYTE; //EPICS Status variable: VBPCableStatR END_VAR VAR StatusReg : Array[0..7] of Word; CommandReg : Array[0..0] of Word; This simplified function block is used to deserialize the command/parameter array into properly typed variables and serialize the status variables into the status array Krisztián Löki, HW&I Group

14 SCL Device Type Function Block
#MyWord := W#0; #MyBoolsinWord[8] := #"NTY-O-SX"; //EPICSName: OpenR #MyBoolsinWord[9] := #"NTY-C-SX"; //EPICSName: ClosedR #MyBoolsinWord[10] := #"NTY-O-SX-ST"; //EPICSName: OpenValidR #MyBoolsinWord[11] := #"NTY-C-SX-ST"; //EPICSName: ClosedValidR #StatusReg[0] := #MyWord; #MyBytesinWord[0] := #"MPSVac-NTY-ST"; //EPICSName: StatR #StatusReg[1] := #MyWord; #MyBoolsinWord[8] := #"NTY-CC"; //EPICSName: CableR #MyBoolsinWord[9] := #"NTY-CC-ST"; //EPICSName: CableValidR #StatusReg[2] := #MyWord; #MyBytesinWord[0] := #"MPSVac-NTY-CC-ST"; //EPICSName: CableStatR #StatusReg[3] := #MyWord; Actual serialization MyWord is a Word, MyBytesInWord is a 2 element byte array declared with the AT construct (MyBytesInWord AT MyWord : Array[0..1] of BYTE), MyBoolsInWord is a 16 element bool array declared with the AT construct Bools in the MyBoolsInWord array are filled from 8-15 and then from 0-7 to maintain BigEndian byte order in the underlying word Krisztián Löki, HW&I Group

15 SCL Instance Data Blocks
DATA_BLOCK "DEV_DTL-010:MPSVac-VVS-10000_iDB" { S7_Optimized_Access := 'TRUE' } VERSION : 1.0 NON_RETAIN "DEVTYPE_MPS_VAC-VVS" BEGIN END_DATA_BLOCK DATA_BLOCK "DEV_DTL-020:MPSVac-VVS-10000_iDB" One instance block is created per device. This is basically an object of type “DEVTYPE_MPS_VAC-VVS” Krisztián Löki, HW&I Group

16 SCL “EPICS_device_calls”
FUNCTION "EPICS_device_calls" : Void { S7_Optimized_Access := 'TRUE' } VERSION : 1.0 BEGIN //******************************************** // Device name: DTL-010:MPSVac-VVS-10000 // Device type: MPS_VAC-VVS "DEV_DTL-010:MPSVac-VVS-10000_iDB" (); // Device name: DTL-020:MPSVac-VVS-10000 "DEV_DTL-020:MPSVac-VVS-10000_iDB" (); This is the “border function” between the generated code and the logic; it does the serialization/deserialization of every instance block. Has to be called by the PLC programmer. Krisztián Löki, HW&I Group

17 SCL “_CommsEPICSDataMap”
"_CommsEPICSDataMappingFBFactory"(EPICSToPLCLength := 0, EPICSToPLCDataBlockOffset := 11, EPICSToPLCParametersStart := 0, PLCToEPICSLength := 8, PLCToEPICSDataBlockOffset := 17, EPICSToPLCCommandRegisters := "DEV_DTL-010:MPSVac-VVS-10000_iDB".CommandReg, PLCToEPICSStatusRegisters := "DEV_DTL-010:MPSVac-VVS-10000_iDB".StatusReg, EPICSToPLCDataBlock := "EPICSToPLC"."Word", PLCToEPICSDataBlock := "PLCToEPICS"."Word"); PLCToEPICSDataBlockOffset := 25, EPICSToPLCCommandRegisters := "DEV_DTL-020:MPSVac-VVS-10000_iDB".CommandReg, PLCToEPICSStatusRegisters := "DEV_DTL-020:MPSVac-VVS-10000_iDB".StatusReg, The _CommsEPICSDataMap function block does the decomposition of the main data blocks into the CommandReg and StatusReg arrays of individual device instance blocks Krisztián Löki, HW&I Group

18 Krisztián Löki, HW&I Group
SCL “_CommsEPICS” FUNCTION "_CommsEPICS" : Void BEGIN IF "Utilities".Pulse_1s THEN "PLCToEPICS"."Word"[2] := "PLCToEPICS"."Word"[2] + 1; IF "PLCToEPICS"."Word"[2] >= THEN "PLCToEPICS"."Word"[2] := 0; END_IF; // Call the comms block to provide PLC<->EPICS comms "_CommsPLC_EPICS_DB"(SendTrigger := "Utilities".Pulse_200ms, BytesToSend := 162, S7Port := 2000, MBPort := 502, PLCToEPICSData := "PLCToEPICS"."Word", EPICSToPLCData := "EPICSToPLC"."Word"); //Map all devices command and status registers to EPICS->PLC and PLC->EPICS data exchange blocks "_CommsEPICSDataMap"(); END_FUNCTION This function: - updates the heartbeat - calls the communication code to send/receive data - calls the composer/decomposer function Krisztián Löki, HW&I Group

19 Populating Status Information
//******************************************** // Device name: DTL-010:MPSVac-VVS-10000 // Device type: MPS_VAC-VVS "DEV_DTL-010:MPSVac-VVS-10000_iDB“."NTY-O-SX" := TRUE; "DEV_DTL-010:MPSVac-VVS-10000_iDB“."NTY-C-SX" := FALSE; "DEV_DTL-010:MPSVac-VVS-10000_iDB“."NTY-O-SX-ST" := TRUE; "DEV_DTL-010:MPSVac-VVS-10000_iDB“."NTY-C-SX-ST" := TRUE; The instance data block can be used to set/retrieve “interface variables” Krisztián Löki, HW&I Group


Download ppt "EPICS Integration of PLC based systems"

Similar presentations


Ads by Google