exercises · South Africa
Car wash PLC program example, five-stage cycle
A car wash PLC program example with five timed stages: soap, brush, rinse, dry and done, built as a step sequencer with abort handling. Ladder and ST.
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: a truck wash bay at a Midrand logistics depot runs a manual hose-and-brush operation that ties up a worker for twenty minutes per rig. The depot has installed a gantry with a soap arch, rotating brushes, a rinse arch and a dryer fan, and wants a push-button cycle: driver positions the truck on the marked spot, attendant presses start, then soap sprays for 20 seconds, brushes run for 30, rinse runs for 20, the dryer for 40, and a done lamp tells the driver to pull out. If the truck creeps off the position sensor mid-cycle, everything must stop immediately and the cycle must abort, not resume on its own when the truck rolls back.
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 |
|---|---|---|---|
VehicleInPos | DI | %I0.0 | Inductive loop / position photoeye, TRUE while the vehicle sits on the wash position. |
StartPB | DI | %I0.1 | Attendant's start pushbutton, normally open, momentary. |
EstopOK | DI | %I0.2 | Bay e-stop circuit, normally closed, fail-safe. TRUE = healthy and reset. |
SoapValve | DO | %Q0.0 | Soap arch solenoid valve, stage 1, 20 seconds. |
BrushMotor | DO | %Q0.1 | Rotating brush drive contactor, stage 2, 30 seconds. |
RinseValve | DO | %Q0.2 | Rinse arch solenoid valve, stage 3, 20 seconds. |
DryerFan | DO | %Q0.3 | Dryer fan contactor, 15 kW, stage 4, 40 seconds. |
DoneLamp | DO | %Q0.4 | Green exit lamp, stage 5, tells the driver to pull out. |
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.
- One step variable, one timer, one table of step times — the same compact sequencer as the traffic light, just with five steps and an abort path. Five separate seal-in rungs with five timers also works, but every stage you add later doubles the interlocking; the step variable scales linearly.
- Abort and finish are different exits and deserve different states. Losing the position sensor mid-wash should land in an IDLE state that requires a fresh start press; finishing stage 5 can auto-return to IDLE when the truck drives off. Mixing the two paths is how half-washed trucks get a dryer blast on re-entry.
- The done lamp is a state, not an afterthought. If DoneLamp shares the dryer's timer, the lamp dies the moment the fan stops and the driver sits waiting. Give 'done' its own state that ends when the vehicle leaves the position.
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: start gate into the sequence
From IDLE, a start press with the vehicle in position and the e-stop healthy moves the step variable to SOAP. The start does nothing in any other state — mid-cycle presses are ignored by construction rather than by extra interlock rungs.
// (Step=IDLE) AND StartPB AND VehicleInPos AND EstopOK ── MOVE SOAP -> Step
Rung 2: one timer, time per step
MOVE the active stage's preset into StepTime (T#20s soap, T#30s brush, T#20s rinse, T#40s dry), run a single TON whenever the step is an active wash stage, and on the done bit advance Step by one. The DONE state has no timer — it exits on the vehicle leaving.
// (Step=SOAP) ── MOVE T#20s -> StepTime (and so on per stage)
// ActiveStage AND NOT tStep.Q ──[TON tStep, PT := StepTime]
// tStep.Q ── ADD Step,1 -> Step
Rung 3: the abort rung
Any active stage AND (NOT VehicleInPos OR NOT EstopOK) moves Step straight to IDLE. Because all outputs decode from Step, this single rung silences the whole bay in one scan — no chasing five coils with five reset conditions.
// ActiveStage AND (NOT VehicleInPos OR NOT EstopOK) ── MOVE IDLE -> Step
Rungs 4-8: decode the outputs
SoapValve on Step=SOAP, BrushMotor on Step=BRUSH, RinseValve on Step=RINSE, DryerFan on Step=DRY, DoneLamp on Step=DONE. The DONE state returns to IDLE when VehicleInPos drops. Each output exists in exactly one rung, which is what makes the 02:00 fault-find survivable.
// (Step=SOAP) ──( )SoapValve
// (Step=BRUSH) ──( )BrushMotor
// (Step=RINSE) ──( )RinseValve
// (Step=DRY) ──( )DryerFan
// (Step=DONE) ──( )DoneLamp
// (Step=DONE) AND NOT VehicleInPos ── MOVE IDLE -> Step
Test the abort hard
Time a full clean cycle first: 110 seconds of outputs in the right order, then the lamp. Now the real test: drop VehicleInPos during each of the four active stages and confirm every output dies instantly and the step lands in IDLE. Restore the sensor — nothing may move until start is pressed. Press start mid-cycle (must be ignored), and pull EstopOK during the dryer stage (same instant stop). Lastly confirm the done lamp survives until the truck actually leaves.
The structured text version
The same logic in IEC 61131-3 structured text — each output written as a boolean equation you can read aloud.
(* Five-stage car wash sequencer, IEC 61131-3 ST *)
VAR CONSTANT IDLE := 0; SOAP := 1; BRUSH := 2; RINSE := 3; DRY := 4; DONE := 5; END_VAR
ActiveStage := (Step >= SOAP) AND (Step <= DRY);
IF ActiveStage AND (NOT VehicleInPos OR NOT EstopOK) THEN Step := IDLE; END_IF;
CASE Step OF
IDLE: IF StartPB AND VehicleInPos AND EstopOK THEN Step := SOAP; END_IF;
SOAP: StepTime := T#20s;
BRUSH: StepTime := T#30s;
RINSE: StepTime := T#20s;
DRY: StepTime := T#40s;
DONE: IF NOT VehicleInPos THEN Step := IDLE; END_IF;
END_CASE;
tStep(IN := ActiveStage AND NOT tStep.Q, PT := StepTime);
IF tStep.Q THEN Step := Step + 1; END_IF;
SoapValve := (Step = SOAP);
BrushMotor := (Step = BRUSH);
RinseValve := (Step = RINSE);
DryerFan := (Step = DRY);
DoneLamp := (Step = DONE);
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.
- Five chained seal-in circuits with each stage's coil resetting the previous one. It runs fine until an abort, and then you discover three of the five reset paths were never tested — the step-variable design makes that whole class of bug impossible.
- Letting the cycle resume after the vehicle rolls back onto the sensor. The driver who crept forward during the rinse gets the brush stage restarting against a truck in the wrong position; abort must land in IDLE and demand a deliberate restart.
- Sharing one timer between stages without resetting it on every transition. The brush stage inherits 12 seconds already on the clock from soap, the cycle shortens unpredictably, and the complaint is 'trucks coming out wet'. The self-resetting TON pattern (done bit breaking its own IN) avoids this.
- No e-stop path through the sequencer. Each output obeys the e-stop individually but the step variable keeps marching, so when the e-stop resets, the bay wakes up mid-stage. Abort the state, not just the outputs.
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 coin-box or token input and a wash-selection input (quick wash skips the brush stage) — skipping states cleanly is a good test of whether your sequencer is really table-driven.
- Add a water-pressure healthy input that pauses the timer rather than aborting, so a municipal pressure dip mid-rinse holds the stage instead of eating the driver's money.
- Count cycles per day into a retentive counter for the depot manager, and alarm when the brush motor's accumulated run hours pass a service threshold — the pump alternation exercise shows the hour-metering pattern.
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
Programmable logic controller 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.