Controlling Traffic Lights with Structured Text and a RevPi Core 3
A simple Structured Text (PLC) program to run on the RevPi Core 3 to control traffic lights.
Having installed the RevPi Core 3 and DIO on DIN rail and got them up and running, as detailed in a previous post, it was now time to roll my sleeves up and see if I could get them to do something useful. As a “proof of concept” I wanted to see if I could simulate a simple traffic light set up.
Structured Text (ST)
There are 3 main standard languages used to create control programs for PLCs – Structured Text Language (ST), Ladder Logic and Function Block Diagram (FBD). The latter two as their names imply, have a more graphical interface but are not quite as flexible as Structured Text and the free version of logi.CAD 3 that comes with the RevPi only supports ST, so that is what I needed to use.
Although Structured Text is a standardised language governed by industry-standard IEC 61131-3, and the core of the language remains consistent, every PLC vendor has its own variations and additions. I found a useful introductory tutorial online that got me started. For those familiar with computer languages, ST is derived from PASCAL and reminded me of the BASIC I used to program Ping Pong games on my ZX80 more years ago than I care to remember.
As well as dealing with a new language I was also working with software I had not used before. I found it was useful going through the logi.CAD 3 glossary to understand some of the terminology used, and to refer back to it when necessary. In particular, I made note of the following:
- Objects - An object in the project explorer of logi.CAD 3 is located within a folder, it is the child of this folder. The object is comparable to a file on the file system.
- Projects - A project is a special type of a folder in the project explorer of logi.CAD 3. By default, the project is the root in the project explorer.
The complete thing is referred to as an Application and includes not only the STL file containing the code you have written, but also one that acts as a configuration file, as well as global variables and a library specific to the PLC you are using.
A couple of times I found logi.CAD 3 would fail to build the application even though the syntax and everything reported as being OK. In these cases, I found it useful to “Clean” the project by clicking on the Clean option under the Project Menu, and then let Logi.CAD 3 do its thing, after which the application built and loaded OK.
PROGRAM RevolutionPiCounterProgram VAR value : BOOL; END_VAR VAR_EXTERNAL Red_1 : BOOL; Amber_2 : BOOL; Green_3 : BOOL; END_VAR IF value THEN Red_1 := False; value := False; ELSE Red_1 := True; value := True; END_IF; END_PROGRAM
In this example the LED flashes continuously. This is because PLC Applications automatically repeat. The “End_Program” actually means go back to the beginning and start again.
As the tutorial puts it “When the PLC reaches the END_PROGRAM the PLC scan cycle will start over again, and your program will repeat itself”:
I now needed to work out how to make the LEDs flash in the standard Traffic Light sequence – Red, Red and Amber, Green, Amber and back to Red.
The speed the light flashes can be changed by simply editing a value in the configuration file, but this changes the speed of the entire scan cycle, which is crude and just slows everything down in the application. I also wanted to be able to change the speed of the different lights independently. This proved more of a challenge than initially expected.
The TON function (timer delay) provided the delay I needed, but I had trouble getting my code to produce the effect I wanted. I could get an LED to come on for a given amount of time and then go off, but not come on again, or flash on and off, but I was unable to specify the off time. I was going round in circles and for a while thinking I had bitten off more than I could chew when, searching the Internet for help, I came across mention of the CASE statement in a useful post on the Codesys forum. Codesys is an alternative to logi.CAD and, as I discovered, there are some differences in the ST syntax used but I was able to adapt an example to my needs.
I had also read about the CASE statement in the online tutorial, but it was seeing the example that suddenly made sense of how I could use it in practice.
This is the code that I ended up with:
PROGRAM RevolutionPiProgram VAR wait : TON; count : INT; END_VAR VAR_EXTERNAL Red_1 : BOOL; Amber_2 : BOOL; Green_3 : BOOL; END_VAR CASE count OF 0: //init count := count + 1; 1: // Red Red_1 := True; Amber_2 := False; Green_3 := False; wait(IN:=TRUE, PT:=T#5s); IF wait.Q THEN wait(IN:=FALSE); count := count + 1; END_IF; 2: // Red and Amber Red_1 := True; Amber_2 := True; Green_3 := False; wait(IN:=TRUE, PT:=T#5s); IF wait.Q THEN wait(IN:=FALSE); count := count + 1; END_IF; 3: // Green Red_1 := False; Amber_2 := False; Green_3 := True; wait(IN:=TRUE, PT:=T#5s); IF wait.Q THEN wait(IN:=FALSE); count := count + 1; END_IF; 4: // Amber Red_1 := False; Amber_2 := True; Green_3 := False; wait(IN:=TRUE, PT:=T#5s); IF wait.Q THEN wait(IN:=FALSE); count := count + 1; END_IF; ELSE count := 0; END_CASE; END_PROGRAM
CASE is used to execute a statement if a particular integer value occurs. In this example, an integer variable is created called “count” that would increase by 1 at each PLC scan, until the final case was run and when the ELSE would set it back to zero. TON is used to run each statement for 5 seconds. This can easily be changed by editing the 5s value in the line:
A different time can be given to each sequence of lights if desired (I altered them all to 2 seconds for the video below). The code could also easily be expanded to add more lights.
Grappling with a new (to me) computer language and an unfamiliar piece of software was always going to be a challenge, but I am pleased with the elegant solution I eventually arrived at. Although the lights I have ended up with may not be exactly “roadworthy”, I can see how with a bit of work they could be developed for simple traffic control at one-off events such as agricultural shows or similar occasions.