On a 1.5 m zone pitch at 0.28 m/s, a 600 mm carton is invisible to both photo-eyes for 3.2 seconds of its journey between them. An upstream zone whose release permissive is nothing more than “the next eye is clear” will use that window to send a second carton, and the two of them arrive at the scanner as one. That is the whole failure, and ZPA conveyor singulation is not fixed with a longer timer – it is deciding, in the logic, which zone owns the box while no eye can see it. Everything below is worked on the line from the zone logic article: a 5069-L320ER CompactLogix, one retroreflective eye per zone at the discharge end, a PowerFlex 525 per zone motor, logic in a 50 ms periodic task, zone pitch 1.5 m, belt speed 0.280 m/s measured with a chalk mark and a stopwatch, product 600 mm cartons.
What ZPA conveyor singulation means once it is in ladder
One sentence with two halves, and the second half is the one that gets left out.
A release sends exactly one product out of a zone, and the zone stays inhibited until that product is confirmed to have arrived somewhere else – confirmed, not assumed, the confirmation being a downstream eye making, and until it makes the box belongs to the zone that released it. Zero-pressure accumulation is the mechanical half of the same idea: product queues without pressing on the product in front, because each zone stops independently, which is what makes a full line restartable and what stops cartons being crushed at the bottom of a queue. Singulation is what turns that mechanical arrangement into one box at a time going somewhere. Without it you have a conveyor that accumulates beautifully and discharges in clumps.
The blind spot, with numbers
Put the eye at the discharge end of each zone, which is where it normally goes.
A carton’s leading edge breaks eye 3 at time zero. The trailing edge clears eye 3 once the box has travelled its own length, 600 mm at 0.280 m/s, which is 2.14 seconds; the leading edge reaches eye 4 once the box has travelled the full 1.5 m pitch, which is 5.36 seconds. Between those two moments no eye on the conveyor can see the carton at all – 3.2 seconds, nine hundred millimetres of travel – and on a good day that gap in coverage is invisible, because the next carton is far enough back that nobody notices what the logic believed during it.
| Product | Blocked at eye 3 | Reaches eye 4 | Seen by nothing |
|---|---|---|---|
| 300 mm tote | 1.07 s | 5.36 s | 4.29 s |
| 600 mm carton | 2.14 s | 5.36 s | 3.22 s |
| 1200 mm carton | 4.29 s | 5.36 s | 1.07 s |
The short product has the longer blind spot, which is the opposite of what most people expect, and it is the reason a line that runs cleanly on big cartons starts double-releasing the week somebody introduces a small one.

