How to handle encoder count overflow

Thread Starter

Embededd

Joined Jun 4, 2025
131
Hi all,

Suppose I have a conveyor where boxes (pink and white) pass one by one. A sensor detects if a box is pink, and about 1600 mm further there’s a rejector that should push only the pink ones out.

Now, I don’t have the hardware set up yet I’m just trying to develop the logic.

1757063082973.png

My thought process is:

  • An encoder is attached to the conveyor.
  • When the sensor sees a pink box, I note the current encoder count.
  • I add the distance-to-rejector (converted into encoder pulses) to get a target count.
  • Then, as the conveyor moves, I keep checking the encoder count. When it matches the target, I would fire the rejector.

This way it doesn’t matter if boxes are spaced randomly or if the conveyor speed changes, since everything is position-based.

The main doubt I’m stuck on is overflow. If the encoder counter rolls over (say it’s 16-bit), what’s the clean way to still check if the current count has reached the target count?

For example, if current count = 65530 and I add distance = 100 pulses, the target becomes 65630, but the counter will overflow. How should I handle that comparison correctly?
 

BobTPH

Joined Jun 5, 2013
11,463
All you need is a bit vector with as many bits as there are items between the sensor and the ejector. The sensor sets the lo bit if the item is pink, and the ejector ejects based on the high bit, then you shift the bits left by one.
 

Thread Starter

Embededd

Joined Jun 4, 2025
131
All you need is a bit vector with as many bits as there are items between the sensor and the ejector. The sensor sets the lo bit if the item is pink, and the ejector ejects based on the high bit, then you shift the bits left by one.
Thanks for the idea, Does the bit vector method will work if the spacing between boxes isn’t fixed?
 

panic mode

Joined Oct 10, 2011
4,864
you need to use encoder travel expressed as specific travel distance (increment). this value need to be smaller than the size of target that you are looking at (colored feature such as bottle cap). this increment will be one bit in your bit-vector. every time encoder moves that increment size, you will bit-shift entire vector.

next step is to populate bit vector with some data. you need sensor that is going to tell you what you are looking for (such as "wrong color"). this sensor is of course stationary and always looking at the same spot. but the output of this sensor will be stored as a bit in your bit-vector. as encoder runs, and products shift, so does the bit pattern in your bit-vector... if your increment is 3mm and pink cap size is 25mm, it means you will have some 8 samples (bits) in your bit array (25/3=8.xxx). more bits are ok (redundancy) as there may be some imperfections or smudges etc. in observed feature (colored area)... or.... the spacing is inconsistent (just to name some).

if your eject location is 1600mm away, you will need a bit array (bit vector) that is at least 1600mm/(3mm per bit)=533 bits.

you could of course use stack or arrays or whatever options exist in your platform but bit-vector is the most memory efficient.

you can see the same thing discussed often as students are seeking help with the assignments. here you can see the same thing but language is ladder logic:
https://mrplc.com/forums/topic/34719-ladder-diagram/#findComment-162321
 
Last edited:

Thread Starter

Embededd

Joined Jun 4, 2025
131
you need to use encoder travel expressed as specific travel distance (increment). this value need to be smaller than the size of target that you are looking at (colored feature such as bottle cap). this increment will be one bit in your bit-vector. every time encoder moves that increment size, you will bit-shift entire vector.
Sorry, but it’s still not clear to me whether your approach will work when the boxes are spaced randomly or only if the spacing is fixed.

I can implement a shift-register style solution in code, That part I understand, I can shift bits and check the reject position.

somethings like this c program

C:
#include <stdio.h>
#include <stdint.h>

int main() {
    uint8_t buffer = 0;  // 8-bit register  ( MSB 7 bit - LSB 0)
    int input;

    printf("Enter Box statuses (0=White, 1=Pink):\n");

    while (1)
    {
        for (int i = 0; i < 8; i++) {
            // Step 1: Read input (0=White, 1=Pink)
            scanf("%d", &input);

            // Step 2: insert new Box at bit0
            buffer = (buffer | input );

           // Step 3: Shift left
            buffer = (buffer << 1);

            // Step 4: Check rejector position (bit-7)
            if (buffer & (1 << 7))
                printf("Box REJECT \n");
            else
                printf("Box PASS \n");
        }
    }

    return 0;
}
But my confusion is: if the box spacing is random, how would this approach still line up correctly at the ejector? From what I can see, a shift-register works only if each box always takes up the same slot/spacing.

