Object-oriented program for controlling a sorting plant
Object-oriented programming offers a wide range of tools that can be used in many different ways. The following example illustrates the benefits of object orientation and demonstrates some ideas for using object orientation in PLC/machine programming. The object-oriented concept presented in this example and the underlying approaches do not claim to be exhaustive and cannot be generalized for other applications.
The example program for illustrating object-oriented programming (OOP) is used to control a sorting unit for metal and plastic boxes according to their material type. The sorting process includes one separation and two discharge units. These operations are implemented by means of cylinders, of which different versions are available. The different cylinder versions differ in terms of complexity. In the example, the system is required to be able to replace the cylinders in use with cylinders of a different type.
The system can distinguish the different material types by means of a sensor for metal detection, so that metal boxes (gray) and plastic boxes (green) are discharged on different auxiliary conveyor belts. The following video illustrates the sorting process, with the system viewed from above.
General concept of OOP
A general goal of object-oriented programming is to develop automation modules, for example. These objects are application-neutral, ready-made functional units, which only have to be developed once but can be used repeatedly without modification. Automation modules are therefore not developed for a specific plant, but generally provide system functionality that can be used in several plants. For example, a class “FB_Axis” for controlling an axis is developed once and then instantiated and used in several systems.
Automation modules can reduce the implementation effort for programming a system quite significantly. At the same time, the quality and reliability of the objects used are comparatively high, since the modules are also used in other systems and are therefore continuously tested and perhaps improved. If the same programming style and implementation concept are used for different modules, it is possible to achieve a uniform “look and feel” for the objects, so that application standardization can be achieved.
A prerequisite for meaningful development and application of automation modules is a modular design and modular programming of the system. For example, subdivision of the system into objects can be designed such that the system consists of different subsystems, and these subsystems contain different submodules. The machine, its subsystems and their submodules are implemented as automation modules and thus act as separate, independent objects.
Furthermore, it may be possible to generalize the data and functionalities that are common to all submodules in a submodule base class. By developing a subsystem base class, this approach can also be applied to subsystems, if there are commonalities between the subsystems. On the one hand, this would significantly reduce the programming effort, and on the other hand only the base class would have to be modified in the event of changes to the common implementations.
Sorting unit – approach
The programming of the sorting unit based on object orientation is explained in detail below, using the example of the cylinders. Implementing of the other submodules, such as drives and sensors, can be derived from the procedure for programming the cylinders. The consolidation of submodules into subsystems is briefly described at the end. Procedure for implementing the cylinders as submodules:
- Planning the software structure
- Implementing the software concept
- Instantiating the program elements
- Allocation of function block instances to an interface instance
- Use of a function block instance via an interface instance
- Further software concept: Consolidation of submodules to subsystems
Planning the software structure
The required cylinder types comprise simple cylinders, which can only move to a home or working position, and cylinders with additional functionalities. These more complex cylinders can monitor reaching of their end positions, and logging or diagnosing their temperature to detect whether the temperature is outside a specified range. The individual machine cylinders should not be limited to a certain cylinder type, but should be exchangeable with other types. In this way it should be possible, for example, to replace a simple cylinder with a cylinder with additional functionality.
Irrespective of any auxiliary functions, all cylinders should be capable of the basic functionality of retracting and extending. Since this is a requirement that applies to each cylinder within the application, the methods and properties associated with the requirement are defined in an interface. An interface contains no implementations, only the definition of methods and properties. It therefore merely represents a convention for the function blocks that implement the interface. The convention is met if the defined methods and properties are provided by the function blocks. Finally, the implementations of the program elements defined in the interface are programmed in the implementing function blocks.
Defining the interface I_Cylinder and its implementation in the cylinder function blocks ensures that the cylinders meet the requirements and have access to the associated program elements. In addition, by defining and implementing an interface it is possible to access function block instances via interface instances. In this way the required cylinder exchangeability is ensured.
Since all cylinders have to provide the basic functionalities of retraction and extension, in addition to defining an interface convention it makes sense to generalize these functionalities and make their implementation available via a base class. For this reason the cylinder FB_Cylinder is planned, which features methods for cylinder movement and represents the base class for all required cylinders. This ensures that all derived classes offer the basic functionalities of retracting and extending, although they are only implemented once in the base cylinder.
The function block FB_CylinderDiag is derived from the superclass FB_Cylinder. As it also monitors reaching of the end positions, it extends the base cylinder with this functionality. It represents the solution for one of the required cylinders.
Since the cylinders require the value of the current temperature for recording and monitoring of the temperature, a function block with this component is derived from the base class FB_Cylinder. By adding a temperature supplement the class name becomes FB_CylinderTemp. It represents the superclass for cylinders with temperature recording and monitoring. The two subclasses with the names FB_CylinderTempDiag and FB_CylinderTempRecord are extended with specific behavior and variables required for these functionalities.
Implementing the software concept
The planned function blocks can now be implemented. In order to illustrate the procedure, parts of the base class FB_Cylinder and the derived class FB_CylinderDiag are described below.
The function block FB_Cylinder integrates the interface I_Cylinder with the aid of the keyword IMPLEMENTS, resulting in the methods and properties of the interface in the superclass to be created automatically. This ensures that the function block and its derivations have the elements required by the interface. The function block structure resulting from the interface and the declaration of the function block FB_Cylinder are shown in the diagram below.
The method Reset, which resets the cylinder output bMoveToWork of the function block, is shown as an example.
// =========================================================
// *** Method Reset of FB_Cylinder ***
bMoveToWork := FALSE;
// =========================================================
With the aid of the keyword EXTENDS the function block FB_CylinderDiag becomes a derivative of FB_Cylinder. The variables, methods and properties of the base class can then be used (depending on the access modifier). Since the subclass is intended to extend the methods Reset and StateMachine of the base class, the methods are inserted in the subclass and can thus be modified. In addition, the method Diag is integrated, which is not included in the base class. The additional variables required for the diagnostic functionality are declared in FB_CylinderDiag. The structure and the declaration of FB_CylinderDiag are shown below:
In the methods Reset and StateMachine of the derived class, the corresponding methods of the superclass can be extended or overwritten. To obtain a method extension the method of the base class is called by using the keyword SUPER. SUPER is a function block pointer that points to the function block instance of the base class. The behavior of the base class can be extended through further instructions in the method of the subclass, whereby the method is adjusted for the cylinder FB_CylinderDiag. As an example, the method Reset of FB_CylinderDiag, which extends the corresponding method of the base class FB_Cylinder through further instructions, is shown below.
// =========================================================
// *** Method Reset of FB_CylinderDiag ***
// Calling method Reset of base class FB_Cylinder via 'SUPER^.'
SUPER^.Reset();
// Reset error
bError := FALSE;
sErrorMsg := '';
// =========================================================
Instantiating the program elements
The function blocks created with the aid of inheritance and corresponding keywords, which represent cylinders with different functionality, can now be instantiated.
The function blocks FB_Cylinder, FB_CylinderDiag, FB_CylinderTemp, FB_CylinderTempDiag and FB_CylinderTempRecord are instantiated once to ensure that a cylinder can be regarded as variable and can be represented by each cylinder type. The interface instance iCylinder is the object that references one of the cylinder function block instances and therefore the currently selected cylinder type at runtime.
The variables bCylinderDiag, bCylinderTemp and bCylinderRecord can be modified by the user and indicate whether the cylinder has diagnostics and temperature functionality.
The instantiation of the function blocks, the interfaces and the three Boolean variables are shown below.
// ===== Variables to enable/disable diagnosis and temperature mode ===
bCylinderDiag : BOOL; // If true the cylinder has diagnosis functionality
bCylinderTemp : BOOL; // If true the cylinder has temperature functionality
bCylinderRecord : BOOL; // If true the cylinder has recording functionality
// ===== Function block instances for cylinder ========================
fbCylinder : FB_Cylinder; // Without diagnosis and temperature mode
fbCylinderDiag : FB_CylinderDiag; // With diagnosis of states
fbCylinderTemp : FB_CylinderTemp; // With temperature mode
fbCylinderTempDiag : FB_CylinderTempDiag; // With diagnosis of temperature
fbCylinderTempRecord : FB_CylinderTempRecord; // With record of temperatures
// ===== Interface instance for cylinder ==============================
iCylinder : I_Cylinder; // Interface for flexible access to cylinder FBs
Assignment of function block instances to an interface instance
To exchange a cylinder all that is required is to adapt the variables bCylinderDiag, bCylinderTemp and bCylinderRecord, since the corresponding function block instance is assigned to the interface instance iCylinder, depending on the state of these three variables.
If the cylinder is to have the functionality of temperature monitoring, for example, bCylinderDiag and bCylinderTemp have the value TRUE and bCylinderRecord has the value FALSE. The desired function block is therefore FB_CylinderTempDiag and the associated instance fbCylinderTempDiag is assigned to the interface instance. The specific outputs bError and sErrorMsg for this class are intercepted separately by assigning them to local variables. Because the FB instance fbCylinderTempDiag is assigned to the interface instance iCylinder, the function block instance with temperature monitoring can be accessed via the interface instance.
If the Boolean variables have other values, conversely, the interface instance will be assigned a different function block instance accordingly. Two samples for function block assignments are shown below.
// =========================================================
// Selecting cylinder by checking variables to enable / disable diagnosis and temperature mode
IF bCylinderDiag THEN
IF bCylinderTemp THEN
// =========== FB with diagnosis and temperature mode ==================
bError := fbCylinderTempDiag.bError; // Assigning output variable of chosen FB to local variable
sErrorMsg := fbCylinderTempDiag.sErrorMsg;
iCylinder := fbCylinderTempDiag; // Assigning chosen FB instance to interface instance
ELSE
// =========== FB with diagnosis and without temperature mode ===========
fbCylinderDiag.tTimeOut := tTimeOutCylinder; // Setting special data for selected FB
bCylError := fbCylinderDiag.bError; // Assigning output variable of chosen FB to local variable
sCylErrorMsg := fbCylinderDiag.sErrorMsg;
iCylinder := fbCylinderDiag; // Assigning chosen FB instance to interface instance
…
END_IF
// =========================================================
Use of a function block instance via an interface instance
The interface instance that was assigned one of the FB instances can call its methods with the help of dot notation. With this method call via the interface instance, the method of the function block instance to which the interface points is called due to the interface pointer.
The following program section illustrates how the selected cylinder function block is moved to the home or working position via the interface instance.
// =========================================================
// Manual cylinder control (Calling methods of FB via interface instance)
// Cylinder to work position
IF fbButtonCylToWork.bOut THEN
iCylinder.MoveToWork();
// Cylinder to base position
ELSIF fbButtonCylToBase.bOut THEN
iCylinder.MoveToBase();
END_IF
// =========================================================
Further software concept: Consolidation of submodules to subsystems
The implementation of function blocks and the application of their instances with the aid of an interface instance presented here represents small-scale object-oriented programming. For optimum application of object orientation it is complemented with larger-scale OOP. Different submodules are consolidated to subsystems.
For a sorting unit, it makes sense to consolidate a sensor for material detection, a drive for controlling the movement of an auxiliary conveyor belt and a discharge cylinder to form a discharge module. In this way it is possible to instantiate any number of objects or sorting modules from this class, with only one discharge module being programmed. Based on this approach it is possible to configure different systems with different numbers of sorting modules that are specialized for other material type (e.g. metal, plastic, foil, glass etc.).
Another subsystem of the sorting unit deals with separation. It consists of a sensor for box identification, a drive for moving the boxes to the main conveyor and two cylinders for implementing the actual separation.
Since the two subsystems for separation and discharging have commonalities, the subsystem-specific data and functionalities are consolidated in a subsystem base class. Separation and discharging are then declared as a subclass of this function block, which means they inherit the generalized program elements from the subsystem base class.
Through the development of submodules and subsystems, the object-oriented programming options and benefits can be applied and utilized at various levels.
TC3.1 sources
The complete TC3.1 sources for the sample program can be unpacked here: TC3_PlcSample_OOPExtendedSample.zip
To start the sample program:
- Activate the TwinCAT configuration and start TwinCAT in Run mode
- Log in on both PLCs and start them (TC3_SortingSystem_PLC and TC3_SortingSystem_Simu)
- Operate the application via the machine visualization. This can be found in:
- PLC project: TC3_SortingSystem_PLC
- Folder: 05_Visu
- For example: Start the system in automatic mode by pressing the following button:
- “Main Switch Power Supply”
- “Automatic”
- “Start”
See also:
- PLC documentation: Object-oriented programming