๐น06- Interfacing ctrlX CORE with IO-Link master using EtherCAT
Bosch rexroth
Last updated
Bosch rexroth
Last updated
This video will teach you how to interface ctrlX CORE with IO-Link master using EtherCAT. The following are the examples covered in the video:
0:00 - Introduction 0:50 - What are we going to see? 1:25 - Connections 2:11 - Adding IO-Link master in the networks 6:28 - Assign memories for IO-Link devices 11:27 - Example 1: Actuating Signal Lamp using Distance sensor 19:45 - Example 2: Reading Vendor and Product ID of the IO-Link device using AoE 28:35 - Example 3: Reading the set-point of the sensor using AoE 31:52 - Example 4: Writing the set-point of the sensor using AoE 34:10 - Example 5: Visualizing IO-Link data on the Node-RED dashboard 37:49 - Outroduction
Software: ctrlX Works Software Version: 1.18.1
Hardware: ctrlX CORE Plus
{attribute 'qualified_only'}
VAR_GLOBAL
//Distance Sensor
rawbyte0 AT %IB0 : BYTE;
rawbyte1 AT %IB1 : BYTE;
//SignalLamp
//Segment1
segment1 AT %QB5 : BYTE;
segment2 AT %QB4 : BYTE;
segment3 AT %QB3 : BYTE;
segment4 AT %QB2 : BYTE;
segment5 AT %QB1 : BYTE;
END_VAR
PROGRAM PLC_PRG
VAR
wData : WORD;
iDistance : INT;
bOutput : BOOL;
bySegment1 : BYTE;
END_VAR
// -------------------- Reading Distance sensor process output --------------------
//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);
//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));
//Defining limits
IF iDistance > 200 THEN
iDistance := 200;
END_IF
IF iDistance < 5 THEN
iDistance := 5;
END_IF
//Set point output
bOutput := GVL.rawbyte1.0;
//SignalLamp condition
IF bOutput = TRUE THEN
// 2= Green
GVL.segment1 := 2;
GVL.segment2 := 2;
GVL.segment3 := 2;
GVL.segment4 := 2;
GVL.segment5 := 2;
ELSE //4= RED
GVL.segment1 := 4;
GVL.segment2 := 4;
GVL.segment3 := 4;
GVL.segment4 := 4;
GVL.segment5 := 4;
END_IF
{attribute 'qualified_only'}
VAR_GLOBAL
//Distance Sensor
rawbyte0 AT %IB0 : BYTE;
rawbyte1 AT %IB1 : BYTE;
//SignalLamp
//Segment1
segment1 AT %QB5 : BYTE;
segment2 AT %QB4 : BYTE;
segment3 AT %QB3 : BYTE;
segment4 AT %QB2 : BYTE;
segment5 AT %QB1 : BYTE;
END_VARde
PROGRAM PLC_PRG
VAR
wData : WORD;
iDistance : INT;
bOutput : BOOL;
bySegment1 : BYTE;
// ---------------- Read AoE -----------------------------
//Name of instance
strMasterName : STRING := 'ethercatmaster';
//Ethercat address of ifm AL1332
uiEthercatAddr : UINT := 1005;
strTargetNetId : IL_ECAT_AOE_NET_ID := (Byte0:= 172, Byte1:=31, Byte2:= 254, Byte3:= 254, Byte4:= 0, Byte5:= 1);
//Vendor variable declaration for IO Link read
strVendor : STRING(32) := ''; //Variable in which the read result (vendor) value will be copied
fbIOLinkRead_Vendor: IL_ECATAoeRead;
uiIoLinkPortNbr_Vendor : UINT := 1;//X1 = Plug, the IO-Link device is connected
wIoLinkIndex_Vendor : WORD := 16; //IO-Link index = 16 (vendor)
byIoLinkSubIndex_Vendor : BYTE := 0; //IO-Link Subindex = 0 (vendor)
bVendor_Error: BOOL;
bVendor_Done: BOOL;
bRead_Vendor: BOOL;
// X01 Product ID variable declaration for IO Link Read
strProductID : STRING(32) := ''; //Variable in which the read result (Product ID) value will be copied
fbIOLinkRead_ProductID: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID : UINT := 1; //X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID : WORD := 19;//IO-Link index = 19 (product ID)
byIoLinkSubIndex_ProductID : BYTE :=0;//IO-Link Subindex = 0 (product ID)
bProductID_Error: BOOL;
bProductID_Done: BOOL;
bRead_ProductID: BOOL;
END_VAR
//Read Aoe vendor ID
//Read function
fbIOLinkRead_Vendor(
Execute:= bRead_Vendor, //Execute bit
MasterName:= ADR(strMasterName), //Instance name
SlaveAddress:= uiEthercatAddr, //EtherCAT address of IO-Link master
TargetNetId:= strTargetNetId , //Refer from ctrlX I/O
TargetPort:= 16#1000 + uiIoLinkPortNbr_Vendor, //ADS communication port = 16#1000 + IO-Link port number
IndexGroup:= 16#F302, //Fixed for IFM IO-Link
//IDXOFFS Index Offset
//Bits 0-7: IO-Link subindex
//Bits 8-15: 00000000
//Bits 16-31: IO-Link index
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_Vendor),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_Vendor)),
SizeOfValue:= SIZEOF(strVendor), //Byte requirement
ValueAdr:= ADR(strVendor)); //Value
IF TRUE = fbIOLinkRead_Vendor.Done THEN
bVendor_Error := FALSE; // Reset error
bVendor_Done := TRUE;
END_IF;
IF TRUE = fbIOLinkRead_Vendor.Error THEN
bVendor_Error := TRUE; // Error handling
bVendor_Done := FALSE;
END_IF;
//Read Aoe Product ID
fbIOLinkRead_ProductID(
Execute:= bRead_ProductID,
MasterName:= ADR(strMasterName),
SlaveAddress:= uiEthercatAddr,
TargetNetId:= strTargetNetId ,
TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID,
IndexGroup:= 16#F302,
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID)),
SizeOfValue:= SIZEOF(strProductID),
ValueAdr:= ADR(strProductID),
);
// -------------------- Reading Distance sensor process output --------------------
//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);
//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));
//Defining limits
IF iDistance > 200 THEN
iDistance := 200;
END_IF
IF iDistance < 5 THEN
iDistance := 5;
END_IF
//Set point output
bOutput := GVL.rawbyte1.0;
//SignalLamp condition
IF bOutput = TRUE THEN
GVL.segment1 := 2;
GVL.segment2 := 2;
GVL.segment3 := 2;
GVL.segment4 := 2;
GVL.segment5 := 2;
ELSE
GVL.segment1 := 4;
GVL.segment2 := 4;
GVL.segment3 := 4;
GVL.segment4 := 4;
GVL.segment5 := 4;
END_IF
{attribute 'qualified_only'}
VAR_GLOBAL
//Distance Sensor
rawbyte0 AT %IB0 : BYTE;
rawbyte1 AT %IB1 : BYTE;
//SignalLamp
//Segment1
segment1 AT %QB5 : BYTE;
segment2 AT %QB4 : BYTE;
segment3 AT %QB3 : BYTE;
segment4 AT %QB2 : BYTE;
segment5 AT %QB1 : BYTE;
END_VAR
PROGRAM PLC_PRG
VAR
wData : WORD;
iDistance : INT;
bOutput : BOOL;
bySegment1 : BYTE;
// ---------------- Read AoE -----------------------------
//Name of instance
strMasterName : STRING := 'ethercatmaster';
//Ethercat address of ifm AL1332
uiEthercatAddr : UINT := 1005;
strTargetNetId : IL_ECAT_AOE_NET_ID := (Byte0:= 172, Byte1:=31, Byte2:= 254, Byte3:= 254, Byte4:= 0, Byte5:= 1);
//Vendor variable declaration for IO Link read
strVendor : STRING(32) := ''; //Variable in which the read result (vendor) value will be copied
fbIOLinkRead_Vendor: IL_ECATAoeRead;
uiIoLinkPortNbr_Vendor : UINT := 1; //X1 = Plug, the IO-Link device is connected
wIoLinkIndex_Vendor : WORD := 16; //IO-Link index = 16 (vendor)
byIoLinkSubIndex_Vendor : BYTE := 0; //IO-Link Subindex = 0 (vendor)
bVendor_Error: BOOL;
bVendor_Done: BOOL;
bRead_Vendor: BOOL;
// X01 Product ID variable declaration for IO Link Read
strProductID : STRING(32) := ''; //Variable in which the read result (Product ID) value will be copied
fbIOLinkRead_ProductID: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID : UINT := 1; //X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID : WORD := 19; //IO-Link index = 19 (product ID)
byIoLinkSubIndex_ProductID : BYTE :=0; //IO-Link Subindex = 0 (product ID)
bProductID_Error: BOOL;
bProductID_Done: BOOL;
bRead_ProductID: BOOL;
// X01 Set point of Variable declaration for IO Link Read
uiSetPointRead: UINT;
uiSetPointRead_swap: UINT; //Varible for byte swap output
bRead_SetPoint: BOOL;
fbIOLinkRead_ProductID_SetPoint: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID_SetPoint : UINT := 1; //X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID_SetPoint : WORD := 60; //IO-Link index = 60 (Set Point)
byIoLinkSubIndex_ProductID_SetPoint : BYTE := 1; //IO-Link Subindex = 1 (Set Point)
bProductID_SetPoint_Error: BOOL;
bProductID_SetPoint_Done: BOOL;
END_VAR
//Read Aoe vendor ID
//Read function
fbIOLinkRead_Vendor(
Execute:= bRead_Vendor, //Execute bit
MasterName:= ADR(strMasterName), //Instance name
SlaveAddress:= uiEthercatAddr, //EtherCAT address of IO-Link master
TargetNetId:= strTargetNetId , //Refer from ctrlX I/O
TargetPort:= 16#1000 + uiIoLinkPortNbr_Vendor, //ADS communication port = 16#1000 + IO-Link port number
IndexGroup:= 16#F302, //Fixed for IFM IO-Link
//IDXOFFS Index Offset
//Bits 0-7: IO-Link subindex
//Bits 8-15: 00000000
//Bits 16-31: IO-Link index
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_Vendor),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_Vendor)),
SizeOfValue:= SIZEOF(strVendor), //Byte requirement
ValueAdr:= ADR(strVendor)); //Value
IF TRUE = fbIOLinkRead_Vendor.Done THEN
bVendor_Error := FALSE; // Reset error
bVendor_Done := TRUE;
END_IF;
IF TRUE = fbIOLinkRead_Vendor.Error THEN
bVendor_Error := TRUE; // Error handling
bVendor_Done := FALSE;
END_IF;
//Read Aoe Product ID
fbIOLinkRead_ProductID(
Execute:= bRead_ProductID,
MasterName:= ADR(strMasterName),
SlaveAddress:= uiEthercatAddr,
TargetNetId:= strTargetNetId ,
TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID,
IndexGroup:= 16#F302,
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID)),
SizeOfValue:= SIZEOF(strProductID),
ValueAdr:= ADR(strProductID),
);
//Read Aoe Product ID Set Point
fbIOLinkRead_ProductID_SetPoint(
Execute:= bRead_SetPoint,
MasterName:= ADR(strMasterName),
SlaveAddress:= uiEthercatAddr,
TargetNetId:= strTargetNetId ,
TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID_SetPoint,
IndexGroup:= 16#F302,
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID_SetPoint),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID_SetPoint)),
SizeOfValue:= SIZEOF(uiSetPointRead),
ValueAdr:= ADR(uiSetPointRead),
);
//Byte swap of Set Point read
uiSetPointRead_swap := WORD_TO_UINT(IL_SwapWord(uiSetPointRead));
IF TRUE = fbIOLinkRead_ProductID_SetPoint.Done THEN
bProductID_SetPoint_Error := FALSE; // Reset error
bProductID_SetPoint_Done := TRUE;
END_IF;
IF TRUE = fbIOLinkRead_ProductID_SetPoint.Error THEN
bProductID_SetPoint_Error := TRUE; // Error handling
bProductID_SetPoint_Done := FALSE;
END_IF;
// -------------------- Reading Distance sensor process output --------------------
//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);
//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));
//Defining limits
IF iDistance > 200 THEN
iDistance := 200;
END_IF
IF iDistance < 5 THEN
iDistance := 5;
END_IF
//Set point output
bOutput := GVL.rawbyte1.0;
//SignalLamp condition
IF bOutput = TRUE THEN
GVL.segment1 := 2;
GVL.segment2 := 2;
GVL.segment3 := 2;
GVL.segment4 := 2;
GVL.segment5 := 2;
ELSE
GVL.segment1 := 4;
GVL.segment2 := 4;
GVL.segment3 := 4;
GVL.segment4 := 4;
GVL.segment5 := 4;
END_IF
{attribute 'qualified_only'}
VAR_GLOBAL
//Distance Sensor
rawbyte0 AT %IB0 : BYTE;
rawbyte1 AT %IB1 : BYTE;
//SignalLamp
//Segment1
segment1 AT %QB5 : BYTE;
segment2 AT %QB4 : BYTE;
segment3 AT %QB3 : BYTE;
segment4 AT %QB2 : BYTE;
segment5 AT %QB1 : BYTE;
END_VAR
PROGRAM PLC_PRG
VAR
wData : WORD;
iDistance : INT;
bOutput : BOOL;
bySegment1 : BYTE;
// ---------------- Read AoE -----------------------------
//Name of instance
strMasterName : STRING := 'ethercatmaster';
//Ethercat address of ifm AL1332
uiEthercatAddr : UINT := 1005; strTargetNetId : IL_ECAT_AOE_NET_ID := (Byte0:= 172, Byte1:=31, Byte2:= 254, Byte3:= 254, Byte4:= 0, Byte5:= 1);
//Vendor variable declaration for IO Link read
strVendor : STRING(32) := ''; //Variable in which the read result (vendor) value will be copied
fbIOLinkRead_Vendor: IL_ECATAoeRead;
uiIoLinkPortNbr_Vendor : UINT := 1;//X1 = Plug, the IO-Link device is connected
wIoLinkIndex_Vendor : WORD := 16; //IO-Link index = 16 (vendor)
byIoLinkSubIndex_Vendor : BYTE := 0; //IO-Link Subindex = 0 (vendor)
bVendor_Error: BOOL;
bVendor_Done: BOOL;
bRead_Vendor: BOOL;
// X01 Product ID variable declaration for IO Link Read
strProductID : STRING(32) := ''; //Variable in which the read result (Product ID) value will be copied
fbIOLinkRead_ProductID: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID : UINT := 1; //X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID : WORD := 19; //IO-Link index = 19 (product ID)
byIoLinkSubIndex_ProductID : BYTE :=0; //IO-Link Subindex = 0 (product ID)
bProductID_Error: BOOL;
bProductID_Done: BOOL;
bRead_ProductID: BOOL;
// X01 Set point of Variable declaration for IO Link Read
uiSetPointRead: UINT;
uiSetPointRead_swap: UINT; //Varible for byte swap output
bRead_SetPoint: BOOL;
fbIOLinkRead_ProductID_SetPoint: IL_ECATAoeRead;
uiIoLinkPortNbr_ProductID_SetPoint : UINT := 1;//X1 = Plug, the IO-Link device is connected
wIoLinkIndex_ProductID_SetPoint : WORD := 60;//IO-Link index = 60 (Set Point)
byIoLinkSubIndex_ProductID_SetPoint : BYTE := 1; //IO-Link Subindex = 1 (Set Point)
bProductID_SetPoint_Error: BOOL;
bProductID_SetPoint_Done: BOOL;
//------------------Write AoE-------------------------
uiSetPointWrite : UINT := 25;
uiSetPointWrite_swap: UINT;
bWrite_SetPoint: BOOL;
fbIOLinkWrite_ProductID_SetPoint_write: IL_ECATAoeWrite;
bProductID_SetPoint_Write_Error: BOOL;
bProductID_SetPoint_Write_Done: BOOL;
END_VAR
//Read Aoe vendor ID
//Read function
fbIOLinkRead_Vendor(
Execute:= bRead_Vendor, //Execute bit
MasterName:= ADR(strMasterName), //Instance name
SlaveAddress:= uiEthercatAddr, //EtherCAT address of IO-Link master
TargetNetId:= strTargetNetId , //Refer from ctrlX I/O
TargetPort:= 16#1000 + uiIoLinkPortNbr_Vendor, //ADS communication port = 16#1000 + IO-Link port number
IndexGroup:= 16#F302, //Fixed for IFM IO-Link
//IDXOFFS Index Offset
//Bits 0-7: IO-Link subindex
//Bits 8-15: 00000000
//Bits 16-31: IO-Link index
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_Vendor),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_Vendor)),
SizeOfValue:= SIZEOF(strVendor), //Byte requirement
ValueAdr:= ADR(strVendor)); //Value
IF TRUE = fbIOLinkRead_Vendor.Done THEN
bVendor_Error := FALSE; // Reset error
bVendor_Done := TRUE;
END_IF;
IF TRUE = fbIOLinkRead_Vendor.Error THEN
bVendor_Error := TRUE; // Error handling
bVendor_Done := FALSE;
END_IF;
//Read Aoe Product ID
fbIOLinkRead_ProductID(
Execute:= bRead_ProductID,
MasterName:= ADR(strMasterName),
SlaveAddress:= uiEthercatAddr,
TargetNetId:= strTargetNetId ,
TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID,
IndexGroup:= 16#F302,
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID)),
SizeOfValue:= SIZEOF(strProductID),
ValueAdr:= ADR(strProductID),
);
//Read Aoe Product ID Set Point
fbIOLinkRead_ProductID_SetPoint(
Execute:= bRead_SetPoint,
MasterName:= ADR(strMasterName),
SlaveAddress:= uiEthercatAddr,
TargetNetId:= strTargetNetId ,
TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID_SetPoint,
IndexGroup:= 16#F302,
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID_SetPoint),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID_SetPoint)),
SizeOfValue:= SIZEOF(uiSetPointRead),
ValueAdr:= ADR(uiSetPointRead),
);
//Byte swap of Set Point read
uiSetPointRead_swap := WORD_TO_UINT(IL_SwapWord(uiSetPointRead));
IF TRUE = fbIOLinkRead_ProductID_SetPoint.Done THEN
bProductID_SetPoint_Error := FALSE; // Reset error
bProductID_SetPoint_Done := TRUE;
END_IF;
IF TRUE = fbIOLinkRead_ProductID_SetPoint.Error THEN
bProductID_SetPoint_Error := TRUE; // Error handling
bProductID_SetPoint_Done := FALSE;
END_IF;
//Write Aoe Product ID Set Point
//uiSetPointWrite_conv := ROR(SetPointWrite,8);
uiSetPointWrite_swap := WORD_TO_UINT(IL_SwapWord(uiSetPointWrite));
fbIOLinkWrite_ProductID_SetPoint_write(
Execute:= bWrite_SetPoint,
MasterName:= ADR(strMasterName),
SlaveAddress:= uiEthercatAddr,
TargetNetId:= strTargetNetId,
TargetPort:= 16#1000 + uiIoLinkPortNbr_ProductID_SetPoint,
IndexGroup:= 16#F302,
IndexOffset:= (16#FFFF0000 AND SHL(ANY_TO_UDINT(wIoLinkIndex_ProductID_SetPoint),16))
OR (16#000000FF AND ANY_TO_UDINT(byIoLinkSubIndex_ProductID_SetPoint)),
ValueAdr:= ADR(uiSetPointWrite_swap),
SizeOfValue:= SIZEOF(uiSetPointWrite_swap),
//SizeOfValue:= 2,
);
IF TRUE = fbIOLinkWrite_ProductID_SetPoint_write.Done THEN
bProductID_SetPoint_Write_Error := FALSE;// FB Finished -> Product name was read,
bProductID_SetPoint_Write_Done := TRUE;
END_IF;
IF TRUE = fbIOLinkWrite_ProductID_SetPoint_write.Error THEN
bProductID_SetPoint_Write_Error := TRUE;// Error handling
bProductID_SetPoint_Write_Done := FALSE;
END_IF;
// -------------------- Reading Distance sensor process output --------------------
//Concatinate the byte 0 and byte 1
wData := IL_ConcatByte(GVL.rawbyte0,GVL.rawbyte1);
//Right shift the word by 4 bit
iDistance := WORD_TO_INT(SHR(wData,4));
//Defining limits
IF iDistance > 200 THEN
iDistance := 200;
END_IF
IF iDistance < 5 THEN
iDistance := 5;
END_IF
//Set point output
bOutput := GVL.rawbyte1.0;
//SignalLamp condition
IF bOutput = TRUE THEN
GVL.segment1 := 2;
GVL.segment2 := 2;
GVL.segment3 := 2;
GVL.segment4 := 2;
GVL.segment5 := 2;
ELSE
GVL.segment1 := 4;
GVL.segment2 := 4;
GVL.segment3 := 4;
GVL.segment4 := 4;
GVL.segment5 := 4;
END_IF