If you’re saying it does handle random spacing, could you please explain how? Because right now it looks like this method wouldn’t track properly unless spacing is fixed.?

@panic mode
 

BobTPH

Joined Jun 5, 2013
11,463
Sorry, but it’s still not clear to me whether your approach will work when the boxes are spaced randomly or only if the spacing is fixed
My initial post would only work with equal spacing. @panic mode’s modification works with random spacing.

Since there is a bit for each encoder pulse between the two stations, it can identify the position of the bad item with the exact same precision as your algorithm, which stored the computed count of the bad ones.

For example, let’s say there are 10 encoder counts between the stations. And there are 3 items at counts 1, 5 , and 7. And the one at 5 is bad.

Here is what the bits would look like coming out of the sensor, numbered 0 through 9 from left to right:

0 0 0 0 0 1 0 0 0 0

They arrive at the ejector 10 pulses later, and the 1 bit is there when the item should be ejected.

Now, if there are thousands of counts between the stations, this might be a bad idea, but for a reasonable number, it will be less data than storing the position (say 16 bits) for each bad one, which could be all of them. The coding is also simpler and more straightforward.
 

Thread Starter

Embededd

Joined Jun 4, 2025
131
For example, let’s say there are 10 encoder counts between the stations. And there are 3 items at counts 1, 5 , and 7. And the one at 5 is bad.

Here is what the bits would look like coming out of the sensor, numbered 0 through 9 from left to right:

0 0 0 0 0 1 0 0 0 0
If the bit shift happens at every encoder pulse, then the position accuracy is tied to that increment. For example, if 1 pulse = 1 mm, then everything gets quantized to 1 mm steps. But what if a object edge is detected at 1.5 mm? In that case, wouldn’t the system only catch it at 1 mm or 2 mm, depending on which pulse arrives, so there’s always a ±0.5 mm error?
 

BobTPH

Joined Jun 5, 2013
11,463
Correct, but storing the encoder count has exactly the same inaccuracy. Can you not see that that new method fires the ejector at exactly the same time as your original method?

The accuracy only needs to be enough to make sure the item is hit by the ejector, which, hopefully is not close to zero width.
 

MrChips

Joined Oct 2, 2009
34,628
The distance between the detector and ejector is a constant.
What you need is a digital monostable. When the object is detected, preset the counter to a known value. Count up or count down. When the count value is zero, fire the ejector.
 

panic mode

Joined Oct 10, 2011
4,864
Sorry, but it’s still not clear to me whether your approach will work when the boxes are spaced randomly or only if the spacing is fixed.
dozens of installations in several factories says that it does work and for many years

I can implement a shift-register style solution in code, That part I understand, I can shift bits and check the reject position.

somethings like this c program
no you don't... that does not work because you did not implement the idea correctly.
first of all your simulation sucks - you do not even display shifted data. next, the scanf is a blocking instruction. so your code only shifts when key is pressed. shifting needs to work all the time - as long as conveyor is running. if you were ever in a plant watching conveyor, you would know that it moves things even if some sensor did not catch something. once you make this part working, THEN you can think of injecting data into your buffer. and reacting to data that was shifted sufficiently...

1757192218552.png

Well not really, but it can help you examine what is going on.
1757192111530.png
 

Attachments

Last edited:

Thread Starter

Embededd

Joined Jun 4, 2025
131
dozens of installations in several factories says that it does work and for many years
I don’t doubt your point if it works in dozens of factories, that proves the approach. But I think most of those cases are PLCs using ladder logic.

Since I don’t know ladder and prefer working with microcontrollers, I’m mainly trying to understand how the same idea will be implemented in C on an MCU with just an encoder, sensor, and rejector.

no you don't... that does not work because you did not implement the idea correctly.
first of all your simulation sucks - you do not even display shifted data. next, the scanf is a blocking instruction. so your code only shifts when key is pressed. shifting needs to work all the time
This wasn’t meant to be the full code I only wrote it to show the basic shift-register logic. Obviously it was for PC, that’s why I used scanf; on an MCU the input would be coming directly from the sensor instead.

What I’m still struggling to understand is the core logic part: when the spacing between boxes isn’t fixed, how does the shift-register method still work ? That’s the piece I can’t see clearly yet

So what I think we need is very long 533 shift register that shift by one bit each encoder increment

Distance from sensor to ejector = 1600 mm.
Encoder resolution = 3 mm per pulse.
Number of pulses = 1600 ÷ 3 ≈ 533.

1757246192674.png
 

MrChips

Joined Oct 2, 2009
34,628
So what I think we need is very long 533 shift register that shift by one bit each encoder increment

Distance from sensor to ejector = 1600 mm.
Encoder resolution = 3 mm per pulse.
Number of pulses = 1600 ÷ 3 ≈ 533.

View attachment 355502
You don't need a very long 533-bit shift register.
A 10-bit counter can encode up to 1023, while a 16-bit counter is good to 65535.
What you need to measure is the interval between detected objects.
Reset the 16-bit counter to 0 and start counting at the first detected object. At the next object, save the object position and reset the running counter to 0. If the counter overflows, stop the counter.
 

panic mode

Joined Oct 10, 2011
4,864
programming language makes no difference. understanding and shaping the logic to produce behavior is what matters. do development in steps. make encoder work. then make bit shift work. then inject sensor data. this will allow you to visualize things and see the data flow.

with that you are 90% there. next step is to read the data in the specific location of the bit-vector. that is what my simulator shows in yellow. since this is just an index you should be able to easily and comfortably pick any location within bit-vector.

the final steps is to do something with the data - perform an action. in my demo simulator, i just show the label REJECT.... but the exact action depends on specific setup. is this a diverter gate (stays open during REJECT signal), or pusher (performs one kick per rejected part) or something else... does the data stream contain gaps or not...

for example your data stream represents rejected product as 4 bits... so you would expect to see reject in data stream shown as
000000011110000000000000000

but, what happens if you see this
000000001111111111111111000

is this one defect or three defects without gap?

normal solution is to create trigger on a rising edge. this gets you single sharp pulse regardless how many "1" follow. then use that trigger to extend the action - use a monostable or do it all in software. this will work great is data stream in your bit-vector contains gaps.
but it will not work well for the last scenario that had three rejects without any gaps.
in that case you need to modify action logic. one simple way is to just look at one bit for reject status. if that bit is "1", set several of following bits to zero (in the data stream).

00000000111111111111111100000000
original stream, right most bit is the reject station and reject part is 4 bits wide. that means, when you sense the reject, you activate reject logic and clear the 4 bits so you get this:
00000000111111111111000000000000
lets summarize, as the data shifts you will get
00000000111111111111111100000000 at the moment right most bit reaches reject index
00000000111111111111000000000000 we activate reject logic and clear 4 bits
00000000011111111111100000000000 the data continues to shift based on encoder logic
00000000001111111111110000000000
00000000000111111111111000000000

00000000000011111111111100000000 and now the next bit is at reject station and logic repeats
00000000000011111111000000000000 activate reject, clear 4 bots on the right etc.

with this implemented you can handle anything, different gaps or no gaps.
 
Last edited:

BobTPH

Joined Jun 5, 2013
11,463
You don't need a very long 533-bit shift register.
A 10-bit counter can encode up to 1023, while a 16-bit counter is good to 65535.
What you need to measure is the interval between detected objects.
Reset the 16-bit counter to 0 and start counting at the first detected object. At the next object, save the object position and reset the running counter to 0. If the counter overflows, stop the counter.
And a data structure that can keep that data for each item between the detector and ejector. If the distance between items is, say, 10 cm, then you need 160 sixteen bit counters or 2560 bits. The bit-vector algorithm is simpler to implement and will generally use less data space.
 

MrChips

Joined Oct 2, 2009
34,628
If you want to go with the long shift register solution, that is doable in software.
Fifty 16-bit registers would give you an 800-bit shift register.
 

panic mode

Joined Oct 10, 2011
4,864
don't know the exact size of lego but pictured should be some 16mm. so 1600mm travel could have up to 100 blocks... is most compact form that could be represented by 100bits. 100bits / (8 bits per byte) = 12.5 bytes or 13 bytes. if stored as 16bit values, that would be 14 bytes or 7 integers/words.
 

drjohsmith

Joined Dec 13, 2021
1,549
The distance between the detector and ejector is a constant.
What you need is a digital monostable. When the object is detected, preset the counter to a known value. Count up or count down. When the count value is zero, fire the ejector.
Wont the op need multiple monostable though , if the distance between the sencor and the ejector was a max of say 12 blocks , then you could conceptually have 12 timing events to follow.
 

MrChips

Joined Oct 2, 2009
34,628
Wont the op need multiple monostable though , if the distance between the sencor and the ejector was a max of say 12 blocks , then you could conceptually have 12 timing events to follow.
Having examined the problem more carefully, I have dropped the monostable solution and went with the long shift register in software.
 
Top