Join us today!
[Solved] Utilizing Properties in TwinCAT 3
I'm new to OOP and hope to use more of its principles in the future. While creating function blocks for my programs, I started to consider using properties to practice the OOP methodology. However, I feel that much of the data that I want to pass through properties can just as easily be VAR_IN and VAR_OUT variables.
How does one determine when to use properties within their function block? Thank you for your assistance!
That's a great question! Before giving a simple example, it would be useful to explain a few things. Properties enables you to hide the data in your function block. This is called encapsulation, which is making sure the 'sensitive' data is hidden from the users. To achieve this, you use 'private' access specifiers.
There are 4 access specifiers you can use in TwinCAT 3:
PUBLIC It doesn't restrict anything and the property or method can be accessed outside the function block.
PRIVATE The property or method can be accessed only within the function block. No outside access is allowed. (Encapsulation)
PROTECTED Access is allowed only within the 'inheritance family'
INTERNAL Access is limited to the same library (namespace).
Properties have two methods called getters(read) and setters(write). They are called as accessors together. You can declare local variables in these methods, however their values get lost on exiting. No input or output declaration is allowed in property accessors. If you want your property to be read only, you can delete the set method and if you want it to be write only, you can delete the get method.
In the get and set methods, you can implement scaling, error check, range check or unit conversion functionalities.
For example, let's imagine you have a 'Pick' function block in your application.
For this function block, you want to get the start position, end position and the velocity data from the user. The start and the end position need to be within a certain range, if not you would want to raise your error flag. You can implement 'error check' inside the 'Set' method of these properties as below:
FB_Pick
In the function block, we have 3 internal variables which is set by the user through the properties and 1 struct output.
FUNCTION_BLOCK FB_Pick VAR_INPUT END_VAR VAR_OUTPUT stError : ST_Error; END_VAR VAR fStartPosition : REAL; fStopPosition : REAL; fVelocity : REAL; END_VAR
StartPosition Property, Set method:
We are checking if the provided start position is between 0 and 50 before passing the user data to our internal data (fStartPosition). If it is not within the range, we are setting the error flag to notify the user.
IF StartPosition > 0 AND StartPosition < 50 THEN fStartPosition := StartPosition; stError.StartPosError := FALSE; ELSE stError.StartPosError := TRUE; END_IF
StopPosition Property, Set method:
We are checking if the provided end position is between 250 and 400 before passing the user data to our internal data (fStopPosition). If it is not within the range, we are setting the error flag to notify the user.
IF StopPosition > 250 AND StopPosition < 400 THEN fStopPosition := StopPosition; stError.StopPosError := FALSE; ELSE stError.StopPosError := TRUE; END_IF
For the Velocity property, let's assume you want to implement error check and also scale the velocity. When you need to change this range or the scaling, all you have to do is to change the implementation in this set method. You wouldn't have to change anything for your internal variable.
Velocity Property, Set method:
We are checking if the provided velocity value is between 0 and 100 before passing the user data to our internal data (fVelocity). We are also scaling this value (fVelocity := Velocity/2)
If it is not within the range, we are setting the error flag to notify the user.
IF Velocity < 0 AND Velocity < 100 THEN fVelocity := Velocity/2; //Scaling stError.VelocityError := FALSE; ELSE stError.VelocityError := TRUE; END_IF
When no access specifier is used for the property, it is treated as public. For some reason, if you don't want users to provide these data in the future and you want to hide them you can simply add the 'Private' access specifier as below:
PROPERTY PRIVATE Velocity : REAL
Users can access these properties simply using dot (.) after typing the function block name ;
fbPick.StartPosition, fbPick.StopPosition, fbPick.Velocity
Adding the additional layer by using properties gives you the ability to implement extra logic before passing the user data to your internal data and also giving you the flexibility to change the protection of your internal data.
I hope this helps!
Hi @ilyasskure, thank you for the great reply. From your description, it seems like there are potentially two advantages to be gained by using properties instead of VAR_INPUT and VAR_OUTPUT.
The accessors Get and Set can be helpful to add read and write protection to variables within a function block. To me, this is the same as declaring a VAR_INPUT (write or Set) or VAR_OUTPUT (read or Get). However, the major benefit is to verify or alter the data coming in via the property before using it in the function block. I can see the usefulness with this aspect.
The other item you hit on is that properties can be made private. This will prevent anything outside of the function block from editing the data though this now makes me feel that it can be described as a VAR type of variable. How would the accessors be used then? Furthermore, if a property is made private and no outside influence is allowed, why create the property?
If I have misrepresented anything, please let me know. Thanks for your help!
@time2learn You're welcome! So glad to help! If you are 100% sure that the variable inside the main function block will be used only within the function block itself, you can declare it as VAR type of variable. However, if you change your mind in the future, users won't be able to access those variables even the inherited function blocks. If you use a private property instead, you could maybe change the access specifier to 'protected' type later so that the inherited function blocks can utilize those as well.
Another thing worth mentioning is that VAR_IN and VAR_OUT are not possible when creating interfaces, you can use properties to define your interface.
Additionally, if you are using a graphical language (ladder logic, continuous function chart) in your plc logic, you would see the inputs/outputs directly at the box of the function block. If you use a property instead, you would not see them and you would need to assign them separately.
@ilyasskure Thanks for adding more insight. I suppose there is a time and place for each one. I'll learn when and where each is best suited as time goes on.
Hello,
firstly, thank you for this explanation. It is very helpful.
Secondly, I would have one question. I have been working on new library based on OOP principles with properties as you mentioned above, but I am struggling with data exchange (parameters for motors, cylinders, axis etc.) with HMI visu. All these parameters were created as properties, but then I decided to use structures for each type of these function blocks (ST_CylinderPar) as INPUT. These structures will be defined as GVL and linked to HMI.
Would you have any better solution to keep the OOP principles ?
As example: FB_AirMonitoring. Operator can enable/disable this function on HMI
@svatoslav-tosner Hi , thank you for your comment!
Have you tried creating a property with the return type as ST_AirMonitor?
Property AirMonitor : ST_AirMonitor
ST_AirMonitor :
ST_EnablePilotValve:
In the logic:
Declaration:
fbAirMonitor : FB_AirMonitor;
Assignment:
fbAirMonitor.AirMonitor := hmi.stAirMonitor;
In case you want to say thank you !)
We'd be very grateful if you could share this community with your colleagues and friends. You can also buy us a coffee to keep us fueled 😊 This is the best way to say thank you to this project and support your community.
twinControls - https://twincontrols.com/
-
Building a Property with Methodes similar to ipArguments of the TwinCat Event Logger
1 year ago
-
Auto Generation of Getters and Setters?
2 years ago
-
Using the Right Language
2 years ago
- 17 Forums
- 267 Topics
- 942 Posts
- 0 Online
- 722 Members