Some of the guys at the office just got back from a SoMachine Motion CODESYS session in Germany. One of them noted a CODESYS tip/trick to change the variable name prefixes or suffixes that will save programmers a lot of time and tedious work.
Holding down the Alt key allows for a vertical highlighting feature.
From the example above:
Changing the word ‘Read’ to ‘Write’ can be done in one quick update for the entire list:
This is useful for common parts of a variable name, like above. Other examples may include:
Change user defined data type names on a set of assignments.
Adding a prefix to a mirror set of variables- e.g. SCA to variables shared with a SCADA system.
Look out for:
‘Copy and paste’ ( Ctrl-C, Ctrl-V) is a large source of PLC program bugs and errors. Severalarticles on programming cover the ‘copy and paste’ issues in depth. A cool feature like this Alt-key highlighting might feed the problem.
As such, practice caution. Saving a few minutes in tedious work is good as long as it doesn’t cause hours of troubleshooting later. Follow through with a visual check to pick up errors. Copy and paste does not negate the need for System 2 thinking which is the conscious and logical thinking instead of the subconscious and automatic thinking.
Having said that, this is one CODESYS trick I wished I had learnt a few years ago. Thank you, Jared.
There are many ways to implement variable declaration in CODESYS. It can be easy to forget the syntax or specifics on some of them. This post covers them for reference. Also, a couple of programmer cautionary comics from XKCD at the bottom… 😀
Variable Declarations:
VarName : INT ;
Variable with located memory address
VarName AT % MW123: INT;
Variables with Initial Value:
VarName : INT := 23;
Variable initial values can be tied to another variable of the same data type:
VarName: INT:= VarName2;
where:
VarName2:= INT;
Declaring STRING with defined length:
VarName2 :STRING(40);
With the above, a string of 40 characters is created. Each character is one byte.
Declaring STRING with initial assignment:
VarName :STRING:= ‘HELLO WORLD’;
Declaring Arrays with Initial Value:
Array1: ARRAY[1..5] OF INT := [1,2,3,4,5];
Without initial value it would just be:
Array1: ARRAY[1..5] OF INT;
Some other notes about arrays:
The first element can be element zero, i.e.
Array1: ARRAY[0..5] OF INT;
Multi-dimensional Arrays:
Array1: ARRAY[0..5,0..2] OF INT;
Array1: ARRAY[0..5,0..2,0..4] OF INT;
Declaring Pointers:
PointerToStrArray : POINTER TO STRING ( 9 );
Declaring Pointers to Arrays:
PointerToStrArray : POINTER TO ARRAY[1..10] OF STRING ( 9 );
In both the pointer examples above, the pointer values can be loaded with the ADR function. More on that here.
Declaring Function Blocks with Inputs:
Declaring an OFF delay timer from the Standard library with an initialized preset time
OffDelayTimer: TOF:= (PT:=T#2S);
The above declaration method can also be used with the preset time tied to another variable of type time:
OffDelayTimer: TOF:= (PT: = PresetTime);
where the PresetTime is declared as follows:
PresetTime: TIME := T#2s;
One of the positive points of a textual variable declaration area is the option to copy and paste. In some programming environments, the alternate to a textual declaration is a tabular or table based variable declaration area. Some table based ( or tabular) variable areas might include a pull-down menu of options for each declaration. This may help someone who is beginning to learn in an environment.
Nevertheless, in the long term, textual declarations are more flexible. Another benefit is opens up the option to generate the variable declaration externally- in Excel for example. The external declaration is useful for larger projects with multiple programmers. In Excel, a name can be created and multiple versions of a variable generated with prefixes or suffixes to that name. One example may be:
For a variable called SysRun:
The local variable could be SysRun_Local
The status to be fed to a SCADA system could be SysRun_SCADA
Instead of typing out: SysRun_Local: BOOL; and SysRun_SCADA: BOOL; , the entire declaration process can be automated in Excel and then copied and pasted into CODESYS.
To wrap up for now..
Comments in variable declaration field are important. It helps the next person who reads the code/program. It might even help you make sense of your work, in the future. Also, for function blocks, the comments on the same line as a variable become the description of input pins when the cursor hovers over a pin.
There are probably other useful points and methods of variable declarations in CODESYS that are not included here. If one comes mind, please comment below.
The PLC programming quickstart checklist is intended for a user to learn a new PLC programming environment. This applies to users who have programmed PLC’s before and also for someone new to PLC’s. Continuing from part 1 with checklist item 3:
3. Program logic
This is where the code is going to be.
IEC 61131-3 is the reference standard for PLC programming languages. In 2016, all major PLC platforms have some level of compliance to this standard. The standard does allow for partial compliance and requires manufacturers to declare specfics of their compliance with a statement. A quick introduction to the standard is available at the PLCopen site.
Per the standard, logic can be written as one of the following 3 types of program organization units (POU’s):
Programs
Functions
Function Blocks
PLCopen covers an overview of these types in a presentation here.
Adding these POU’s to the program usually occurs on the left side of the screen. There are some differences on how this is done in various environments.
In SoMachine which uses CODESYS V3, a POU is added by right clicking the Application directory and selecting Add Object>> POU. Subsequently, the option to add a Program, Function or Function Block pops up.
The POU types and options do vary in terminology and operation from platform to platform. In CCW, the Programs are added under the Program directory header. Function blocks are added under a separate header called User Defined Function Blocks.
When adding a program, the user is usually prompted to define the language chosen for that POU. When playing with a new environment, here is where you will find out the languages supported ( other than in the literature).
It would be advisable to select the different languages and test drive them. At the very least, select the language you will use and play around with the development environment. A later part will cover the specific items to look for in the language chosen.
Some questions to ask, that does vary from platform to platform is:
Can a program call another program?
When a function block is updated, does it automatically update every instance?
Can program execution order be arranged?
The final question takes us to checklist item 4…
4. Task Configuration
The importance of a ‘task’ is that it gives the PLC programmer control over what parts of the code to run and when. Task configuration covers the order , timing and triggers of execution. For example,
A cyclic task may be configured to execute every 20ms.
An acyclic, freewheeling task may be set to occur per the processor execution cycle for the POU as defined.
An event triggered task may run only when an input is triggered.
If a part of the code needs to have a higher priority over other parts, it may be defined in a task of its own. It could also be set to execute with a shorter cycle time, if required.
SoMachine tasks are configured under the Task Configuration header. Multiple tasks can be defined with the number varying based on the specific PLC used. CCW does not have a specific task configuration section. Programs noted in programs section are executed in order. The order can be changed, as required. CCW does have an interrupt option that can be used to trigger specific logic as required.
Key takeaway here is to note the differences in the number of tasks and sequencing options for programs/POU’s in various environments.
Most control engineers and PLC users are going to encounter several PLC platforms over a career span. Whether through jobs at different companies or through migration of control platforms, the need to adapt and learn new programming environment is an essential part of the job. As I go through this process with a new platform, the following checklist was developed as a ‘quickstart guide’ when programming in a new PLC platform.
The good news is that most PLC programming platforms use a very similar set of features. The features are called using different names by different vendors. In many cases, even the layout of the program is similar. There is usually a directory on the left side of the screen, a message window at the bottom…etc.
So, this post will be Part 1 of a multi-part series about the key things to look out for in a new PLC programming environment. The way this will be set up is as follows:
Several programming platforms will be referenced in examples; SoMachine (CODESYS), SoMachine HVAC and Rockwell CCW. I’m very familiar with SoMachine and CODESYS, new to SoMachine HVAC and never used Rockwell Automation’s CCW before.
The intent would be to get proficient enough in a new environment to write simple to intermediate programs. We will save more advanced features for another discussion.
I/O Declaration
The basic function of a PLC is to be able to accept inputs and control outputs. In most current PLC programming environments, the inputs and outputs are referred to in the logic using variable/tag names or pre-assigned terminal designations.
If a PLC program is to be looked upon as a story, the main characters would be the variables and the I/O. They are the subject.
So, the key questions when encountered with a new environment is:
Where are input and output variables or tag names assigned?
How are they called in the program- pre-assigned name or user-defined names?
Common approaches:
The I/O tags or their user assigned tag/symbol names are declared in one place and then available to be called throughout the program. They are essentially similar to global variables.
Some of the terms used for these names include symbols (CODESYS), tags (often used in SCADA environments and aliases (alternate references to a I/O point in Rockwell controllers)
In SoMachine the input and output mapping can be addressed using either the address assigned to the terminal input( this is referred to as direct addressing) or a user-defined symbol name.
In CCW, I/O is addressable in code using either the pre-assigned name or an alias.
Between the pre-assigned name and the user-defined name, both are usable in this case. With the usage of the pre-assigned name in SoMachine, a pop-up usually occurs to advise the user to use symbolic addressing for ease of maintenance and modification.
Variable declaration
Once the I/O is declared and accessible in the program, the next point of interest would be to figure out where and how variables are declared. Some variables can be pre-planned if we know the functions they will be plugged into. Others may be added on the fly.
The two main types of variables are the local and global variables. Local variables can be called from the POU that it is declared in. Global variables are accessible anywhere in the project.
Some environments allow for variables to be declared textually. Others require a tabular declaration with a pull down for the data type. The textual declaration may involve a little more typing, however, the benefit is that it is more flexible and supports copy and pasting variable names. For larger projects, variables can be created in a spreadsheet separately and then pasted into the PLC program project. The benefit of a separate variable creation is that variations of the variable name for SCADA purposes and also the generation of memory locations can be performed easily and quickly in a spreadsheet.
For textual declarations, observe the syntax used for various data types. Some key questions here are:
How are variables given an initial value?
How are persistent or retain variables created ( to keep values through power cycles)?
How are arrays declared?
Regarding the point about retain and persistent variables. In CODESYS, the retain variables holds a value through power cycles. Persistent variables hold a value through program downloads.
In SoMachine, retain variables are declared using the VAR_RETAIN header in the variable declaration section.
Variables to be kept through program downloads are declared in a separate object.
Next part will cover the program types or POU’s as referenced by the IEC 61131-3 standard…
A couple of previous posts covered sorting CODESYS arrays and using them with pointers. There was never a preface to the topic of arrays. So, this is a stab at clarifying the definition and application of CODESYS arrays.
What and why of arrays?
An array is an set of data. It could be a collection of numbers or a collection of custom data types. One analogy of arrays is a bucket with numbered containers in it., arranged from container 0 or 1 to container x. X being the length of the array. Each container can store some data.
The purpose:
Collect and organize data of a certain type.
Data in an array can be called with a common namespace.
Makes it easier to sort data
Easier to do math on a set of data points
In the memory layout of a PLC, array elements are usually stored in contiguous ( back-to-back) memory locations. This has some benefits for retrieval when reading from another PLC, HMI or SCADA system.
How are they used?
The basic declaration of an array:
TestArray : ARRAY[1..5] of INT;
It also offers the option of initializing the element values in the declaration:
TestArray : ARRAY[1..5] of INT:= [5,3,2,5,2];
Array lengths can be defined using a variable in the declaration. That is to tie the array size to a variable name instead of a fixed number in the declaration. NOTE: The variable has to be declared as a VAR CONSTANT and can not be altered in runtime. The value of the VAR CONSTANT variable needs to be declared and initialized with a constant value in the programming environment. The IEC 61131-3 standard also makes reference to this point. So, the feature of using a constant in the declaration of array length only serves to centralize the location of initial setup of parameters, if required by the control program.
TestArray : ARRAY[1..UserDefinedVarLength] of INT:= [5,3,2,5,2];
VAR_CONSTANT
UserDefinedVarLength : INT:= 5;
END_VAR
The above as noted in the CODESYS environment:
CODESYS Array declaration in the actual declaration window
CODESYS Arrays can be multi-dimensional. That is, they can have more than one attribute and form a matrix. Multi-dimensional arrays are declared as follows:
An example application with a visual representation of the multi-dimensional array above could be as follows:
CODESYS Functions that can be used with Arrays:
There are a number of functions that can be used with arrays. Often times, for organizing and sorting data in arrays, pointers are used. Other than that, the following are some functions and their applications to arrays:
SizeOf
This function returns the number of bytes reserved for an area. If an array is made up of INT datatypes, each element would take up 2 bytes. The total number of bytes would be number of elements times 2. For REAL datatypes it would be a multiplier of 4.
CheckBounds
This is added as an implicit check. It shows up as ‘ POU for Implicit Checks’ when Add Object is selected and check arrays during runtime to determine if any code is attempting to access array elements that are outside the declared range.
NOTE: Sum and arithmetic functions ( ADD, MUL, SUB…etc) usually accept INT, REAL’s and ANY_NUM type inputs. As such, feeding an array to the input of a math function will usually result in an error. Arrays have to be broken out to individual elements to be manipulated and used for number crunching.
To wrap up, a video on arrays in CODESYS from Kurt Braun’s YouTube channel
There are probably a number of functions related to arrays that folks out there use. If you know of one, please share in the comments section below.
Resources: Staying on the topics of arrays, the following articles are on the same topic:
The ability to connect to a PLC remotely (or HMI) and to pull data, access webservers and download programs is increasingly a requirement on industrial automation projects. Remote data access and program maintenance saves travel time to sites and simplifies daily operations. Some of the PLC features that enable this are:
Webserver on PLC and HMI: Allows data monitoring and some updates to PLC configurations
WebVisualization: These are customizable user interface pages that are embedded in the PLC. WebVisu is the CODESYS term for these HTML5 pages. Some examples of their usage from YouTube are noted here.
PLC Programming software remote gateway support: This is the ability for a PLC programming software to connect to remote Ethernet based devices. This could be for program downloads or regular program viewing.
This article will cover the steps for remotely connecting from the SoMachine PLC programming software to a remote M241 PLC. The InHand Networks IG601 cellular gateway device is used as the intermediary. Other examples of intermediary gateway devices may include Netbiter by HMS and eWon ( also by HMS now I believe).
Over the last few years, the criteria I have laid out for these devices have included the means to use them without the manufacturer’s cloud- based connection service. Simultaneously, keeping the option to route more secure connections through the cloud service, only when required, is a plus.
The criteria for the gateway device:
Ability to setup port forwarding at the gateway device
Ability to use a VPN connection for secure PLC program downloads
Ability to support a static IP at the gateway device and allow for the above mentioned VPN connection at the same time.
The InHand Networks IG601 meets these criteria. Getting this set up can be accomplished with two sets of steps. The InHand steps and the SoMachine steps.
Install Device Touch on the connecting PC. The installer is available in the Device Cloud portal. The next steps will assume proper setup of the Device Cloud and connection using Device Touch on the local PC. Instructions on Device Touch are available at the following link.
NOTE: While in the Device Cloud, be sure to set up a site, a device and the PLC. I forgot to add the ‘Controller’ once. It took some time and a call to InHand’s support team to figure it out.
Open Device Touch on your computer and connect with your Device Cloud account. Once connected to the cloud. Connect to the specific site/gateway but selecting it and clicking on the ON/OFF slider bar.
SoMachine Steps
In SoMachine, configure connectivity in the SoMachine gateway. The gateway is accessible by double clicking on the root of the controller directory in the device tree.
5. The connection method is set to IP address. In the example, the remote controller IP address was set to 10.0.0.100 with a subnet mask of 255.255.255.0
6. Per step 3 above, if Device Touch is active and the Maintenance Channel is on/ready (screen cap below), go to the Online menu and select Login.
NOTE: The update key on the gateway will not result in the detection of the controller in the Gateway list. Entering the IP address and selecting ‘Login’ actually triggers the process if searching for the device and placing it in the available controllers list in the Gateway. The Update button in the Gateway may not find remote devices. As such, the remote PLC may not show up even if by clicking on the Update button.
The gateway will scan the remote network via the Device Touch adapter. Once the controller has been found, it will show up on the controller list in the gateway with a REM icon next to it.
Note: The standard warning message indicating the pending connection to a controller will pop up prior to an actual login. Entering Alt-F will proceed with the connection and potential remote download of a program. Clicking the Cancel button will abort the connection.
Troubleshooting tip:
Should the remote controller not be detected using the IP address connection method above, restart the SoMachine gateway as shown in the screen cap below. Subsequently repeat step 4 above.
Should questions or comments arise, put it in the comments section below.
A CODESYS Visualization or Viz, is a way to embed a graphical interface into a PLC program. Interfacing with the PLC programs visually allows for quicker troubleshooting among other benefits. Further to that WebVisualizations publish a CODESYS visualization in HTML5. This enables user access to a PLC visualizations via a web browser.
Several examples of Visualizations and WebVisualizations exist online. Visualization and WebVisualization screens are created with drag and drop objects which are configured instead of coded. This simplifies screen development instead of having to build Java or HTML based objects for web accessible screens on the PLC.
The collection of YouTube based Visualizations highlighted below showcase the possibilities with the various screen objects across various applications – some industrial and some exemplar/illustrative.
The first example is of an elevator application built in CODESYS. Credit to donkeykowng on creating this for a school project.
The next example is of an industrial mixing process with multiple tanks with levels updated dynamically. Credit to tweektweak23.
More recent update of Codesys includes support for multi-touch. (from CoDeSysMotion YouTube page)
A key benefit of a visualization is that it allows for parts of the PLC program to be graphically represented and viewed without the PLC programming software. This is given that the programmer or designer of the system designs and embed appropriate visualizations to represent the system. Being able to pull up a graphical representation of the system on a PC/tablet/phone browser allows for preliminary troubleshooting without too many people having to have the programming software license . If the problem is beyond wiring , mechanical or I/O issues , then someone with the programming software can be dispatched.
Patterns in PLC Programming: The threshold + timer function – Debounced Threshold
PLC programs are frequently made up of the same sets of functions or patterns of logic. These patterns perform commonly required control routines. Examples include threshold detection for alarm purposes, input/output mapping and scaling functions, to name a few. These combination of functions make up re-usable patterns or function sets that form the building blocks of a PLC program.
Repeated usage of some functions in a PLC programming environment holds true to the universal 80/20 rule ;20% of the functions available in a programming environment( such as timers and logic functions) would probably be used to build 80% of PLC programs.
The debounced alarm/threshold pattern is one of these commonly required PLC programming patterns. This pattern is probably better written in ladder diagram (instead of any of the other 61131-3 languages), for two reasons:
Maintenance personnel will be able to view the status of the process/monitored variable, associated timer and output all in the same place
It can be programmed in 2 rungs of ladder compared to more than 10 lines of code.
The ladder diagram version could look something like this:
Alarm ACTIVE
Note: An Auto/Manual Reset Provision is built into the Alarm Reset Timer rung.
Alarm NOT ACTIVE
The following pattern is the debounce pattern for detecting limit breaches along with a timer, written in Structured Text for the CODESYS environment. As described above, the structured text version takes more space and possibly looks more intimidating specifically to someone who is used to the ladder environment.
The plain text version of the structured text version is attached below:
PROGRAM DeBounced_Limit
VAR
irProcessValue : REAL; (*Process value scaled from analog input signal*)
rProcessLowLimit : REAL; (*User defined process value low limit alarm threshold*)
The CODESYS language supports the usage of pointers which is essentially a variable that stores the location of another variable or data point instead of its value. The actual value of a variable that a pointer points to can be retrieved by dereferencing the pointer.
What could it be used for?
1.Storing the location of the variable saves space specifically when pointing to large data points or structures.
Pointers allow for sorting and re-arrangement of data sequences without actually changing the location of the original data points. To characterize in a diagram:
Going down the path of object oriented programming in PLC’s/PAC’s, this supports abstraction by separating the usage, manipulation and parts of an object from the original object itself. This helps reduce the PLC code required to handle every scenario and also helps in situation where the original object can not be manipulated because its hardcoded to an input ( for example).
Example:
Let’s say the array of data on the left side of the diagram above is read (as inputs) from a set of 4 drives controlling 4 pumps. From top of the array to the bottom Array location 0 would be for Pump 1 , location 1 for Pump 2 …..location 4 for Pump 4.
If the data is each of the pumps runtime, the pointers to the runtime allow for it to be sorted and stored in the pointer of arrays without changing the order of the original array which is important, as the original array of runtime data may be hardcoded to the actual input or read values from the drives.
Secondly, when the decision is made to call a pump to run, the same mechanism of pointers and arrays and de-referencing can be used to point to the command word of each of the pumps on a communication bus.
The end result is the amount of code required in determining which of the pumps to run is reduced.
What does the syntax look like in CODESYS?
To create a pointer:
The address operator or ADR is used.
Let’s say the variables are:
PROGRAM PLC_PRG
VAR
j: INT;
k:INT;
pointToJ: POINTER TO INT;
END_VAR
The pointer assignment would be:
in plain text:
pointToJ:=ADR( j);
Note: ADR is a CODESYS operator and not an operator prescribed in IEC61131-3.