A 1024 PPR encoder on the tail roller of an 8 m belt, read in X4 by a 5069-HSC2xOB4, gives 652 counts for every 50 mm of belt, and a shift register that moves one cell every 652 counts knows where a carton is to within one cell whether the belt is running at 0.500 m/s, ramping, or standing still under an E-stop. The same register shifted on a timer was 100 mm wrong per zone the week the metering-belt trim moved the speed 5%, and it lost every carton on the belt the first time somebody hit the E-stop mid-transfer. Time is not position. The encoder is.
Shift on counts. Re-seed at every eye. Alarm on the carton that is not where the register says.
Everything below is on the takeaway belt from the merge and divert articles: a 5069-L320ER CompactLogix, one belt 8.0 m long at 0.500 m/s under a single PowerFlex 525, an induct eye PE_I where product lands on it, and four tracking zones of 2.0 m each with a 42EF polarised retroreflective eye at every boundary, PE_T1 to PE_T4. Tracking logic runs in the 50 ms conveyor task. The zones here are lengths of one belt between eyes, not accumulation zones with their own motors; the last section says why that matters.
What the encoder has to be on, and what it has to go into
The encoder goes on the roller the belt turns, not the roller the motor turns.
A drive roller slips under load. On this belt, loaded with six cartons, the drive roller ran 1.2% faster than the belt – measured by chalk-marking the belt and the roller edge and counting turns over 20 m – and 1.2% of 8 m is 96 mm, which is two cells of error by zone 4 before anything else has gone wrong. A tail roller or a snub roller is turned by the belt, so what it counts is belt. This line has a 100 mm crowned tail roller, 314.2 mm per turn, and the 1024 PPR encoder on it in X4 gives 4096 counts per turn, 0.0767 mm per count, 13.04 counts per millimetre; one 50 mm cell is 652 counts, and at 0.500 m/s the counter sees 6520 counts a second. That number rules out the ordinary input card. 5069-UM004 gives the Simple Count mode on a 5069-IB16 a maximum of 500 Hz, and the fast 5069-IB16F 30 kHz, and even the fast card counts one input with no direction, so a belt jogged backwards during a jam clear counts forwards. The 5069-HSC2xOB4 has six differential inputs, three per counter, does X1, X2 and X4 quadrature with direction from the A-B phase, and 5069-UM006 puts its maximum at 1 MHz. It is the right module and it is not an expensive one next to a lost carton at the sorter.
Count belt, not motor. Then count it with a module that can.
Two settings on the module matter and both are output tags rather than configuration. Counting starts when O.Counter00.Hold is written to 0 – 5069-UM006 says this is the one place the module differs from a 1769-HSC, which used an enable bit set to 1 – and the count is a ring counter that wraps between RolloverValue and RollunderValue, so the delta arithmetic in the task has to handle the wrap or the register will one day shift 160 cells in one scan. Set the rollover high, 1,000,000,000, and subtract with a wrap test.
![]()
Cells are 50 mm, 40 to a zone. The counter sees 6520 counts a second at 0.5 m/s, which is why the count lives in a 5069-HSC2xOB4 and not in the input card.
The register, and why it shifts on counts
One cell per 652 counts, every zone shifting together, each zone loading its own eye.
The register is four arrays of 40 bits, one per zone, and each shift is a BSL on each of them. 1756-RM018 describes what a BSL does exactly: it shifts the specified bits one position, unloads the top bit into the control’s .UL, and loads the source bit into bit 0, and it is transitional, executing once per false-to-true of the rung. The source bit for zone 1’s register is PE_I, so a 600 mm carton crossing the induct eye at a shift every 50 mm leaves twelve consecutive true bits in the register – the register carries the carton’s length as well as its position, with no timer and no speed in the arithmetic. The source bit for zone 2’s register is PE_T1, zone 3’s is PE_T2, zone 4’s is PE_T3. That is the re-seed, and it is the design decision the rest of the article defends: every zone’s register is loaded from a real detection at its own boundary, so whatever error the belt accumulated in the zone before is thrown away at the eye. A parallel DINT array per zone carries the carton ID alongside the bits, and on the boundary eye’s rising edge the ID sitting in the last three cells of zone 1 moves to cell 0 of zone 2.
(* ConveyorTask, 50 ms - shift on encoder counts, all four zones *)
Enc_Now := HSC:I.Counter00.Count;
Enc_Delta := Enc_Now - Enc_Last;
IF Enc_Delta < -500000000 THEN (* wrapped forward through RolloverValue *)
Enc_Delta := Enc_Delta + 1000000000;
END_IF;
Enc_Last := Enc_Now;
IF Enc_Delta > 0 THEN (* a jog backwards does not shift anything *)
Cells_Acc := Cells_Acc + Enc_Delta;
END_IF;
WHILE Cells_Acc >= 652 DO (* two cells if the task overran; never one *)
FOR z := 1 TO 4 DO
FOR c := 39 TO 1 BY -1 DO (* shift the IDs up from the top: not COP *)
Zone_ID[z, c] := Zone_ID[z, c - 1];
END_FOR;
Zone_ID[z, 0] := 0;
END_FOR;
Shift_Trigger := 1; (* the BSL rungs fire on this edge *)
Cells_Acc := Cells_Acc - 652;
END_WHILE;
The ID shift is a loop counting down from the top, and that is deliberate. COP looks like the instruction for it, and 1756-RM018 describes COP as a straight byte-to-byte copy of contiguous memory that must be tested to confirm it changes nothing you did not intend; the manual does not promise what happens when the source and destination overlap, and shifting an array up by one element is exactly that overlap. A loop from the top is 160 assignments a shift, ten shifts a second at full speed, and the 5069-L320ER does not notice. Shifting the bit registers is the BSL’s job and it needs no loop.
A loop from the top costs nothing; an overlapping COP costs a test.
![]()
Rung 50 shifts every zone on the same count. Rung 52 is the re-seed for the IDs; the bits re-seed themselves because each BSL’s source is its own boundary eye.
Why not a timer, since the belt runs at a fixed speed? Because it does not. The metering-belt trim upstream moves this belt’s reference by 0.25 Hz steps, a cold gearbox runs slow for the first twenty minutes, and a timer-shifted register carries every percent of speed error as a percent of distance: 5% is 100 mm per 2 m zone, two cells, and at zone 4 it is eight. And when the belt stops, a timer keeps counting unless every timer is gated on a run bit that is itself only an intention, and the ramp on either side of the stop is 0.25 s of belt that was neither running nor stopped. The encoder counts belt. A stopped belt makes no counts, a slow belt makes them slowly, and the register is right in both cases without a line of logic about it.
A stopped belt makes no counts. That sentence is the whole argument.
Re-seeding, and the two alarms it gives you for free
A register that is never corrected is a register that is eventually wrong.
Drift comes from the carton, not the encoder. A carton landing on the belt from the 0.280 m/s zone lags the belt while friction accelerates it, 8 to 26 mm on this line depending on the base; the divert paddle in zone 3 pushes every carton it touches and does not divert about 9 mm along the belt; product creeps on a belt with a slight incline. None of those is in the count, because the count is belt, and each one moves the carton off its record by a few millimetres per zone. Fifty cartons tracked with a single 160-cell register and the encoder on the drive roller were 90 to 175 mm ahead of the eye by PE_T4; the same fifty with the encoder on the tail roller were 10 to 55 mm ahead; with four re-seeded registers no carton was more than 25 mm off at any eye, because no zone carried more than its own 2 m of drift.
The re-seed window is the number that turns drift into a diagnosis. When PE_T1 makes, the logic looks for an ID in the last three cells of zone 1, cells 37 to 39, a window of 150 mm either side of where the record should be. Found: the ID moves to zone 2, cell 0, and the carton is exactly where the eye is. Not found: the eye has seen a carton the register does not know about – one placed on the belt by hand after a jam, or one whose induct detection was lost to a beam blocked by a strap – and that is an Untracked alarm with a new ID flagged unknown so the sorter downstream can send it to the exception lane rather than guess. The other direction is the register’s .UL: when the top bit of zone 1 unloads true, a carton record has reached the boundary, and if PE_T1 has stayed clear through the last three cells the carton is not there – it fell off, it was pulled, it is wedged under the divert – and that is a Lost alarm with the zone number. Both alarms cost nothing. They are what a register with a re-seed window knows that a register without one cannot.
Two alarms, no extra hardware, and both of them name the zone.
![]()
Worked from the article’s slip terms. One register drifts with distance; the re-seeded ones never carry more than one zone’s worth, and the window catches what falls outside it.
Three cells is not a universal number. It is the largest drift on this belt between two eyes, 26 mm at the induct plus 9 mm at the paddle plus creep, with margin, and a longer zone or a slicker product opens it. Set it from the measured drift and make it a per-zone tag, because zone 3 with the paddle in it needs a wider window than zone 1.
![]()
The two rows the encoder fixes outright are the timer rows. Everything below them is a few millimetres a zone, and the re-seed at the next eye throws it away.
Where this does not work
On accumulation zones with their own motors.
The twelve zones upstream of this belt each have a PowerFlex 525, and each one stops and starts on its own; an encoder on zone 7 says nothing about a carton on zone 5, and an encoder on every zone is twelve counter channels for a problem that does not need them. On those zones the carton’s position is a zone number, and the record moves when the ownership handshake hands it from one zone to the next on the downstream eye making – a shift register with a zone as the cell and the handover as the clock. The encoder register is for a belt that moves as one piece, where the question is not which zone but where in the zone, because a divert has to fire at a position and a scanner has to be told which ID it just read. Where the two meet, at PE_I, the accumulation record’s ID and measured length are handed into zone 1’s cell 0 on the induct eye’s rising edge, and from there the encoder carries them.
One belt, one encoder, one register. Twelve motors, twelve handovers, no encoder.
One more thing the register cannot do is survive a controller power cycle without help. The BSL control structures and the ID arrays are ordinary tags and keep their values, but Enc_Last has to be re-read from the counter before the first delta or the first scan shifts the register by the whole count since the last run. Set it on first scan, and treat what is on the belt after a long stop the way the photo-eye article treats a hand-placed carton: default the unknown to the longest product you run.
The thing everyone checks first
The encoder.
A carton that arrives at the divert 100 mm early sends people to the encoder, the coupling, the PPR setting, the counter module’s LEDs, and none of it is wrong, because an encoder that was wrong would be wrong for every carton by the same amount and this one is wrong by an amount that grows with the number of cartons on the belt. That is slip, and slip is the drive roller under a loaded belt, so the first check is where the encoder is mounted, and the second is whether the register is shifting on counts at all – a register that was quietly moved to a timer during commissioning “because the counter card had not arrived” is still on the timer three years later on more lines than anyone admits. Trend Cells_Acc and Enc_Delta at the task period for a minute: a delta that sits at 326 every 50 ms is an encoder doing its job, and a delta that is zero while the belt is visibly moving is a Hold tag nobody wrote to 0 after the module was replaced.
Slip grows with the load. A wrong PPR is wrong by the same amount every time.
Next step
Put the tracked leading-edge position of the carton nearest each boundary eye on the HMI next to the eye’s own state, and watch one shift: the difference at the moment each eye makes is the drift for that zone, and the largest one you see in a shift, with margin, is the re-seed window for that zone. Then count Untracked and Lost per zone per shift, because a zone that loses two cartons a shift has a mechanical problem the register has just told you the location of. The counter wiring itself – line-driver against single-ended, the shield, the 50 m the encoder cable is allowed – is in wiring an encoder to a high-speed counter input, and the array indexing the ID loop depends on is in PLC indirect addressing.