TwinCAT 3 Tutorial
This is an in-depth tutorial on Beckhoff’s TwinCAT 3 PC-based automation software.
Twin cats?
The tutorial is organized into a chapter format and is meant to be read like a book. Start here with the Table of Contents:
1.
Introduction
2.
Quick Start
3.
Structuring PLC Data
4.
Persistent Variables
5.
Structuring PLC Logic
6.
Multiple virtual PLCs
7.
Ladder Logic Editor
8.
Writing your own Functions and Function Blocks
9.
Structured Text
10.
Building an HMI in .NET
11.
Introduction to Motion Control
12.
Introduction to TwinSAFE
13.
The Scope View
1 - TwinCAT 3 Tutorial: Introduction
In the control system industry we’re used to slow progress. PLCs lag behind PC technology by ten years or more, and we pay an outrageous premium for PLC hardwarecompared to the technology sitting on our desktop in our offices.
Beckhoff has always pushed PC-based control systems based on commodity hardware like Intel x86 processors and Ethernet chips. With TwinCAT 3, their flagship automation software now supports multi-core processing, which leaves traditional PLC technology so far behind it’s not even funny.
On all new TwinCAT 3 PLC programs I start, I set the task to run every 0.5 ms by default, and I could run most of them much faster. Not only does the PLC logic execute every 0.5 ms, but the EtherCAT I/O bus for a reasonably large machine can also run at this speed. When you compare this with a traditional PLC with typical logic scan times (plus I/O refresh times) in the tens of milliseconds, you can see that TwinCAT 3 with EtherCAT is far better suited to any high speed process than your typical PLC.
If you think scan times don’t matter, consider a conveyor line running at around 1 m/s (completely reasonable) and you have to fire an output as a specific point on the conveyor passes a given location (measured by an encoder). The difference between a 1 ms reaction time and a 10 ms reaction time is the difference between 1 mm and 10 mm accuracy.
The TwinCAT 3 solution also offers many advantages over the traditional PLC/HMI/Laptop combination we’re familiar with:
•
The development environment runs on the same machine as the PLC logic, so you don’t need a separate laptop. Going online is as simple as opening the development environment and clicking the Go Online button.•
The HMI runs on the same machine as the PLC, so HMI-to-PLC communication responds incredibly fast. Transferring data between the TwinCAT 3 runtime and the HMI is as fast as a memory copy instruction. I’ve been able to transfer hundreds of kilobytes of data from a PLC array to a .NET application in a fraction of a second.•
If you’re into writing your own HMI software (for example in .NET), the driver for the protocol (called ADS) is included for free.•
The TwinSAFE safety editor is integrated into the development environment, so mapping signals between your safety program and your PLC program is trivial, and safety inputs can also be double-mapped both to the safety program, and to your PLC program for monitoring and alarming.•
You can use source control applications like git, mercurial or subversion, and they can even integrate with the development environment.Not only does TwinCAT 3 offer outstanding performance, but you can download it, install it, and try it out indefinitely for free! When you try to activate your first TwinCAT 3 PLC program, you’ll be prompted to generate a 7 day trial license. When that 7 day trial license expires, if you’re not done testing, you can just generate a new 7 day trial licensewithout
reinstalling. Obviously you wouldn’t be able to run this in a production environment if you had to do this every 7 days, but
the trial is a fully functional version of TwinCAT 3. Want to try something on your test bench before you commit to implementing it in production? Just install the trial version on an old PC and test it out.
I’ve been a control system programmer for over 15 years, and I’m also a .NET programmer, but I’m a ladder logic programmer first and foremost. If you’re a control system programmer in North America, you’re likely familiar with Allen-Bradley’s (or Rockwell Software’s) RSLogix family of control software. There is no doubt that RSLogix has set the standard for ladder logic editors, and to be completely honest, no other editor comes close to the user-friendliness of their development environment, and I’m including TwinCAT 3.
Beckhoff is a German company and ladder logic just doesn’t seem to be popular on their side of the pond. TwinCAT 3’s ladder editor is a major improvement over the one in TwinCAT 2, but it still doesn’t have the polish you’d be used to if you’re coming from the RSLogix world. I guarantee you’ll be frustrated the first time you try it, but that’s why I’m writing this tutorial. In my experience, programming ladder logic in TwinCAT 3 can be just as productive as in RSLogix, and it doesn’t need to be painful. Also, keep in mind that TwinCAT 3 is very new and Beckhoff continues to support and improve it.
If you’re familiar with RSLogix 5000, you may find some of my examples familiar. I’ve tried to organize my TwinCAT 3 projects in a way that’s similar to how most RSLogix 5000 programmers would organize their projects. That made the transition easier for me, and I hope it will for you too.
2 - TwinCAT 3 Tutorial: Quick Start
This “Quick Start” is actually rather long, but it’s going to take you through downloading, installing, configuring, programming, building, activating, going online, forcing, and even making online changes to a TwinCAT 3 PLC program. When you’re done you will have a basic understanding of the TwinCAT 3 system and how it works.
Prerequisites
TwinCAT 3 can run on a plain-vanilla copy of Windows 7. As of June 2016, Beckhoff says TwinCAT 3 is fully supported on Windows 10 (with TwinCAT version 3.1.4020.0).
One of Beckhoff’s main product lines is industrial PCs and if you buy their industrial PCs, you’ll get a discount on the TwinCAT 3 license. Also, the license cost scales with the processing power of the PC. Their most expensive license tier is for “3rd party hardware”, which means any PC you didn’t buy from them. I have no opinion on whether you should buy a Beckhoff industrial PC or a commercial PC. One thing to keep in mind is that Beckhoff’s top of the line industrial PC won’t have quite as much processing power as the newest commercial PCs on the market today, so if you’re really concerned about performance, you’ll probably go with a commercial PC. On the other hand, industrial PCs are hardened against tougher environmental conditions like dirt and temperature, and they come in nicer form factors for mounting inside of a control panel. They also take a 24V input rather than running from the AC mains. Whatever you do, make sure you invest in a good UPS as well.
BIOS Settings
If you use a 3rd party PC, you may have to change the following settings in the BIOS:
•
Turn off Hyper-Threading (Intel Core-i7 specifically)•
Turn on Intel Virtualization Technology Extensions (VT-x), which is required for the 64-bit version of TwinCAT 3Optional: I/O
Whether or not you’re hooking up to a legacy system, or starting fresh, I highly recommend using an EtherCAT I/O bus. The performance is phenomenal compared to any other bus on the market today, including any other Ethernet-based technology, and even SERCOS. The price is also quite reasonable because the technology is based on commodity Ethernet hardware.
If you do want to go with EtherCAT, you can’t just use any Ethernet card in the PC as your bus master. It has to be an Intel chip, as that’s the only chipset that Beckhoff’s EtherCAT bus master seems to support. While you can buy a compatible card from Beckhoff, I’ve also had success with commercial off-the-shelf Ethernet cards. Your mileage may vary. For a list of compatible Ethernet chips, do a Google search forbeckhoff ethercat compatible cards or visit the
following
URL:http://infosys.beckhoff.com/english.php?content=content/1033/tcsystemmanager/reference/ethercat/html/ethercat_
supnetworkcontroller.htm
As of this moment, an Intel Gigabit CT PCI-E Network Adapter EXPI9301CTBLK is a reasonably priced commodity card
that works well.
If you want to try TwinCAT 3 without any hardware attached, you can do that too, and you won’t need an EtherCAT master at all.
If you do happen to need to interface to legacy I/O buses like DeviceNET, rather than installing a DeviceNET bus master card in the PC itself, I highly recommend starting with an EtherCAT bus to an EtherCAT bus coupler such as an EK1100,
and then buying one of the many different EtherCAT-to-whatever bridges that Beckhoff sells, as this is usually less expensive in the short run, and lets you expand your system with lower cost (and higher performance) EtherCAT I/O in the future.
Optional: Visual Studio 2010 Professional
If you’re already a .NET programmer then you may already have Visual Studio 2010 Professional installed. If that’s the case, TwinCAT 3 will actually install as an extension to VS2010. If you don’t have it installed, don’t worry; TwinCAT 3 will install the Visual Studio Shell instead.
You may wonder if you can use the free versions of Visual Studio such as Visual C# 2010 Express edition or Visual Basic .NET 2010 Express Edition. While you can have them installed, and you can use them to write programs that communicate with the TwinCAT 3 runtime, TwinCAT 3 won’t install as an extension to these products.
Downloading TwinCAT 3
The TwinCAT 3 installer is free to download, but it requires registration. Beckhoff periodically releases new versions, so to get the very latest, go to their product web page:
http://www.beckhoff.com/english.asp?download/tc3-downloads.htm
Click the TE1xxx | Engineering link under the Software section. Click on the TwinCAT 3.1 – eXtended Automation Engineering (XAE) link. Note that XAE includes the runtime (XAR) as well.
Once you register you’ll receive an email with download instructions. Download the .zip file and extract it to some temporary directory.
Installing TwinCAT 3
In the directory where you unzipped the downloaded TwinCAT 3 archive, locate the “exe” file and double-click it.
Follow the directions. Use the default options. When it prompts you about the Visual Studio 2010 shell, check the box to install it:
You will have to restart before it completes.
Create Your First TwinCAT 3 Project
Now that you have TwinCAT 3 installed, check in your system tray for a new icon:Just for reference, the color of the icon (blue) means the TwinCAT 3 runtime (PLC/motion controller/etc.) is in Config mode. That’s similar to “program mode” on an Allen-Bradley PLC. When the runtime is started the icon will be green. Red means it’s stopped.
Right-clicking on the icon will display a system menu:
Select TwinCAT XAE from the system menu. (The “E” stands for “Engineering.” That’s the programming environment.) After the splash screen you’ll see the Visual Studio Start Page:
Click the New Project+ link (highlighted) on the left side of the page. That will display theNew Project dialog:
I’ve only installed TwinCAT 3 without installing Visual Studio 2010 Professional, so you can only see one project type: TwinCAT XAE Project. If you have Visual Studio 2010 Professional installed,you’ll see all the regular project types,
plus this new TwinCAT XAE Project type. Make sure you’ve selected this type. Then give your project a suitable Name (see the highlighted field above). When you change the project name, the solution name will change to match. For our purposes they can be the same name. I chose “TwinCAT 3 Tutorial.” Click OK.
This could take a minute. It’s building a new TwinCAT 3 project from a template. When it’s complete you’ll see a screen like this:
All of the files for this project are organized in the Solution Explorer on the right. Here’s a brief explanation of each section: The top node in the tree is the “Solution.” This is actually a Visual Studio construct, not a TwinCAT 3 object. In Visual Studio, a Solution is a group of Visual Studio Projects and an associated “build order.” In our case there’s only one Visual Studio Project: TwinCAT 3 Tutorial. If you’re using Visual Studio 2010 Professional, you would be able to add additional projects under the solution, such as a C# or VB.NET project (perhaps an HMI or a data collection application?). This would be convenient simply because you could keep everything in one place and even use the integrated source control add-ins to manage everything in one environment.
Under the project you have:
•
SYSTEM: this section manages the runtime including the licenses. You can configure how many PC processor coresto use, which PLC or motion tasks run on each core, and what percentage of each core’s processing power to allocate to each task. Note that it’s possible to connect to runtimes on other computers, but for now we’ll only be concerned with the local runtime.
•
MOTION: this is where you add motion control tasks, and assign axes to each task. These tasks do the work ofclosing the control loops for you. Your PLC programs typically interface with the motion tasks using standard motion function blocks and the motion tasks do the heavy lifting of controlling the actual servo drives, etc. When you commission a new axis (setting up your motion parameters like speed, acceleration, deceleration, etc., you interact directly with the objects under the MOTION section of the tree).
•
PLC: this is where you add PLC projects. Each PLC project lets you define variables (memory assignment) and PLClogic.
•
SAFETY: if you’re using an EL6900 Safety PLC slice or the new TwinCAT 3 safety runtime (a certified safety PLC that runs on the PC itself), you can edit the safety logic here. This is handy because you can create connections between the PLC and the Safety logic for monitoring and status.•
C++: one of the big new features or TwinCAT 3 is the ability to write C++ code that executes directly in the runtime.•
I/O: this is where you configure your I/O network, and then create your mappings between all of the different modules.For example, if you define an input in the PLCmodule, you have to map it to a physical input in the I/O module.
TwinCAT 3 Solution File Structure
One of the interesting things about TwinCAT 3 compared to other PLC programming environments is that it stores the “solution” in a collection of files and directories rather than in a single monolithic file. If you open the directory where you asked it to create your solution, you’ll see the following:
The TwinCAT 3 Tutorial.sln file is your “solution” file, and it corresponds to the top level node in your solution explorer in the right hand side of your TwinCAT XAE window. TheTwinCAT 3 Tutorial folder corresponds to the TwinCAT 3 Tutorial project under the solution. If you double click on that folder, you’ll see a file called TwinCAT 3 Tutorial.tsproj:
If you’re inquisitive, you can open this file with Notepad (or any text editor) and look at the contents. You’ll see that it’s just an XML file. When you start to add a PLC program or a Safety program in the editor, you’ll then see new folders created here, and theTwinCAT 3 Tutorial.tsproj file will include references to these child projects.
In TwinCAT 3, a “PLC” is like a “virtual” PLC. You can run multiple virtual PLCs on a single computer. This might actually be useful if you had a single PC controlling multiple machines. Each machine could be controlled by a single virtual PLC, which might be a good way to manage the complexity of a large system. You can also separate virtual PLCs by CPU core, so if your scan time started to get too high, you could break out part of that logic and run it in a separate virtual PLC and schedule the task that runs that second PLC on a different CPU core. Two virtual PLCs can still send data back and forth by mapping outputs on one PLC to inputs on the other PLC, and vice-versa.
The simplest case is to create a single PLC project. Let’s do that now. Right-click on the PLC node in the Solution
Explorer (highlighted):
From the context menu that appears, select Add New Item+ to display the following wizard:
Enter a name for your new virtual PLC in the Name box (highlighted above). I chose “PLC1” but you may want to pick a more descriptive name, like the name of the machine or cell that this PLC will control.
Standard PLC Project is the default template, so leave that selected and click the Addbutton in the bottom right. TwinCAT
3 will build a new PLC project for you from a template. This could take a few seconds to a few minutes depending on the speed of your computer. When it’s complete, you’ll see your new PLC in the Solution Explorer:
It gets a little confusing to talk about the “PLC Project” now because there are so many nodes in the tree, so from now on I’ll call the nodes by their name: PLC1 or PLC1 Project.
Most of the interesting parts are under the collapsed PLC1 Project node, so click on the triangle next to that node to expand it:
Let’s go through them one at a time to explain their meaning:
•
External Types: you should never have to go in here, so don’t worry about it.•
References: this is where you add references to external libraries (either ones that are included in TwinCAT 3, suchas motion control libraries, or ones that you write yourself, which we’ll explain later).
•
DUTs, GVLs, POUs, and VISUs: these are just convenience folders that are created by TwinCAT 3, and it’s whereyou’re supposed to create your Data Unit Types, Global Variable Lists, Program Organization Units, and Visualizations, respectively. What do those mean?
o
Data Unit Type (DUT): this is similar to a structure or a user-defined type in other programming languages. It allows you to group a few pieces of data together into a single composite piece of data.o
Global Variable List (GVL): as the name suggests, this is a list of variables (memory locations) that will be accessible from everywhere in this PLC (but not other PLCs) and can be accessed from your HMI.o
Program Organization Unit (POU): contains logic (such as ladder logic, function block diagram logic, structured text, etc.) and associated local variables that are only accessible from inside that logic. There are 3 types of POUs: Programs, Functions, and Function Blocks, which will be explained later.o
Visualization (VISU): these are your HMI screens. TwinCAT 3 has a built-in HMI system that takes advantage of the fact that you’re already running TwinCAT 3 on a computer with a screen. This is an optional add-on (sometimes called a “supplement”). You have to pay extra for the visualization license if you want to use it in a production machine, but in my experience it’s a reasonable price. Note that you can also use 3rd party HMI/SCADA systems with TwinCAT 3, and you can write your own .NET program. The 3rd party solutions typically use OPC for communication, and .NET programs use Beckhoff’s free DLL that lets you communicate directly with the runtime using their proprietary ADS communication library.When you created the PLC project, TwinCAT 3 automatically created the first POU for you (a Program called MAIN). It did this so that it could automatically create a Task for you. To explain what this means, I’ve expanded a few more nodes in the Solution Explorer tree:
I’ve highlighted the important nodes, above. Under SYSTEM > Tasks, there is a new Task called PlcTask. A Task is what gets scheduled to run on the TwinCAT 3 runtime (that is, you can’t run a Program directly, you have to create a Task, and the Task then runs your Program). The Task has certain attributes, like how often to run. Double-click on the PlcTask node under the SYSTEM > Tasks node, and you’ll see this properties page for the Task:
Note the two highlighted fields above next to the Cycle ticks field. By default the task is configured to run once every 10 cycle ticks, and that corresponds to once every 10 ms. That means the TwinCAT 3 runtime itself is actually configured to “wake up” once per millisecond, and every 10 times it wakes up, it executes this Task. You can then configure what this Task does when it runs. TwinCAT 3 has already done this by linking PlcTask to the MAIN program in PLC1. That means our program called MAIN in PLC1 will be executed once every 10 ms.
Configuring the Real-Time
All of the editing we’ve been doing in TwinCAT 3 XAE is a normal Windows program, and Windows is a general-purpose operating system, not a real-time operating system. The runtime component of TwinCAT 3 (called XAR) has to run under real-time conditions so that it won’t be pre-empted by other tasks on the computer while it’s busy executing machine control logic.
The TwinCAT 3 runtime pre-empts normal Windows programs by running in “ring 0” execution mode. In Windows there are only two execution modes: ring 0 and ring 3. Ring 0 is “kernel” mode, which is where all drivers and some internal windows code runs, and ring 3 is “user” mode, which is where normal windows programs run.
The runtime registers a timer interrupt to force execution of the runtime at a regular interval (called the clock tick). Interrupt routines run under ring 0, or kernel mode, so the runtime has access to the full resources of the computer. The runtime then executes Tasks, and each Task can do things like run PLC Programs, do Motion Control, interface with the EtherCAT I/O bus, or manage communications with the HMI. These interrupts pre-empt ring 3 (user-mode) programs so the runtime always gets priority over normal Windows programs, like the TwinCAT 3 editor or your HMI.
To configure the real-time behavior of TwinCAT 3, double-click on the SYSTEM > Real-Time node in the Solution
That will display the Real-Time configuration window:
Notice that the “Available CPUs” shows only one CPU and it’s allocated to Windows. This is actually incorrect, because my computer is a Core i3 with 4 logical cores. Click theRead from Target button to make TwinCAT 3 read the actual configuration from the PC:
Now it correctly shows 4 cores. The cores are listed in the top list box, numbered 0, 1, 2, and 3. This configuration allows you to allocate cores between Windows, the TwinCAT 3 runtime, or both (or neither). I have found that mixing Windows and TwinCAT 3 on the same core might cause problems (at least in earlier versions of TwinCAT 3), so if you have a 4-core machine, I recommend allocating 2 4-cores for Windows and 2 4-cores for TwinCAT 3 runtimes. Changing this allocation requires a reboot, so save everything first.
Warning: only use the core isolation feature on Windows 10 if you have build 4020.0 or later. The “core isolation” feature is not compatible with Windows 10 in earlier versions. As far as I have been told, prior to build 4020.0, TwinCAT 3 won’t be able to see the cores set to “Other” and the only way to fix it is to use the “Reset this PC” feature of Windows 10.
If you have Windows 7, to change the core allocation, first click the Set on target button and the following window will pop up:
Here, we just set the number of cores available to Windows, and the remainder will be available to the TwinCAT 3 runtime. Change the number 4 to a 2, and then click the Setbutton:
Click OK to the confirmation dialog box:
Hang on while the system reboots. Once it has rebooted, open the TwinCAT 3 solution again (either by double-clicking on the TwinCAT 3 Tutorial.sln file wherever you saved it, or by opening TwinCAT 3 XAE again and selecting it from the Recent Files list.
Now double-click on the SYSTEM > Real-Time node in the Solution Explorer again, and the real-time configuration window will look like this:
Notice that CPUs 0 and 1 still say “Windows” but cores 2 and 3 now say “Other”. Now we want to configure the TwinCAT 3 runtime to use cores 2 and 3. Under the RT-CPUcolumn, check the checkboxes next to cores 2 and 3, and uncheck the checkbox next to core 0:
Notice that the CPU Limit column showed 80% next to core 0 when it was checked but shows 100% next to cores 2 and 3. That’s because when the TwinCAT 3 runtime has to share a core with Windows, we have to limit how much CPU time
it can use, so that Windows still has some time to run user programs. However, when the runtime has a core all to itself, it can use to up 100% of the CPU time on that core.
The lower grid allows you to configure which tasks run on which core. Currently there are only 2 tasks: PlcTask and PlcAuxTask. The first is the task that was created when we created the PLC1 project. The second is an automatically created “housekeeping” task. For now, both are set to run on core 2, which is a bit wasteful of core 3, but in most real applications there’s a good chance of using two real-time cores. If your application has any motion control, it’s typical to run the motion control task on a separate core, and if you had more than one virtual PLC, you can choose to run them on different cores to balance the load.
Next, check the Base Time columns in the grids above. By default, the TwinCAT 3 runtime “wakes up” every 1 millisecond and checks if it needs to execute any Tasks. You can optionally change the Base Time in the upper grid. 1 millisecond is actually the slowest option. I find that 0.5 ms (500 us) works quite well for most PLC tasks. Note that this is much faster than you’ll be used to if you come from a more traditional PLC brand.
In the lower grid, you can see that even though PlcTask is running on core 2 with a 1 ms base time, it only runs once every 10 Cycle Ticks, so it effectively only runs once every 10 ms. I normally set this to 1 Cycle Tick so the PLC task would run every time the runtime wakes up. Note that your I/O refresh is tied to the speed of the Task using the I/O. That means if you set your PlcTask to run every 1 ms, then any I/O mapped to that Task also has to refresh once every 1 ms. The EtherCAT I/O bus is actually fast enough to do this even with a rather large number of devices on the bus.
To change the PlcTask so that it runs every 1 ms, double click on the SYSTEM > Tasks > PlcTask node in the Solution
Edit the PLC Logic
Add a Global Variable List
Let’s assume we’re going to program a grinding machine. Perhaps there’s a grinding wheel that needs to be turned on and off via a motor starter. Let’s start by declaring some variables for our PLC to interface with the outside world.
Under the PLC1 project, right click on the GVLs folder (highlighted):
From the context menu that appears, choose Add > Global Variable List+
A dialog box will appear where you can enter a name for your new Global Variable List. Let’s enter a suitable name for this list, like Grinder:
Then click the Open button. This will do 2 things: it will add a new Global Variable List in the GVLs folder, and it will open the new Grinders GVL for editing. Your PLC1 project will now look like this in the Solution Explorer:
Rand the main editing area will now have a window open for editing the GVL:
An empty Global Variable List isn’t very useful, so let’s add some variables. You’ll have to type the following exactly correctly between the VAR_GLOBAL and END_VAR lines:
Note that I’ve created 3 variables, all of which are of type BOOL. The first variable (GrindingWheelMS) will represent the output for the motor starter that turns on the grinding wheel. The grinding wheel will run as long as this variable is on. The other two variables represent the inputs for start and stop pushbuttons (PBs) for the grinding wheel. We haven’t actually declared them as real outputs or inputs yet, but we’re going to come back to that later.
A BOOL value in TwinCAT 3 can take on two values: TRUE and FALSE. These variables can be used anywhere in the PLC program. It’s possible to create two Global Variable Lists that bothhave a variable of the same name. In that case, if you used that variable name in your program, when you tried to build your PLC
project, the compiler will
complain that the name is “ambiguous”. In that case you will have to prefix the variable name with the name of your Global Variable List. Due to this possibility, I always use the fully-qualified name (including the Global Variable List name) whenever I use a global variable in my logic, and I will do that in the rest of this tutorial. This is optional (and unnecessary) if you only have one GVL.Adding a Ladder Logic Program
Now that we have some variables to control, let’s write some logic to control them. Right click on the POUs folder in the Solution Explorer and choose Add > POU+
In the Add POU dialog that pops up, enter a name for the new Program (RunGrindingWheel), choose Program under Type, and at the bottom underImplementation Language, choose Ladder Logic Diagram (LD):
Then click the Open button. Your new Program will show up under the POUs folder in theSolution Explorer, and the Program will be opened for editing in the main window:
The editing screen is split into two parts. At the top is your list of variable declarations. These are similar to the variable declarations in a Global Variable List, but any variables declared here can only be used within this Program. It’s a useful place to declare variables for storing temporary values or helper coils. In order to write a simple start/stop rung, we won’t need to declare any local variables.
The bottom part of the screen is where you write the ladder logic. The numeral “1” indicates that it has already added a blank rung #1 for you. Let’s start by adding a coil to this rung. You can right click on the rung and choose Insert
Coil from
If you don’t see that toolbar, it might be hidden. Try right clicking on the blank toolbar spaces at the top of the screen and selecting the TwinCAT PLC FBD/LD/IL toolbar.
A third option is to click on the Toolbox vertical tab on the far left of the screen and drag and drop the coil icon from the toolbox over to the empty rung. Any of those options will result in a new coil being added to your empty rung:
Notice that the coil has three question marks over it. This is where you have to enter the name of the variable you want to assign to this coil. Type the fully-qualified name of the grinding wheel motor starter variable into this field: Grinder.GrindingWheelMS:
Now let’s add the start button. The easiest way is to click on the rung right where the small tick-mark is in the center of the rung, and then right-click and choose Insert Contact from the context menu. Now you will see a contact inserted on the left of the rung:
Then enter the fully-qualified variable name for the start pushbutton: Grinder.StartGrindingWheelPB:
That will turn the motor starter on when the start pushbutton turns on, but of course it won’t stay on unless we add a seal-in circuit. To add a branch around the start button contact, select the contact, right click, and choose Insert Contact Parallel
Edit the three question marks over the new parallel contact and change it toGrinder.GrindingWheelMS so that the coil seals itself in:
Now the motor starter will stay on after the start pushbutton input turns off, but it will keep running forever. Finally let’s add the stop pushbutton into the circuit as a normally closed contact. Select the section of rung between the branch on the left and the coil on the right (where the small tickmark is). Right click on this section of rung, and choose Insert Negated
Contact from the context menu:
Finally, replace the three question marks above the normally closed contact with the fully-qualified variable name of the stop pushbutton: Grinder.StopGrindingWheelPB:
Finally, our start/stop circuit is complete! Remember to click the Save All button on the toolbar (it looks like a stack of
three floppy disks).
Calling the Ladder Logic Program from MAIN
There’s one last thing we have to do before we can run our program. When the PlcTaskruns, it will only execute the MAIN program, not our new RunGrindingWheelprogram. To get our program to execute every 1 ms, we need to “call” it from the MAINprogram. Double click on the MAIN program in the POUs folder of the Solution Explorer:
That will open the program in the Structured Text editor:
This looks very similar to the RunGrindingWheel program when we first opened it, but in this case, everything in the bottom is in Structured Text (ST) language instead of Ladder Diagram (LD). If you want, you can delete the MAIN program and replace it with a new MAIN program that uses Ladder Diagram. You have to remember to link thePlcTask to this new MAIN program because when you delete the old one it will lose the link.
However, since the MAIN program’s only job is to call other programs (in our example), it’s simple enough to do this in Structured Text. Change line 1 of the MAIN program to the following:
That is, it’s just the name of the program you want to call, following by an open and a closed bracket, and finally a semicolon. All statements in Structured Text end in a semi-colon. You could add other program calls below this one on new lines if you wanted. The program will call them once, in sequence, every time it runs (which is once every millisecond).
Downloading and Going Online
Build the PLC Project
It’s a good idea to “build” the PLC project before you try to download it. This will tell you if you have any syntax errors or misspelled variable names. In the Solution Explorer, right click on the PLC1 Project node and choose Build from the context menu:
This could take a minute while it compiles the PLC project. At the bottom of the screen, there’s a tab called Output, and it will show you the progress of the compiler:
Take a look at the last line to see if there were any errors. You want it to say “1 succeeded” and “0 failed”. If it failed to build, you should look for error messages earlier in the output messages. Double-clicking on the error message should take you to the site of the error, or close to it.
Activate the Configuration
Now that our PLC project compiled successfully, the next step is to “activate the configuration”. What this does is:
1. Stop the TwinCAT 3 runtime (all running programs will halt, and I/O will turn off) 2. Apply the real-time configuration to the runtime (number of cores, tasks, etc.) 3. Copy the compiled program(s) to the runtime
4. Apply the “mapping” configuration (we will discuss mapping later) 5. Restart the TwinCAT 3 runtime in run mode
Note that when the runtime starts, it won’t automatically load the PLC program unless we “activate it as the boot project”, and it won’t start executing the PLC program unless we configure it to “autostart the boot project”. Do these two things by right clicking on thePLC1 node in the Solution
Explorer:
Rand then choose Activate Boot Project+ from the context menu, and then do it again and choose Autostart Boot Project. Now go to the top menu and choose TwinCAT > Activate Configuration from the menu. You will have to confirm this action with the following dialog box:
Click the OK button. Since we haven’t purchased a runtime license for this machine, it’s going to ask us if we want to generate “trial licenses”:
Click the Yes button. Then it will ask you to enter a captcha-type randomly generated group of characters to prevent you from automating the generation of trial licenses. Enter the letters in the text box underneath exactly as they appear (yours will be different than mine):
Then click the OK button. This generates a “trial” license which will expire after 7 days. Don’t worry too much about exceeding this 7-day limit though, as you can just generate another 7-day license when that happens. You will have to purchase an actual license only when you deploy to a production system.
After generating the trial license, it will ask you if you want to restart in run mode:
Click the OK button. You should see the TwinCAT icon in the system tray (if it’s visible) turn from blue (config mode) to red (stopped) and then finally to green (running). If that happens, the TwinCAT 3 runtime is running in run mode on your PC!
If you look at the PLC1 node in the Solution Explorer window, you will also notice that it now displays a green rectangle, indicating that the PLC program is running:
Go Online
Like most other modern PLCs, TwinCAT 3 supports online debugging. To see this in action, start by double-clicking on the RunGrindingWheel program so that it’s open in the editor’s main window. Then select PLC > Login from the main menu:
That puts the system into “online” mode and you can view the current state of the logic. Power is represented by the blue lines, and the status of the contacts and coils are represented by the blue rectangles in the middle of each. As you can see above, theGrinder.GrindingWheelMS coil is currently off, as are the start and stop pushbuttons.
Write Values to Variables (Online)
Even though the pushbuttons and motor starter variables aren’t connected to anything physical, the code is running. We can watch the state of the motor starter variable change by writing new values to the pushbutton variables. Let’s start by simulating someone pressing the start pushbutton. To do that, we’re going to write the value TRUEto Grinder.StartGrindingWheelPB. The first step is to queue a value to write. Hover your mouse over the center of theGrinder.StartGrindingWheelPB contact and double-click the small rectangle in the center:
Next to the contact you can now see a queued write value (“TRUE“). You can change the queued write value to FALSE by double-clicking it again, and remove the queued write value entirely by double-clicking it a third time. When you’re ready to write the queued values to the PLC variables, choose PLC > Write values to all online applications from the drop-down menu at the top of the screen. You will immediately see the state of the rung change to reflect the new value:
As you can see, simulating the start pushbutton turning on caused the logic to turn on the Grinder.GrindingWheelMS motor starter variable. Now let’s simulate releasing the start pushbutton by writing the value FALSE to the start pushbutton:
Rand write the values by choosing PLC > Write values to all online applications from the drop-down menu at the top of the screen:
You can see that the motor starter variable (coil) stayed on. To finish the example, let’s simulate someone pressing the stop pushbutton by writing the value TRUE to theGrinder.StopGrindingWheelPB contact:
Writing the value then turns off the motor starter coil:
Writing a value to a variable is a one-time operation, so if you tried to write the valueTRUE to the motor starter coil, it won’t appear to have any effect, because 1 millisecond later, the program logic will execute and change the value back to FALSE. If you want to override the logic, you need to use the “force.”
Force Variables (Online)
Forcing a variable is similar to writing a variable, except that the force overrides the logic of the program. For instance, we can force the motor starter coil to TRUE even though the logic is trying to keep it turned off. Start by double-clicking on the small rectangle in the middle of the motor starter coil:
You can see that we’ve queued the value TRUE, just like if we were going to do a variable write. However, in this case we’re going to choose PLC > Force values to all online applications from the menu at the top of the screen:
Forced variables are indicated with a small “F” in a red box next to the contact or coil that is forced. These variables will stay forced until you choose PLC > Unforce all values on all online applications from the menu at the top of the screen. You will also be asked if you want to unforce existing forces if you logout (go offline).
Using the TwinCAT PLC Toolbar
We’ve been going through the PLC menu at the top of the screen for all of the online functions, but there is also a toolbar that can give you quick access to these functions. It looks like this:
If you don’t see it, try right right-clicking on the toolbar area near the top of the screen and making sure that the TwinCAT
PLC option is checked. If it’s already checked and you can’t see it, then you might have too many toolbars on one line,
and that would force it to shrink the toolbar to almost nothing, like this:
If that’s the case, drag and drop the shrunk toolbar onto a new empty toolbar line and it will expand fully for you.
Making Online Changes to PLC Programs
TwinCAT 3 supports online changes to PLC program logic and variables.
TwinCAT 3 does not support online changes to the mapping between your PLC program and your physical I/O, so if you want to add or remove I/O, or you want to change the mapping between your PLC I/O and your physical I/O, you have to
use TwinCAT > Activate Configuration from the top menu, and you will then have to restart the runtime, which will restart your PLC programs. This will cause your machine to stop.
The process for making an online change to a PLC program is:
1. Make sure you are offline (logged out). 2. Edit your PLC program logic and variables.
3. Login (at the prompt, select Login with online change).
4. If you’ve edited a variable (for instance, changed the type), it will warn you that the variable will be moved to a new memory location, and ask if you want to continue. This is safe to do unless you have an external program (like an HMI or a data collection system) reading or write variables in the PLC, in which case you may want to shut them down before continuing.
5. Click Yes when it asks if you want to “update the boot project” (if you say No then your changes will be lost if you restart the runtime or reboot the computer).
Your changes will be applied without stopping the PLC program, and without any interruption to the machine.
Now let’s make a change to our logic. Stop buttons on machines are sometimes wired using a normally closed contact instead of a normally open contact (so the input is on when nobody is pushing the button and the input turns off when someone pushes it). The reason for this is so that the machine will stop if the wiring to the stop button is disconnected (and it also allows you to chain stop buttons in series). Let’s change our grinding wheel start/stop logic to work with a normally closed stop pushbutton. First, make sure that you are offline. Choose PLC > Logout from the menu if you haven’t done so already. Here is the original logic:
Left-click to select the contact in the middle (Grinder.StopGrindingWheelPB):
TwinCAT 3 has a handle shortcut for changing a normally closed contact to a normally open contact, or vice-versa: just press the slash key (“/”). Now your logic will look like this:
Login to the PLC by choosing PLC > Login from the menu. TwinCAT 3 will notice that the logic has changed and will ask you what you want to do:
Leave Login with online change selected and click OK. Next it will ask you if you want to update the boot project:
Click Yes. After that you will be online with the PLC, and your changes will be applied:
Notice that the Grinder.StopGrindingWheelPB contact is now a normally open contact, meaning the input has to turn off to stop the grinding wheel.
Designating PLC Inputs and Outputs
When we built our example PLC program above, we didn’t actually define which variables were inputs and which were outputs, so as far as the runtime was concerned, all of the variables were internal variables and the PLC didn’t interact with any physical I/O.
Designating a variable as an input or output only makes it available for mapping to a physical input or output during the mapping phase (after we’ve configured our I/O devices, which will be covered later).
We designate a variable as an input or output by modifying the variable declaration. Here is the original list of variables in the Grinder Global Variable List:
First let’s designate the GrindingWheelMS variable as an output. Change the variable declaration to the following:
As you can see, I’ve added AT %Q* directly after the variable name. The Q means output. You can designate the other two variables as inputs like this:
This is the same, but I’ve replaced the Q with an I meaning “input.” I know this is a weird syntax, but it’s a throwback to processors where you could (or had to) explicitly map variables to an input or output memory area. In this case, the asterisk means “I don’t care where you put it, just put it in the input or output map accordingly.”
Now you have to “build” the PLC project to see these variables show up on the PLC’s input or output map. Right-click on the PLC1 Project node in the Solution Explorer and choose Build from the context menu:
After the project is compiled, you will now see two new nodes under the PLC1 Instancenode:
Expand the inputs and outputs by clicking on the small triangle next to each node:
Now you can see the variables that you designated as inputs and outputs are available here for mapping. Normally you will map these variables to physical I/O, but they can also be mapped to I/O in the motion control task, the Safety program, or even to I/O from another PLC. That’s how you would be able to interlock two PLC programs together virtually without
running any physical wiring. The runtime takes care of copying the data between each task, or between tasks and physical I/O.
Beware that if you change the name or type of a variable that has been designated as an input or output, TwinCAT 3 will unmap that variable from any existing mappings, and will only give you a rather easy-to-miss message in the output window when the PLC project builds. When you activate the configuration and restart, you may be left wondering why your output won’t turn on, or why your start button isn’t working. Note that when you’ve mapped a variable, the icon will change to include a small arrow, so you can tell which ones are mapped:
(All I did here was map the PLC output Grinder.GrindingWheelMS back to PLC input Grinder.StartGrindingWheelPB, which is a rather silly thing to do in real life.)
Whew! That concludes the Quickstart chapter of this tutorial! You’ve now covered all the basics of downloading, installing, configuring, programming, going online, forcing, and making online changes to your PLC program in TwinCAT 3. That’s a lot of new information, but I hope it gives you a good enough introduction to feel like you can experiment and play around with the system some more. When you’re ready, you can move forward in the tutorial with more advanced topics.
3 - TwinCAT 3 Tutorial: Structuring PLC Data
TwinCAT 3 gives you a lot of options about how to organize the data (whether boolean, integer, floating point, string, or user defined data) in your PLC project. As with any PLC project, you want your data structures to follow naturally from the actual machine it’s controlling. I think we can all agree that Infeed.Conveyor.Running is easier to understand than bit[328].
Global vs. Local Variables
If you’re coming from the RSLogix 5000 world then you’re probably already familiar with the concept of global vs. local variables. A ControlLogix has “controller scope” and “program scope” tags. Essentially “controller scope” tags are global (because every program can see them) and “program scope” is local because only the program they’re defined in can see them. It’s also pretty common to come across PLC projects where all the tags are declared in “controller scope”.
TwinCAT 3 also has global variables and local variables. Global variables live in “Global Variable Lists” and Local variables live inside programs, function blocks and functions (a.k.a “POUs”). As for what should go where, that’s ultimately your decision, but here are the rough guidelines I use:
•
Inputs and Outputs: Global•
HMI Buttons and Indicators: Global•
HMI Alarms: Global•
Faults: Global•
Interlocks: Global•
Everything Else: LocalWhat do I mean by “Interlocks”? When you divide up your program, you typically divide it into modules that physically match your machine, so you might have a program for the Infeed Conveyor, one for the a Pick & Place, and one for a Robot. Most of your Infeed Conveyor logic shouldn’t care about the Pick & Place logic, except that you might want to prevent the Infeed Conveyor from running if the Pick & Place isn’t out of the way of the conveyor. In that case, you probably want to create a globalPickAndPlace.ClearOfInfeedConveyor variable. The Pick & Place logic is responsible for setting this using a coil, and the Infeed Conveyor logic uses it to prevent running the conveyor. This is an “interlock” signal and since two different programs need to access it, then it’s a good candidate for a global variable.
You’ll also notice that everything accessible from an HMI is also global. This is just my preference. You don’t have to do thatR an HMI can access local variables, but since an HMI-accessed variable is kind of like an interlock, I like to give them Global status. When someone is reading or modifying your PLC logic they’ll tend to make the assumption that Local variables are only accessed, wellR locally. That means when they want to make a change, they’ll only check
for usages
of the variable within that local scope. Checking the HMI for references to that variable is much harder. That’s why I suggest making HMI-accessed variables Global and also indicating with a comment that they are accessed from the HMI.
Global Variable Lists
When you created your PLC project in TwinCAT 3, the wizard automatically creates aGVLs folder:
“GVL” stands for “Global Variable List.” It’s Beckhoff’s intention that you should put all your global variable lists in the GVLs folder, but I think that’s incorrect. The organization and structure of your PLC project should mimic the physical and logical organization of your machine. Let’s continue our example of a machine with an infeed conveyor followed by a pick & place. If those are two major components of the machine, then that’s a logical way to break down our logic and data.
Let’s create two folders under our project called InfeedConveyor and PickAndPlacerespectively. Start by right clicking on the PLC Project node and selecting Add -> New Folder from the context menu. That will create a new folder called NewFolder1 and you can change the name to InfeedConveyor:
I want to stop here and talk about folder ordering. First of all, TwinCAT 3 will order the folders and
items in a folder alphabetically. Secondly, TwinCAT 3 has a bug where it will only re-order them
after you save your project, close the solution and open it again. Initially they show up based on
the original folder name, which was NewFolder1(hopefully this is fixed in a later version). Since
the folders represent the major components of our machine, we want the ordering to flow logically
from the way the machine works. If the machine works by parts being introduced to the machine
on the infeed conveyor, and are then processed by the pick & place, then it makes the most sense
to have the InfeedConveyor folder come before PickAndPlace folder. It just so happens that “I”
comes before “P” in the alphabet, but this is only a happy coincidence. That’s why I suggest
prefixing each folder with a number so you can enforce a logical ordering:
I used two digit numbers because that will allow it to sort correctly from 01 through 99. Don’t worry about needing to insert one later as renumbering even 10 or 20 folders doesn’t take very long.
Now let’s add a Global Variable List for the infeed conveyor. Right click on the01_InfeedConveyor folder and select Add
-> Global Variable List+ from the context menu. That will display the Add Global Variable List dialog.
Now you’ll see an empty global variable list in the editor:
Now we have to imagine some global variables that our imaginary conveyor might have. I think it needs an output to turn on the motor (we’ll call that “Run”), a through-beam sensor across the end of the conveyor to sense when a part reaches the pick position (we’ll call that the “NoPart” input) and maybe this conveyor needs to signal to the pick & place that the conveyor is stopped (we’ll call that the “Stopped” interlock). Here’s what a global variable list with those 3 variables would look like:
Let’s look at the first variable:
NoPart AT %I* : BOOL; (* Through-beam sensor *)
The line starts with the variable name (NoPart). Typical variable naming rules apply, so you can’t start the name with a number, and you can’t have spaces or special characters in the name, except an underscore. Here I’ve used the PascalCase way of writing the variable, by sticking capitalized words together. You don’t have to use PascalCase, but
you should pick a consistent way of naming your variables and stick with it.
After the variable name is an optional element that defines the variable as an input or output (AT %I*). The “I” means input and a “Q” means output. Adding this element will force the variable to show up in the PLC project’s I/O map which makes it available for linking to physical I/O. Inputs are set by the input scan before your logic runs, and outputs are set by your
logic, but copied to the physical outputs during the next output scan. (Technically the input an output scans happen at the same time.)
A colon (:) separates the declaration of the variable from the variable type (BOOL). Here are the common types you’ll use, though there are more:
•
BOOL: A boolean value (TRUE or FALSE)•
BYTE: An 8-bit unsigned integer value (0 to 255) aka USINT•
SINT: An 8-bit signed integer value (-128 to 127)•
WORD: A 16-bit unsigned integer value (0 to 65,535) aka UINT•
INT: A 16-bit signed integer value (−32,768 to 32,767)•
DWORD: A 32-bit unsigned integer value (0 to 4,294,967,295) aka UDINT•
DINT: A 32-bit signed integer value (−2,147,483,648 to 2,147,483,647)•
ULINT: A 64-bit unsigned integer value (0 to 18,446,744,073,709,551,615), new in TwinCAT 3•
LINT: A 64-bit signed integer value (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807), new in TwinCAT 3•
REAL: A 32-bit floating point value•
LREAL: A 64-bit floating point value•
STRING: An ASCII null-terminated string, default 80 characters•
STRING(n): An ASCII null-terminated string, with max length “n” characters•
TIME: A 32-bit time value (typically used in timers)A note on how much memory each one takes: for anything that says “8-bit”, “16-bit”, “32-bit” or “64-bit” then the memory usage is 1 byte, 2 bytes, 4 bytes, or 8 bytes respectively. A BOOL could be represented by a single bit, but takes a full byte (this is for performance reasons). There is also a rarely used data type called BIT which uses a single bit, and can have the values 0 and 1, but this is not equivalent to a BOOL. ASTRING takes 81 bytes (80 for the characters and 1 for the null terminator) and aSTRING(n) takes n+1 bytes.
Beckhoff’s Infosys site has more information about TwinCAT 3 Data Types.
After the data type, there is a terminating semi-colon (;). The compiler stops reading here.
After the semi-colon you can put an optional comment ((* Through-beam sensor *)). There are
two ways to insert comments: you can enclose them in bracket-asterisks, as I did, or you can
preface them with a double-slash (//). Note that comments will show up as tool-tips when you
hover your mouse over any use of this variable in your logic, so they are helpful.
The other thing that shows up in a tool-tip over a variable is the data type (BOOL, INT, etc.). Long before we had helpful features like this in our IDE, programmers invented a system for embedding the type of the variable in the variable name called Hungarian Notation. You will often see TwinCAT code examples, even in the official documentation, that use
Hungarian Notation (such as bIsTRUE : BOOL;). This is now discouraged thanks to smarter and more helpful editors. In general you should avoid Hungarian Notation in your TwinCAT 3 programs.
When you refer to global variables in your logic, you should use the fully qualified name of the variable (including the Global Variable List name) such asInfeedConveyor.Run. Technically it will let you omit the Global Variable List name and just use the variable name (Run). This is a throw-back to TwinCAT 2 where there was only one Global Variable List. You don’t want to run into a situation where it gets confused with another global variable called Run in another Global Variable List (OutfeedConveyor.Run would be an obvious one). If you happen to do this, the compiler will give you an error telling you that you have an ambiguous variable name and it will force you to use the fully qualified name. I suggest using fully qualified names for all global variables.
Adding Structure(s)
A conveyor is a pretty simple piece of equipment and I doubt you’d want to break up the structure of
the InfeedConveyor Global Variable List into smaller pieces, but for a larger part of the machine you might want to. For instance, the pick & place might have two positions (Pick and Place). Rather than having variables such
asPickAndPlace.InPickPosition it’s a bit nicer to havePickAndPlace.Pick.InPosition (I realize some of the reasons why it’s nicer might not be obvious at this point, but trust me).
You can accomplish this with TwinCAT 3’s Structure, which is a kind of Data Unit Type, a.k.a. “DUT”. In the RSLogix 5000 world, this is called a “UDT” meaning “user defined type.” Let’s start by creating a Structure for the pick & place’s Pick position. Begin by right clicking on the 02_PickAndPlace folder and selecting Add -> DUT+, which will open the Add DUT dialog window. Enter PickAndPlace_Pick in the Name text box. Make sure the Structure radio button is selected in the Type group box. Then click theOpen button:
That will generate a new (empty) structure in the editor window:
Any variables we add here will show up prefixed with PickAndPlace.Pick. in their fully qualified name. Add an InPosition variable like this:
Now let’s create a new PickAndPlace Global Variable List. Right click on the 02_PickAndPlace folder, use Add -> Global
Variable List+ and after creating it, add this variable:
Now we’ve created a variable called PickAndPlace.Pick.InPosition. Note that you can also define inputs and outputs inside your structure (by adding AT %I* orAT %Q* respectively).
Arrays
It’s often advantageous to declare a numbered list of variables, and for this we traditionally use arrays. TwinCAT 3 has full support of arrays of any type. The syntax for declaring an array variable looks like this:
To use this array in your logic, it would look like this: ExampleGlobalVariableList.SomeArrayVariable[1]. That would be the first element. The last element in the array would beExampleGlobalVariableList.SomeArrayVariable[10].
Note that the syntax ARRAY[lower..upper] OF allows you to define any lower or upper bounds you like. Unlike a language like C, your lower bound doesn’t have to be zero. The total number of elements in the array is upper - lower + 1. You can also define multi-dimensional arrays like this:
You could access the first element of the array like this: ExampleGlobalVariableList.SomeArrayVariable[1,50] and the last element as ExampleGlobalVariableList.SomeArrayVariable[10,55].
Caution: when some programmers graduated from RLogix 500 to RSLogix 5000 and were first introduced to tags, they just didn’t “get” it. They wanted their nice safeB3:0/5 or whatever. Since the concept of tags was confusing, they just created a big controller-scope array tag called bits and used bits[0], bits[1], bits[2], etc. in their logic. It was a bad idea, but doing the same thing in TwinCAT 3 is a really bad idea. At least in RSLogix 5000 you could add a useful comment for each element of the array but there is no method of doing that in TwinCAT 3 (because you’re not supposed to do that anyway). Your TwinCAT 3 program would be completely incomprehensible.
I would also like to caution you against using arrays for things that aren’t naturally numbered, or which aren’t a good fit for fixed numbers. For instance let’s say you have an auto sequence of steps like:
1. Run conveyor to sensor 2. Pick part from conveyor 3. Place part on fixture 4. Return pick & place to home
Perhaps you would like to implement that auto sequence using the Step pattern. Good idea. Now you might think you
want to create an array of variables for your steps, such as PickAndPlace.AutoSequence.Step[1]. Having done this in the past, I now think it’s a bad idea. It’s very common to have to modify your auto sequence to add or remove steps in the future. What if between your pick and place step you wanted to add a measurement step? It’s not so easy to add a step 2.5 when you’ve declared them as an array, and renumbering the steps in all your logic can be a real pain. I think it’s better to create variables like PickAndPlace.AutoSequence.PickStep andPickAndPlace.AutoSequence.PlaceStep. Then you can add and remove steps, or even re-order them, without cursing yourself later.
Conciseness and Readability
You might notice that some of my variable names above end up very long. I agree that’s a problem. On the one hand, since the comments for each variable only show up if you hover your mouse over the variable, you shouldn’t make your variable names too cryptic or it will be hard for someone to understand your logic. On the other hand, if you make them
too long, you can’t fit enough of your ladder logic on the screen at once, and the logic itself becomes difficult to follow. There’s a trade-off to make in conciseness vs. readability.
I suggest making short codes or acronyms for your top level machine elements. For example, you could abbreviate InfeedConveyor as IFC and PickAndPlace toPP. When someone looks at your PLC project, they will still see 01_InfeedConveyor and 02_PickAndPlace as two folders, and inside each there will be Global Variable Lists IFCand PP respectively. Since you’re only doing this at the top level of your program, and it’s fairly easy for someone to see the relationship of the full name to the abbreviation, I think this is a good way to shorten your fully qualified variable names without sacrificing much readability.
For the lower level variable names, make an effort to pick names that are still concise but convey the meaning to the reader. Yes, it takes practice and there’s no perfect answer, but effort really counts here.
4 - TwinCAT 3 Tutorial: Persistent Variables
Traditional PLCs offer various forms of data persistence (so your PLC memory isn’t lost when the PLC loses power). Some use battery-backed SRAM, which maintains power to all or a portion of the memory even when power is removed from the PLC. Some use flash-memory technologies. Since TwinCAT 3 runs on PC hardware, and PC memory isn’t battery-backed up, it has a different mechanism for storing persistent variables.
By default, variables in TwinCAT 3 are not persistent. If you restart the runtime, or your PC loses power, then when your PLC program restarts the variables will revert to their default state. This is fine for many situations (we generally want our outputs to start in the off state anyway). However, there are times when we need to store machine state such as part presence or process information and we don’t want to lose it when the PC reboots. TwinCAT 3 allows you to explicitly define variables that are “persistent” for this purpose.
In this chapter I’ll explain how to create persistent variables, how TwinCAT 3 saves and restores them, and how to write a program to periodically save them to a file in case of a crash or power loss.
Declaring Persistent Variables
For this example, I created a new Global Variable List called “PersistentExample”. Note that persistent variables don’t need to be global (they could be defined in a program or a function block, for example). By default a Global Variable List only has one section of declarations (called VAR_GLOBAL):
Anything declared inside of the VAR_GLOBAL section is not persistent. However, we can declare a section to be persistent like this:
Adding the PERSISTENT keyword after VAR_GLOBAL tells TwinCAT 3 that any variables in this section should be written to persistent storage when the runtime shuts down, and restored from persistent storage when the runtime restarts
(the data is actually stored to a file on disk, and I’ll explain more about the details later). I’ve declared two integervariables (one persistent and one non-persistent) as examples, and I’ve initialized them with default values (5 and 3 respectively). Now let’s login to the PLC, and apply this as an online change. You will now see an online view of this Global Variable List:
As you can see, both variables have been created in the PLC, and they have the values 5 and 3, respectively. Now I’m going to write new values to them. In the Prepared valuecolumn, enter the values 10 and 6, like this:
Now choose PLC > Write values to all online applications to overwrite the variable values in the PLC memory:
As you can see, the values have changed. Now we’re going to restart the runtime and see what happens. First choose PLC
> Logout from the menu and then choose TwinCAT > Restart TwinCAT System to initiate a runtime restart. You will be
asked to confirm:
Click OK to restart in Run Mode. You will see the TwinCAT icon in the system tray briefly turn red, and then turn back to green. When that’s done, go back online by choosingPLC > Login from the menu:
You can see that the persistent variable retained the value of 10 that we wrote to it, but the non-persistent variable reverted to the initialization value of 3 that we defined in the variable declaration. The written value of 6 was lost.
How Persistence Works
TwinCAT 3 stores the persistent variables in a file on the computer’s hard drive. The sequence of when this happens is critical to understand to prevent you from losing your valuable persistent data. When you shut down the TwinCAT 3 runtime, here is how it saves your variables:
1. The PLC program stops executing
2. The runtime reads all of the persistent variables and writes them to a file 3. The runtime stops
The persistent data file is stored in the C:\TwinCAT\3.1\Boot\Plc folder, and it will be named Port_851.bootdata. Each PLC instance on a runtime has an “ADS port number”. The default port numbers start at 851. You can change the port number, but that’s not important right now.
When TwinCAT 3 restarts, here is how it restores your variables:
1. The runtime loads the PLC program (including the default values of all variables)
2. The runtime looks for a persistent data file on the hard drive, and if it finds one, it restores the saved values to the PLC variables
3. It deletes the persistent data file from the hard drive 4. The PLC program starts executing
If, for some reason, the runtime can’t find the persistent data file, then all of your persistent variables will be reset to their default values. This is actually very easy to demonstrate because if the runtime doesn’t get a chance to shutdown cleanly, it won’t write the persistent data file to the hard drive. Here are some ways that this can happen: