Go Down

Topic: Problem with rotary encoder (Read 2359 times) previous topic - next topic


I have a rotary encoder, similar to that one:


I have hooked it up to my stationary bike, with the code similar to the one in the link.

However, it does not work properly - the count is not reliable at all, the direction is often wrong. For example, if I turn the pedals in one direction, the counter does not go up steadily, but seems to alternate between some values... (e.g. 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2...).

First question is: is the encoder suitable at all for my purpose? The typical speed would be four full turns per second, maybe it is just too much for it?

Second question: what might be wrong with the code? Why is it alternating the value?


These sort of devices are often noisy especially if they are the cheaper contact type. The optical ones have much less contact bounce with them. Have you put any capacitors on the lines.
Also it might be more reliable if you just use one edge to detect a pulse not two.


The problem is the bad contact bounce with those cheap encoders. Normally one can deal with contact bounce using one of the button libraries, however I don't believe you can use that method inside a interrupt routine as they rely on millis() function which doesn't increment inside another interrupt routine. So you are left with two possible solutions:

Don't use interrupts and handle the inputs with normal digitalRead() function in you loop() code.  That way you can use software debouncing functions like in the button library. Your speed requirements don't seem to fast for this method but I don't know that for sure.

Use external contact bounce components to try and eliminate the contact bounce.

Or a third option is to buy a quality optical encoder that doesn't use mechanical switch contacts. They can be pricey, around $50 and up unless you find a used or surplus one on E-bay.



It is even worse - the encoder is so bad that even slight moves on the plane parallel to the rotation (i.e. "bending" of the axis) activates the contact...

I have decided to use an old ps2 mouse - the encoders are excellent and I think debouncing is done within the hardware. The problem would be with the "hardware" i.e. connecting it mechanically to the bike chain, but then it is a topic for another forum.


connecting it mechanically to the bike chain, but then it is a topic for another forum.

Maybe a friction coupling to the tire would work better with the 'mouse guts' encoder? The problem using a mouse encoders is their very high 'steps' per movements, it's going to really push up the interrupt rate.

I think you will be much better off not trying to use a mechanical encoder with interrupts, it's a bad combination.  ;)


You could use the holes in the chain as encoder, put a led above it and an LDR/photoresistor below and it will give you speed info. Counting teeth on the gear at the back will give the pulses per rotation. Double the hardware (a bit shifted) and you can detect direction of the chain too.

just thinking out loud. ;)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


The wheel is easy - it's what I'm trying out right now (it would be even easier if the rubber on the mouse wheel did not peel off due to age!). However, it's a freewheel (obviously) so only one direction is registered, and I'd like to have both. Also, the inertia is too high for my purposes - I will not win Split/Second season without delicate control of the throttle and brake ;)

I have thought of this, but did not know I could detect the direction... Could you explain that in more detail?


one led/ldr combination gives a square wave OK.

if we place the second one not exactly in sync with the first but a few mm further

       +-------+           +-------+
       | LED1  |           | LED2  |
       +-------+           +-------+

+-----+       +------+       +------+       +-------+

       +-------+           +-------+
       | PHR1  |           | PHR2  |
       +-------+           +-------+

If the chain moves to the right PHR1 sees the hole a small fraction earlier than PHR2 sees its hole
If the chain moves to the left PHR1 sees the hole a small fraction later than PHR2 sees its hole

connect  PHR1  to an IRQ routine (RISING) and use something like this.
Code: [Select]

volatile int direction;

void IRQ()
  if (digitatalRead(PHR2) == LOW) direction = RIGHT;  // or CW
  else direction = LEFT;  // CCW;

  count++; // for the speed

Practical problem might be dirt, => do the photoresistors above the chain so gravity works with you...; The leds are needed so it will also work at night ;)

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


I am not sure if I follow - is the difference due to the fact that due to delay between IRQ and readout of the second sensor it has been either covered or opened?

Anyway, it is not possible this way...

For this to work tension must be applied to the chain around the place the sensor is located (otherwise sagging of the chain will confuse the sensor). The problem is that with the forward movement the tension is on the lower part of the chain and with the backward movement on the top part... Of course, this in itself could be an indication of the direction of movement, now just to couple it with the speed reading...

Oh: the sprocket! The wheel itself is free, but the sprocket is not! No problem with the tension, either.

I guess I will have to sleep it over!

P.S. One more thing I forgot to mention - the advantage of hooking the mouse wheel to the chain (or, rather a small sprocket attached to it) instead of the main wheel is that the gear ratio is much more palatable... The sprocket I've got is somewhat smaller than the bike sprocket (did not get around to count the teeth), but not below 1:2 - the wheel speed is typically around 4 rotations per second, so I guess it should work out OK.


Unfortunately, I have failed miserably... I cannot construct a mechanism which would transfer the rotation reliably.

Therefore, I am reconsidering using Hall sensors or LED sensors. However, I have a problem with grasping the principle of the rotary encoding. I have looked at the diagram and the explanation above, I have read through the wiki several times and I still don't get it... For example, how does the code relates to the diagram here? If I read the PHR2 at the situation given in the diagram, I get... an indeterminate (between) state? Does Arduino wait till the sensor has a discrete value?


Does Arduino wait till the sensor has a discrete value?

Any use of a digital encoder device (mechanical, optical, or magnetic) works on the ability of the decoding circuitry (read that as arduino input pins and correct coding) to quickly detect a change of state of either channel's on/off signal. The mechanical seperation of the encoder channel sensors insures that the signals will always have 90 degrees (in the time domain) of seperation between the channels, so with accurate detection of when the channel signals change and adding proper decoding formula, one can accuratly determine when a step occurs and in what direction. If one only needed to know speed information, then just measuring the frequency of a single channel would be all that is required.



Most cheap rotary encoders using mechanical switch technology like this have a maximum speed rating of 60rpm or similar. About one rotation per second.  That's because the individual contacts take a ms or two to stop bouncing, and with 12 detents that's 48 contact positions per rotation to debounce... 

For fast rotation an optical encoder - such as the guts of a (computer) mouse - is required.  They also have a longer life.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]


Yes, a mouse seems definitely the way to go... It still does not work as I would like to, though. But I think I will move it to another topic.

Go Up

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131