Eyes at the discharge end of each zone leave a blind length equal to the pitch minus the product length. The arithmetic in this article is all about the box that lives inside it.
The permissive that causes the double release
Write it the obvious way and it looks right on the bench.
(* wrong, and it passes every test with one box on the line *)
Zone[i].Release := Zone[i].Occupied AND NOT Zone[i+1].PE;
Two cartons, nose to tail in zone 3, tell you what that rung really does. The first is released, clears eye 3 after 2.14 s, and for the next 3.2 s eye 4 is still clear because the box has not reached it yet, so the rung is true and the second carton is released. Both are now inside the same 1.5 m of conveyor and the only question left is whether they arrive at the sorter touching or merely too close to gap. The release itself had nothing wrong with it as a rung – it had everything wrong with it as a question, because the logic asked whether the downstream zone’s eye was blocked when what it needed to know was whether the downstream zone was free to accept a box. Those two are the same thing only when the conveyor between them is empty, which is exactly the condition that does not hold on an accumulating line.
An eye tells you about 50 mm of conveyor. It says nothing about the other 1450.
Ownership, and the handshake that carries it
Give the box an owner and the ambiguity goes away.
A zone holds Owns from the moment it releases until the downstream eye makes. A zone holds Expecting from the moment the upstream zone releases into it until its own eye makes. A zone is ready to accept only when its eye is clear and it is not expecting anything, and that second term is the whole article – it is the state that covers the blind spot, and it costs one BOOL per zone. A retentive timer carries each of those states, because a plain TON clears its accumulated value the moment its rung goes false and every one of these waits is interrupted by something.
(* ConveyorTask, 50 ms periodic - single release with ownership *)
FOR i := 1 TO 12 DO
Zone[i].Occupied := Zone[i].PE;
Zone[i].Ready := NOT Zone[i].PE AND NOT Zone[i].Expecting AND NOT Zone[i].Jam;
(* the gap: this zone stays held for 850 ms after each handover *)
Zone[i].HoldTmr.PRE := 850;
Zone[i].HoldTmr.TimerEnable := NOT Zone[i].Owns;
TONR(Zone[i].HoldTmr);
(* one release, on the edge, and only when the neighbour has said yes *)
ReleaseReq := Zone[i].Occupied AND Zone[i+1].Ready
AND NOT Zone[i].Owns AND Zone[i].HoldTmr.DN;
Release_OS[i] := ReleaseReq AND NOT Release_Last[i];
Release_Last[i] := ReleaseReq;
IF Release_OS[i] THEN
Zone[i].Owns := 1;
Zone[i+1].Expecting := 1;
Zone[i].HoldTmr.ACC := 0;
END_IF;
(* the zone drives only while it owns a box that is still in transit *)
Zone[i].RunReq := Line_Running AND Zone[i].Owns AND NOT Zone[i].Jam;
(* the handover completes on the downstream eye making, and on nothing else *)
IF Zone[i+1].PE AND Zone[i].Owns THEN
Zone[i].Owns := 0;
Zone[i+1].Expecting := 0;
Zone[i].XferTmr.ACC := 0;
END_IF;
(* the box that never arrived: 1.5 m / 0.28 m/s = 5.4 s, x1.5 margin *)
Zone[i].XferTmr.PRE := 8000;
Zone[i].XferTmr.TimerEnable := Zone[i].Owns;
TONR(Zone[i].XferTmr);
IF Zone[i].XferTmr.DN THEN
Zone[i].LostProduct := 1; (* alarm; do not silently clear Owns *)
END_IF;
END_FOR;
One line in there deserves calling out, and it is the comment on the lost-product timer. A zone that quietly forgets a box it cannot account for will carry on running and carry on releasing, and the box it lost is on the floor, under the frame, or wedged in the transfer where the next one is about to hit it – so the timer alarms with a zone number and a person goes and looks, rather than the state machine tidying itself up. The same argument applies to Expecting. Every bit in this handshake that waits for a sensor gets a preset and an alarm, because the alternative is a line that stops with no fault on the screen and nothing visibly wrong with it.

