exercises · South Africa
PLC Sorting Program Example: Height and Carton Tracking
Build a PLC sorting program example with height classification, carton tracking and timed commands, plus failure tests and practical SA training questions.

This PLC sorting program example classifies a virtual carton from two height signals, keeps a separate record of whether a classification exists, and consumes that record at a downstream detection point. The main lesson is object tracking: a Boolean saying “tall” is not enough to tell you whether a short carton, a tall carton or no carton is expected.
You will work through a deliberately restricted single-carton model, an 800 ms virtual divert command and failure tests for overlapping arrivals. All signals are supplied exercise values. The example is not a pneumatic circuit, a validated machine programme or evidence that an actual parcel reaches the correct conveyor.
For a South African learner considering packaging, warehousing or manufacturing training, this is a useful question to bring to a course demonstration: can you explain how a classification remains associated with the same object after the measuring point has cleared? A moving animation alone does not answer that question.
Define the single-carton sorting contract
Call the supplied inputs LowEye, HighEye and DivertEye. True means the corresponding virtual beam is occupied. During an accepted measuring interval, any observed HighEye true while LowEye is true makes the classification Tall. If HighEye is never observed true during that interval, the classification is Short.
This is an “any observed high” rule, not a measurement of maximum physical height. A flap, noise or different sensor placement can change the input history. The model does not infer whether an object is stacked, damaged, suitable for a strapping machine or above a calibrated dimension.
Only one carton may enter the model at a time. A new carton is allowed after the previous classification has been consumed, the command interval has ended if used, and all three eyes have been observed clear. The model reports an unexpected arrival instead of silently overwriting the first carton’s classification.
Choose these fictional parameters for the exercise:
| Item | Exercise definition |
|---|---|
| Height classification | At least one HighEye observation while LowEye is true |
| Divert decision | A valid Tall record arriving on a fresh DivertEye rising edge |
| Virtual command duration | 800 ms from accepted tall arrival |
| Capacity | One carton record, including measuring and command phases |
| Interruption policy | Cancel the command and require an explicit clear-and-reset procedure |
| Physical installation | None; all values and outputs are simulated |
Do not claim that a particular carton spacing guarantees this capacity. Distance between sensors, carton length, speed, actuator timing and the definition of spacing all matter. The programme below enforces a conservative learning contract through its states; it does not design an upstream metering conveyor.
Keep identity separate from the tall flag
Use the states Empty, Measuring, AwaitDivert, Pulsing, WaitClear, Fault and ResetRequired. These states distinguish the lifecycle of the record. SeenHigh is temporary measurement memory. Tall is a completed classification, meaningful only after measuring has finished.
Empty means the model is available for one new leading edge. Measuring means LowEye has risen and the model is accumulating observations. AwaitDivert means LowEye has fallen and a valid Tall or Short record is waiting. Pulsing means a Tall record was consumed and the virtual command interval is active. WaitClear prevents immediate reuse until the exercise observes an empty sensing area.
A Short record in AwaitDivert is valid even though Tall is false. Compare it with Empty, where Tall false means nothing about an expected carton. Without that distinction, a programme can treat an unclassified arrival as a correctly classified short carton and never report the lost association.
Fault means an event broke the declared sequence. ResetRequired is the starting state and the state entered after interruption. Both keep the virtual command false. Record a reason, such as “divert arrival before classification” or “new gauge arrival while record occupied”, rather than calling every event a defective sensor.
Review ladder logic basics before implementing the state memory. The bottle-counting exercise provides additional practice with raw input edges and the difference between an event and a held level.

Establish startup and reset behaviour first
Initialise State to ResetRequired, SeenHigh and Tall false, and the command timestamp empty. Initialise PreviousLow, PreviousDivert and PreviousReset from their current supplied inputs. This prevents an input already true at startup from being presented as a newly observed edge.
Define Enabled and StopRequest separately from the three eyes. If Enabled is false or StopRequest true, interruption has priority: select ResetRequired, clear the temporary measurement and completed classification, clear the timestamp and make DivertCommand false. Update all previous-input values even during interruption.
A fresh ResetRequest edge is accepted only when Enabled is true, StopRequest false and LowEye, HighEye and DivertEye are all false. Accepting reset selects Empty and clears the record. A reset edge with any eye occupied selects Fault. Holding Reset does not keep resetting the programme; a new release and press are required for another reset event.
This policy intentionally discards a record after interruption. It does not claim that a physical carton disappeared. A real installation would need an appropriate reconciliation or clearance procedure before resuming, based on its actual design. For this disconnected exercise, explicitly clear the supplied eyes and start the test case again.
The conveyor warning and restart exercise explores a different restart policy for a virtual conveyor command. Keep those policies separate. Neither an ordinary status Boolean nor this reset sequence implements a physical emergency-stop function.
Measure over the occupied interval
Calculate LowRise from LowEye AND NOT PreviousLow, LowFall from NOT LowEye AND PreviousLow, and DivertRise from DivertEye AND NOT PreviousDivert. Calculate these from raw supplied values before deciding whether the state can accept the events. At the end of every evaluation, update the previous values.
In Empty, a LowRise starts Measuring and sets SeenHigh to the current HighEye value. This includes a high observation on the same evaluation as entry. Starting by clearing SeenHigh and only checking HighEye on later evaluations would miss that case.
During Measuring, set SeenHigh true whenever both LowEye and HighEye are true. Otherwise retain SeenHigh. On LowFall, copy SeenHigh to Tall and enter AwaitDivert. Do not replace the accumulated result with the current HighEye value at exit: the upper eye may already be clear when the lower eye falls.
HighEye observations outside an accepted LowEye interval do not classify anything in this exercise. Record them if useful, but do not invent an object association from them. A continuously true HighEye will classify every accepted measuring interval as Tall; that result follows from the rule and is a reason to test signal quality separately.
If DivertEye becomes occupied while Empty or Measuring, select Fault. There is no completed record that can legitimately arrive at the divert point in those states. In Empty, an already-held LowEye without LowRise also selects Fault rather than starting partway through an unobserved measuring interval.
Consume the record at the divert point
In AwaitDivert, a new LowRise means a second carton has entered too early. Select Fault and discard the record. Give this conflict priority if LowRise and DivertRise occur together. That conservative rule avoids silently accepting two objects in one evaluation under a one-object contract.
With no conflict, DivertRise consumes the classification. If Tall is true, enter Pulsing and store the supplied current time as PulseStartedAt. If Tall is false, enter WaitClear with no divert command. In both cases clear Tall after reading it; the state transition records that the classification has been consumed.
A held DivertEye is not a new arrival. Detect the edge from raw DivertEye, not from DivertEye AND Tall. Gating the edge detector with Tall can manufacture an apparent arrival when Tall becomes true while DivertEye was already occupied.
For completeness, treat an occupied DivertEye without a fresh edge in AwaitDivert as an invalid sequence. It cannot occur in a normal trace produced by the earlier states, but checking it makes manually edited watch-table states easier to diagnose.
In Pulsing or WaitClear, a new LowRise or another DivertRise selects Fault. The model is still busy with the previous event. It does not queue, merge or extend overlapping command requests. To allow more cartons, change the tracking design and its specification rather than deleting the busy check.

