PLC object-oriented programming benefits
Object-oriented programming (OOP) is about organizing and simplifying program elements in an optimal way by using objects, methods, and properties.
The latest IEC-61131-3 standard update includes object-oriented programming (OOP) language. Although OOP is often associated with high-sounding terminology, it is quite simple. OOP is all about organization and simplification. Organization refers to the manner in which the program elements are grouped and the grouping mechanisms are employed. Well-organized programs are more intuitive and easier to work with. OOP features are designed to promote and facilitate sound organizational projects. Simplification refers to the simplified interface that is presented to the external world. Beneath that surface, complex details within the object itself are kept within the program.
What are objects?
An object combines related functions and the data upon which they operate into a single entity that models the state and behavior of real-world devices, processes, and other constructs. In the IEC-61131-3 standard, objects are implemented as function blocks with some additional capabilities. Function blocks can define methods and properties to further partition the code and extend the interfaces. Methods and properties can be implemented using any of the IEC-61131 languages. Language selection is determined by an individual method or property basis, which makes it easy to use the best-suited language depending on the circumstance.
The example project contains a function block that implements a simple up/down counter and is defined as shown in Figure 1. The term "class" used in other OOP languages is synonymous with "function block." Both terms refer to definitions that must be instantiated before they can be used. Instances of classes or function blocks are referred to as "objects."
Methods are functions that have access to the defining function block's internal data and parameters. They may also have input and output parameters and return values like ordinary functions.
In Figure 2, a method is defined using Relay Ladder as the implementation language. When the input parameter is true the counter increments until it reaches a maximum value. PMaxCount and Count are defined in the main body of the function block. Since methods have access to the function block's data and parameters, PMaxCount and Count can be used from within the method. The return value is written to CountUp, which is the name of the method itself.
The variable NotMax is defined within the method and allocated on the method's call stack. This means the value from the previous execution is not retained. Variables defined in the function block body are allocated in memory and retain their values from execution-to-execution.
A second method that decrements the counter is defined in Figure 3. This time, the implementation language is Structured Text. When the input parameter is TRUE, the counter is decremented until it reaches a value of zero. Count is the function block's output parameter, and the return value is written to CountDn, the method name. This method provides an easy and convenient means of organizing a program into smaller, more manageable pieces. It's also designed to be easy to mix and match different languages.
It's a simple matter to call these methods from the function block body, as shown in Figure 4. Since these methods are defined using the keyword "PRIVATE," they can only be called from within the function block itself. Methods defined using the keyword "PUBLIC" can also be called externally.
Properties are functions that behave like variables and can be used in expressions the same way variables are used. Instead of being bound to a memory location, a property is bound to its get() and set() functions. When data is read from a property, its get() function is executed. When data is written to a property, its set() function is executed as shown in the example below:
The "PUBLIC" and "PRIVATE" keywords can also be used to control how properties may be accessed. "PRIVATE" means the property can only be used internally within the defining function block. "PUBLIC" means the property can be used externally. However, the "PUBLIC" and "PRIVATE" keywords can also be used with the get() and set() function definition. This allows properties to be readable externally and writable internally.
At their most basic form, properties read and write data to and from internal variables. Their additional capabilities can be used to validate data values or perform other operations. For example, the property MaxCount is added to the program shown in Figure 5. This allows the maximum count to be set to a specified value and its current value to be read. Data is passed to and from the set() and get() functions via the MaxCount property name as if it were a variable. The get() function returns the value of the function block variable PMaxCount. The set() function validates the input value by ensuring it's a positive number before writing the result to PMaxCount.
In the next part of the example, a Reset property, using Relay Ladder language, is added to the project in Figure 6. The reset property does not have an underlying variable that is read and written. When a value of TRUE is written, a reset operation is performed. When the property is read, an expression is evaluated, and the result is returned.
It's worth noting how the project's structure and organization are reflected in the project tree. Each program, function block, method, and property in the project is represented by a node. Double clicking a node will open it as a tab in the document page of the main window. Tabs can be undocked and displayed as separate windows like in Figures 5 and 6. The get() and set() functions are undocked so both can be displayed along with the property definition.
Extending function blocks
What happens when a function block meets almost all requirements except for a few things that need to be done differently? Normally, the function block is copied and modified as needed. The problem with this scenario is that a substantial amount of code is identical in both blocks, which means that bug fixes or other modifications will likely need to be done twice.
This can be avoided by extending the original function block rather than make a copy. The original block's variable, parameter, method, and property definitions are applied to the new block. This block is said to "inherit" or "be derived" from the original. Therefore, changes made to the original block are reflected in the new block.
In the example shown in Figure 7, a new function block FB_MyUpDn is added. By using the keyword "EXTENDS," the new block inherits all the data, parameters, methods, and properties of the original up/down counter, FB_UpDn. The code in the body of FB_UpDn is not inherited, which makes both function blocks identical at this point.
The new function block imposes an upper limit on the MaxCount property by defining its own property, which implements the limit shown in Figure 8. The new property overrides the MaxCount property defined in the original function block. Calling MaxCount(500) from an instance of the original block executes the original MaxCount code and sets the value to 500. Calling MaxCount(500) from an instance of the new block executes the new code and sets the value to an upper limit of 250.
What about programs?
A program is a function block where the definition and the instance are the one and the same. Consequently, a program has only one instance, but it also has several features in common with function blocks. A program can define internal data, parameters, methods, and properties just like function blocks. Although this does not strictly adhere to the edicts of OOP, it is a useful technique that can be applied to any program regardless of the underlying design philosophy, which is illustrated in Figure 9.
In the example, A_Property, and an example method, A_Method, have been added to the main program to illustrate this capability. The main program also contains an instance of the FB_UpDn function block. The function block and its two main properties are used in the program body. The Reset property written in the first rung and its value is read in the second rung. The UpDn function block's code is executed in the third rung. The last two rungs write values to the MaxCount property.
Designing with objects
An object models the state and behavior of a given entity. The key to good object-based design is choosing which entities to model. Good choices result in clean and intuitive designs. Making good choices, however, is as much art as science and is the most difficult part of the process. Thinking of objects as real-world devices and processes is a good place to start. It's much easier to begin with tangible entities and then move on to the abstract concepts than attempting everything at once.
There is more to OOP, but it all comes back to the fundamental goal of organizing program elements in an optimal way. Objects, methods, and properties are the primary means of achieving this goal, which makes it essential to understand and master these concepts. Get started by taking small steps to organize conventional programs; object-based designs can come along later. Being familiar with using the techniques will make it easier to imagine all the other possibilities. There is no reason not to give it a try.
Richard Jafrate is the founder of Mitek Automation. Edited by Chris Vavra, production editor, Control Engineering, CFE Media, email@example.com.
- Object-oriented programming (OOP) is about organization and simplification.
- Function blocks can define methods and properties to further partition the code and extend the interfaces.
- Object-based design is about choosing which entities to model.
What other ways can OOP be used?
The example project was created using Bedrock Automation's integrated development environment (IDE) which is available as a free download from their website.
The example project's source code can be downloaded from Mitek Automation's website.
See additional stories about PLC programming linked below.