Top half: the release rung goes true again at 2.14 s because eye 4 is still clear. Bottom half: Expecting holds the permissive down until eye 4 makes at 5.36 s, and the second release waits.
The gap you are trying to create, and what eats it
Two zones running at the same speed cannot create a gap.
Product goes in one end and comes out the other with whatever spacing it already had, which on an accumulated line is none, so the gap has to come from time rather than from speed: hold the upstream zone after the handover completes and the box that left keeps moving while the box behind it does not, which at 0.280 m/s buys 280 mm of gap for every second of hold. Three things then take some of it back. The coast is the biggest – a zone commanded to stop does not stop, and ramping down from 0.280 m/s over 0.5 s the held carton travels another 70 mm into the gap you were building, which is the same half-the-ramp arithmetic as starting. The detection chain costs less than people think: a 42EF RightSight diffuse eye is rated at 1 ms, a 5069-IB16 input ships with a 1 ms filter, and one pass of a 50 ms task is the rest, so the whole chain is 52 ms and 15 mm of belt. And the next transfer costs more than people think, because a downstream section running 5% slower closes the gap by 5% of its own length, which over 6 m is 300 mm – the entire gap – and is why a gap measured at the release point and a gap measured at the scanner are two different numbers.
So work backwards from the gap the scanner actually needs:
| Term | 150 mm target gap |
|---|---|
| Gap required at the scanner | 150 mm |
| Coast of the held zone | 70 mm |
| Detection chain, 52 ms at 0.28 m/s | 15 mm |
| Total distance to buy | 235 mm |
| Hold time = 235 mm / 0.280 m/s | 839 ms |
| Preset | 850 ms |
Redo that with your belt speed and your own ramp before you use the number.
The 70 mm term is proportional to the ramp, and a drive whose decel has been stretched to stop tall product tipping over has eaten gap without anybody touching the program. On a PowerFlex 525 that ramp is P042 Decel Time 1, and the parameter is the time from Maximum Frequency down to 0 Hz rather than from wherever the drive happens to be running – so a zone commanded to 30 Hz on a 60 Hz maximum actually stops in half of P042, and doubling the parameter from 1.00 s to 2.00 s adds 70 mm to the coast and takes it straight out of the gap. That is the mechanism behind most “the scanner used to read fine” calls, and it is findable in an afternoon by comparing the drive parameters against the commissioning printout.
Slug release, and when it is the right answer
Single release is not the only mode and it is not always the one you want.
Slug release runs a group of zones together so the product inside the group moves as a block, nose to tail, with no gaps at all. It empties a full line into a truck, a lift or a downstream machine that takes product as fast as it arrives, and on this line it does that about three times faster than releasing one box at a time. The numbers: single release gives a cycle of 6.21 s per carton, 580 cartons an hour, with a 150 mm gap; slug release gives 2.14 s per carton, 1680 an hour, with nothing between the boxes. You do not get both out of one belt speed, and when a line genuinely needs gaps at slug throughput the gap gets made somewhere else – a discharge zone running faster than the accumulation zones, which is a speed-ratio problem and a different piece of logic entirely.

Same conveyor, same speed, same product. Single release waits 5.36 s for the handover confirmation plus the 850 ms hold; slug release just runs, and the discharge rate becomes the product length divided by the belt speed.
Slug release carries one condition and it is not negotiable. Everything in the slug must have somewhere to go before the slug starts, because releasing into a downstream that stops halfway through turns the zero-pressure line you paid for into a pressure line with the whole slug leaning on the front box. That is how crushed cartons appear on a conveyor that was specified not to crush them, and the mechanical people will look at the rollers first.
Two zones that disagree
The call usually comes in as “zone 5 has stopped and there is nothing on it”.
What happened is that the handover half-completed: zone 4 released, set Owns, and something – a bounce on the eye, a box that rocked and cleared the beam for one scan, a reset that cleared half the state – left zone 5 with Expecting set and no box coming. Zone 5 is not ready, so zone 4 will not release into it, and zone 4 is holding a box it believes it already released. Both zones are waiting for each other and neither of them will move without a person. It is the same defect as the double release seen from the other side: two zones with different opinions about where one box is.
Three things keep it rare and recoverable.
- One owner at a time, written in one place. If both the upstream and the downstream routine can set and clear
Expecting, one of them will eventually do it in the wrong scan order. - A timeout on every state that waits for a sensor.
Expectingneeds a preset just as much asOwnsdoes, and it needs to alarm rather than self-clear. - A reset that rebuilds state from the eyes, not from zero. After a jam clear or an E-stop, walk the array once, set
OccupiedfromPEfor every zone, clearOwnsandExpectingeverywhere, and let the line rediscover what it is holding.
Anything sitting in a blind spot at that moment is genuinely lost, and no program will find it.

The rung that does the work. Occupied, downstream ready, and not already owning a box – the third contact is the one missing from the version that double-releases.
Next step
Put a counter on every release and a counter on every completed handover, per zone, and trend the difference across a shift – they should be the same number, and the zone where they are not is the zone losing or duplicating product. That finds it without anybody standing at the line waiting for it to happen again. The two questions that follow are how to keep track of which box is which once they are all moving, where the array work in PLC indirect addressing and FIFO instruction usage is the mechanism, and how long a zone should wait before it calls something a jam, which is set from zone length and belt speed rather than copied from the last project.