Define the 800 ms command precisely
Use nondecreasing supplied timestamps in milliseconds for this worked model. DivertCommand is true only in Pulsing. On a later evaluation where current time minus PulseStartedAt is at least 800, transition to WaitClear and make the command false. Entering WaitClear does not also enter Empty during that same evaluation.
On a subsequent WaitClear evaluation with all three eyes false and no conflicting new edges, select Empty. This deliberately adds an observed clear phase. A carton entering during that phase is unexpected, even if a more sophisticated machine could physically accept it.
An interruption or Fault cancels this custom pulse immediately at the evaluation where it is processed. That cancellation policy is part of this state model. Do not label the complete model a drop-in implementation of a vendor TP function block.
The CODESYS TP documentation describes a rising-edge-triggered pulse with a configured duration. Schneider Electric’s TP documentation also describes the pulse and states that another rising input before the duration has elapsed does not change Q. Consult the exact library when translating the exercise into a native timer implementation.
A timer’s output is a programme value. An 800 ms true interval does not prove that a cylinder extended fully, a valve responded or a carton diverted. This article supplies no pneumatic sizing, actuator feedback, guarding design or physical timing validation.
For a related timing comparison, use the motor-staging exercise. It makes the distinction between a timestamp, a sampled transition and a physical response explicit.
Work through a tall carton followed by a short carton
Start with the clear-and-reset procedure completed: State Empty and previous eye inputs false. Enabled remains true, StopRequest false and ResetRequest false throughout the table. Times are fictional supplied observations, not a controller performance measurement.
| Time ms | Low | High | Divert | State after evaluation | DivertCommand |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Empty | False |
| 10 | 1 | 0 | 0 | Measuring | False |
| 20 | 1 | 1 | 0 | Measuring | False |
| 30 | 1 | 0 | 0 | Measuring | False |
| 40 | 0 | 0 | 0 | AwaitDivert, Tall | False |
| 100 | 0 | 0 | 1 | Pulsing | True |
| 200 | 0 | 0 | 0 | Pulsing | True |
| 899 | 0 | 0 | 0 | Pulsing | True |
| 900 | 0 | 0 | 0 | WaitClear | False |
| 910 | 0 | 0 | 0 | Empty | False |
| 1000 | 1 | 0 | 0 | Measuring | False |
| 1010 | 0 | 0 | 0 | AwaitDivert, Short | False |
| 1100 | 0 | 0 | 1 | WaitClear | False |
| 1110 | 0 | 0 | 0 | Empty | False |
At time 40, HighEye is false but the retained observation from time 20 makes the record Tall. At time 1010, the new measuring interval contains no high observation, so the second record is Short. The earlier Tall result cannot leak into it.
The command begins at 100 and clears at the evaluation at 900. If the next evaluation after 899 were at 950 instead, the model would first report the expired pulse at 950. Record the observed transition, not an invented evaluation at 900.
In your implementation, log State, SeenHigh, Tall, each raw eye, each edge and PulseStartedAt. An output screenshot alone cannot show whether the programme classified the correct carton or merely produced a pulse at a plausible moment.

Test failures that an attractive animation can hide
Run a short-only sequence first, then tall-only, tall-short and short-tall. Include a carton whose only high observation occurs on the entry evaluation. Include another whose high observation occurs in the middle and is gone before exit. Both must classify Tall under the declared rule.
Test a continuously held LowEye. The model stays Measuring and never creates a completed record. Test a carton that leaves the gauge but never arrives at DivertEye. The model stays AwaitDivert. These are unfinished sequences, not automatic proof of a jam or broken sensor. A separately specified timeout could flag excessive waiting.
Test an unexpected DivertEye arrival in Empty and in Measuring. Both select Fault. Test a second LowRise in AwaitDivert, Pulsing and WaitClear. Each selects Fault instead of replacing the first classification. Test simultaneous new gauge and divert edges in AwaitDivert; the conflict takes priority and no command starts.
Hold DivertEye true through the end of a tall pulse. The command expires, but WaitClear must not release the record capacity until the eyes clear. A second rising divert edge during Pulsing must fault rather than extending the timestamp.
Interrupt at 799 ms after pulse start and exactly at 800 ms. StopRequest has priority in both cases, selects ResetRequired and clears the command. Restore Enabled while leaving an eye occupied: the model remains unavailable until the stated reset conditions are met. A held Reset must not turn that restoration into repeated acceptance.
These observations verify the exercise’s behaviour, not a safety function or sensor installation. Keep expected results separate from results actually observed in your chosen programming environment.
Why a FIFO needs more than a larger array
A first-in-first-out queue can hold several completed classifications, but it needs its own contract. Define enqueue at accepted gauge exit and dequeue at accepted divert arrival. Store a valid record for Short as well as Tall. Include a sequence identifier so test logs can show which record was consumed.
Specify queue-full and queue-empty behaviour. A divert event with an empty queue must not silently mean Short. A gauge exit when the queue is full must not overwrite an unconsumed classification. Decide the order when enqueue and dequeue occur in the same evaluation, then test that order at both boundaries.
Object order is another assumption. A FIFO associates the first departing gauge record with the first arriving divert event only if objects preserve order and relevant events are neither lost nor duplicated. Side entry, manual removal, recirculation and merged streams can violate that assumption.
A shift register indexed by distance is a different model. It needs a defined position increment, tracking resolution, object occupancy representation and handling of stopped or reversed movement. A fixed travel timer alone does not maintain position when actual speed changes. Treat these as separate extensions rather than promising that one flag scales to a production sorter.

South African course and portfolio questions
If you are comparing PLC training in Gauteng, KwaZulu-Natal or the Western Cape, ask the provider to demonstrate the same event trace in the actual software used on the course. Location does not establish which controller, timer library or simulation features are included. Request the equipment list and the learner’s practical tasks.
A useful course exercise should let you inspect the hidden tracking state, introduce an unexpected carton and explain how recovery works. Ask whether the lesson includes just classification, a single-object sequence, a queue or actuator confirmation. Those are different learning outcomes and deserve separate evidence.
For a portfolio, include the contract, state diagram, normal trace and three failed test cases with corrections. Describe the work as a simulated sorting exercise. Do not present a conceptual image as a commissioned South African installation or claim throughput, reduced damage or production savings that you have not measured.
The online PLC training guide can help frame delivery questions. Training for engineering students discusses learning evidence, while the training-centre guide covers institutional evaluation. Keep completion records distinct from a registered qualification or employer authorisation.
Questions learners ask about PLC height sorting
Can two photoeyes measure carton height accurately?
This exercise produces a category from observed Boolean inputs. It does not calculate a continuous height or establish measurement uncertainty. Sensor geometry, alignment and the definition of the category would need separate evidence in a physical application. “High was observed” is the supported conclusion here.
Why should I latch HighEye rather than sample it at exit?
The accepted interval may contain a high observation that has ended by the time LowEye falls. SeenHigh remembers that observation. The approach also retains brief unwanted high observations, so it does not replace validation of signal quality or a separately defined filtering rule.
Can I stop and restart without losing the carton record?
This model intentionally clears the record and requires reset after interruption. A retained-record version is possible only with a different recovery specification: explain how you know the carton and detection sequence remain associated. Do not assume that retained memory alone proves retained physical identity.
Does an 800 ms pulse guarantee a successful push?
No. It specifies the virtual command interval under this model. To study confirmation, add a separate supplied DivertConfirmed event and a defined observation window. Distinguish “command issued”, “confirmation observed” and “confirmation missing”; missing confirmation alone does not identify a unique physical cause.
Can I practise this without a physical sorting conveyor?
You can study the state transitions with supplied inputs and a compatible programming environment. Check which instructions and editing features it supports before translating the full exercise. A simulator may help reveal logic errors while leaving physical sensing, movement and actuator behaviour outside the model.

Continue with sensor interpretation and scan observation
Use sensor practice in PLC Simulation Software to explore the product’s sensor learning entry point. For execution order, inspect its scan-cycle highlighting feature. These are relevant next steps, not a claim that this exact sorter is a supplied, graded project on a particular plan.
Return to the PLC programming examples collection to compare this record lifecycle with counters, timed sequences and other exercises. Your strongest result is a trace that explains which object the record represents, when that record is consumed and what happens when the declared assumptions fail.