exercises · South Africa
PLC gate control program for a sliding gate
PLC gate control program for a sliding gate: open and close with limit switches, safety-beam reversal, a 30-second auto-close, and load-shedding sanity.
Difficulty: intermediate · 45–75 minutes
This is a build-along exercise, not a reading page. You get a short job card of the kind a contractor actually receives, an I/O table to wire against, and a worked solution to check yourself with once your own version runs — plus the test sequence that proves it, because a program you haven't tried to break is a program you haven't tested. Sketch first, build second, test third. Same order as on site.
Open the simulator and build along →The job card
Job card: the steel sliding gate at a Pretoria East factory yard is driven by a 0.75 kW motor with open and closed limit switches, a safety beam across the driveway at bumper height, and a trigger button in the guard house. Required behaviour: a trigger while closed opens the gate; fully open, it waits 30 seconds and closes itself; a trigger while closing reverses it to open; the beam breaking while closing reverses it immediately (a bakkie nose, a person, a dog — the gate must never close on any of them); and after load-shedding the gate must stay exactly where it is until someone presses the trigger — a gate that moves by itself on power-up is how vehicles get scraped and insurance calls start.
Read it the way a foreman hands it to you. Every requirement on that card is a test case: when you think the program is done, walk the card line by line and force each condition in the watch table. Any line without a matching test you actually ran means you're not done yet. That habit — card in one hand, watch table in the other — is what separates a programmer who commissions clean from one who gets the call-back at month end.
I/O assignment
Wire your simulator project to this table exactly. Half the value of an exercise like this is tag discipline: name the points the same way the table does and the solution steps further down will read straight onto your rungs without translation.
| Tag | Type | Address | Purpose |
|---|---|---|---|
TriggerPB | DI | %I0.0 | Guard-house trigger button, normally open, momentary. One button: open, or reverse-to-open while closing. |
LimitOpen | DI | %I0.1 | Open limit switch, normally closed, wired fail-safe: TRUE while the gate is NOT yet fully open; goes FALSE at full open (or on a broken wire, which reads as 'at limit' and safely stops the motor). |
LimitClosed | DI | %I0.2 | Closed limit switch, normally closed, fail-safe, same sense: FALSE = fully closed or wire broken. |
BeamClear | DI | %I0.3 | Safety beam across the driveway, normally closed, fail-safe. TRUE = beam intact and path clear; an obstruction or a cut cable both read FALSE. |
MotorOpen | DO | %Q0.0 | Gate motor contactor, open direction. |
MotorClose | DO | %Q0.1 | Gate motor contactor, close direction. Never together with MotorOpen. |
A note on the Type column: DI is a digital input, DO a digital output, AI and AO are analogue in and out, and M is an internal memory bit that never leaves the CPU. The addresses use IEC notation (%I, %Q, %M). If your head is in Allen-Bradley land, map %I0.0 to I:0/0 and carry on — the logic doesn't change, only the spelling of the addresses.
Think before you build
Don't open the ladder editor yet. The notes below are the design decisions that determine whether your program works first time or fights you for an hour. Read them, then sketch the rung shapes on paper. Pencil and the back of a delivery note is fine — most working programs start exactly there.
- Four states: CLOSED, OPENING, OPEN (timing auto-close), CLOSING — and a fifth, UNKNOWN, for power-up anywhere mid-travel. Both motor outputs decode from the state, each with the opposing output's normally-closed contact as a second line of defence; reversing contactors also get the mechanical interlock in the panel, same argument as star-delta.
- The limits are wired NC fail-safe, so the input sense is inverted from intuition: TRUE means 'not at this limit yet'. Write the sense as a comment at the top of the program — half the faults on gate retrofits are someone 'fixing' an inversion that was correct.
- Power-up state is UNKNOWN unless a limit says otherwise. If LimitClosed reads at-limit, start in CLOSED; if LimitOpen does, start in OPEN with the auto-close timer suppressed until a trigger; anywhere in between, the gate parks until a human presses the button. Never auto-move on boot.
- The beam reverses only while CLOSING. Breaking the beam while opening is normal traffic driving through; breaking it while the gate is parked open simply holds the auto-close timer reset, which quietly gives you 'gate will not close on a parked bakkie' for free.
Step-by-step solution
Build one rung at a time and test after every rung. Never write the whole program and then test the lot — when five rungs go in untested and the machine misbehaves, you're debugging five suspects instead of one. The steps below follow that order. In the pseudo-rungs, ] [ is a normally-open examine, ]/[ is normally-closed, and ( ) is the output coil.
Rung 1: power-up state resolution
On first scan: NOT LimitClosed lands the state in CLOSED, NOT LimitOpen lands it in OPEN (with a TriggerNeeded flag set so the auto-close stays quiet), anything else lands in UNKNOWN. From UNKNOWN, the first trigger commands OPENING — opening from an unknown position is the safer guess because the beam protects the close direction only.
// FirstScan AND [/]LimitClosed ── MOVE CLOSED -> State
// FirstScan AND [/]LimitOpen ── MOVE OPEN -> State, (S)TriggerNeeded
// FirstScan AND both limits TRUE ── MOVE UNKNOWN -> State
Rungs 2-3: trigger handling per state
A rising-edge contact on TriggerPB does different work per state: in CLOSED or UNKNOWN it commands OPENING; in CLOSING it reverses to OPENING; in OPEN it clears TriggerNeeded and restarts the auto-close wait. Edge, not level — a guard leaning on the button must not hold the gate hostage.
// rTrig.Q AND (State=CLOSED OR State=UNKNOWN OR State=CLOSING) ── MOVE OPENING -> State
Rungs 4-5: travel and arrival
OPENING runs until LimitOpen goes FALSE (at limit), then OPEN. CLOSING runs until LimitClosed goes FALSE, then CLOSED. Add a 45-second travel watchdog on both moving states: a gate that has hit neither limit in 45 seconds has a slipped pinion or an obstruction the beam cannot see, and the motor must stop in UNKNOWN with a fault flag rather than cook itself against a jam.
// (State=OPENING) AND [/]LimitOpen ── MOVE OPEN -> State
// (State=CLOSING) AND [/]LimitClosed ── MOVE CLOSED -> State
// moving AND tTravel.Q ── MOVE UNKNOWN -> State, (S)TravelFault
Rungs 6-7: auto-close and beam reversal
In OPEN, a 30-second TON runs only while BeamClear is TRUE and TriggerNeeded is FALSE; its done bit commands CLOSING. In CLOSING, NOT BeamClear commands OPENING immediately — one rung, no debate, no delay. The asymmetry (beam ignored while opening) is deliberate and worth a comment.
// (State=OPEN) AND BeamClear AND [/]TriggerNeeded ──[TON tAuto, PT := T#30s]
// tAuto.Q ── MOVE CLOSING -> State
// (State=CLOSING) AND [/]BeamClear ── MOVE OPENING -> State
Test the reversals and the power cut
Full cycle first: trigger, open to limit, 30 s, auto-close to limit. Then the reversals: break the beam mid-close (instant reverse to full open), trigger mid-close (same). Park a 'vehicle' on the beam with the gate open: the gate must wait indefinitely, then close 30 s after the beam clears. Now the load-shedding test: kill PLC power with the gate half-open, restore it — both outputs must stay off until a trigger. Finally simulate a snapped limit-switch wire (force it to the at-limit reading) and confirm the motor stops rather than driving through the end of the track.
The structured text version
The same logic in IEC 61131-3 structured text — each output written as a boolean equation you can read aloud.
(* Sliding gate controller, IEC 61131-3 ST *)
VAR CONSTANT CLOSED := 0; OPENING := 1; OPEN := 2; CLOSING := 3; UNKNOWN := 4; END_VAR
rTrig(CLK := TriggerPB);
IF FirstScan THEN
IF NOT LimitClosed THEN State := CLOSED;
ELSIF NOT LimitOpen THEN State := OPEN; TriggerNeeded := TRUE;
ELSE State := UNKNOWN; END_IF;
END_IF;
tAuto(IN := (State = OPEN) AND BeamClear AND NOT TriggerNeeded, PT := T#30s);
tTravel(IN := (State = OPENING) OR (State = CLOSING), PT := T#45s);
CASE State OF
CLOSED, UNKNOWN: IF rTrig.Q THEN State := OPENING; END_IF;
OPENING: IF NOT LimitOpen THEN State := OPEN; TriggerNeeded := FALSE;
ELSIF tTravel.Q THEN State := UNKNOWN; END_IF;
OPEN: IF rTrig.Q THEN TriggerNeeded := FALSE; END_IF;
IF tAuto.Q THEN State := CLOSING; END_IF;
CLOSING: IF NOT BeamClear OR rTrig.Q THEN State := OPENING;
ELSIF NOT LimitClosed THEN State := CLOSED;
ELSIF tTravel.Q THEN State := UNKNOWN; END_IF;
END_CASE;
MotorOpen := (State = OPENING) AND LimitOpen AND NOT MotorClose;
MotorClose := (State = CLOSING) AND LimitClosed AND NOT MotorOpen;
Ladder wins this argument when an electrician has to fault-find your program at 02:00 with a multimeter mindset — the rung looks like the circuit diagram it replaced, and that familiarity is worth real money on a breakdown. ST starts winning when the pattern repeats: ten pumps with the same interlock shape is one ST function called ten times, where ladder hands you ten near-identical rungs to keep in sync by hand forever. Learn both. Build the exercise in ladder first, then write the ST version and confirm the two behave identically in the simulator. That translation skill — same logic, two languages — is exactly what technical interviews and commissioning work both test.
Common mistakes
Every mistake below comes from a real program: either one of ours from years back, or one we were called in to fix. Check your build against the list before you call the exercise done.
- Both motor outputs energised together. One missed interlock contact and the reversing contactors fight; with no mechanical interlock in the panel that is a phase-to-phase short. Decode both from one state variable AND keep the NC cross-contacts AND fit the mechanical interlock — three layers because the failure is expensive.
- Reading the NC limit switches with intuitive sense. 'TRUE = at limit' feels natural, but fail-safe NC wiring gives the opposite, and the symptom of getting it backwards is a gate that drives INTO its end stop at commissioning — at full speed, with the new motor.
- Resuming travel automatically after a power cut. The state variable was retentive, power returns, and the gate sets off while a car sits half through the entrance. Power-up must land in a parked state that requires a human trigger, full stop.
- Reversing on the beam in both directions. Beam-break during opening then traps the gate in a reversal loop as every entering vehicle re-triggers it; the beam's job is protecting the close direction, and the asymmetry is the design, not an oversight.
- No travel watchdog. A slipped drive pinion means the motor runs forever against a stationary gate; 45 seconds of no-limit-reached should stop everything and flag a fault, not wait for the motor's thermal trip to do the thinking.
Most of these share one root cause: the rung shape doesn't match the intent, so the program passes the obvious test and fails the edge case. That's why the solution steps force the edge cases deliberately instead of stopping at "it starts and it stops". Steal that habit for every program you write from here on.
Take it further
Got it working first time? Good — now make it earn its keep. Each extension below changes the spec the way a real client does: after you've finished. Treat each one as a fresh job card, and re-test the whole program afterwards, not just the new part. Regressions hide in the rungs you didn't touch.
- Add a pre-movement warning flasher (3 seconds before any motion, using the conveyor exercise's horn pattern) and a courtesy light output that holds for 60 seconds after any movement.
- Add a partial-open 'pedestrian mode' on a double-press of the trigger — opening for 4 seconds of travel instead of to the limit — and handle what happens when someone triggers full open mid-pedestrian-cycle.
- Add an obstruction counter: three beam-reversals on the same closing attempt parks the gate open with a fault lamp, because something is genuinely in the way and re-trying forever is how gate motors burn out.
If you build even one extension, screenshot the finished rungs and keep them somewhere organised. A folder of working, tested exercise solutions is the start of a portfolio — and hiring engineers ask candidates to explain a rung far more often than they ask to see certificates.
Run this in the simulator
The sandbox on the free tier lets you build the core rungs of this intermediate exercise yourself — no card details, no install, signed up and on a rung inside two minutes. The watch table is the part that matters here: force the inputs, watch the outputs, and run the test sequence from the solution steps against a live scan cycle instead of imagining it. To be straight about what's paid: the guided version of this exercise — graded checkpoints, feedback on every submission — sits in the curriculum on the Basic tier at USD 12 per month and Pro at USD 29 per month, alongside the wiring track, sensor school and cert packs. Training centres and engineering departments wanting this in a lab should look at the Teams tier (USD 199 per seat per year, minimum 5 seats); the training-centres page carries the institutional details and the contact form. If you're an individual learning the trade, prove the core rungs in the free sandbox first and decide whether the graded track is worth the money. And once this one runs clean, line up the next exercise a notch harder — the step up is where the skill gets built.
Start in the free sandbox →Reference
Ladder logic on Wikipedia covers the background theory behind this exercise, and it's worth twenty minutes of your time after the build — theory sticks better once your hands have done the work. The languages used here are defined by the IEC 61131-3 standard from iec.ch, and your CPU vendor's manual remains the canonical source for how a specific controller executes them.
What we don't claim
This site is not SAQA-registered, not MerSETA-accredited, and not an NQF-registered qualification provider. Our completion certificates are course-level only — they describe what you covered, not an NQF Level X qualification. The CCST cert from ISA is the portable industry credential we recommend; we are not an ISA cert delivery partner either, but our cert packs are CCST-aligned. The exercise on this page is practice material written by working programmers: finishing it proves the skill to yourself and to the simulator's progress tracking, not to a regulator.