Rotary Encoder Help ?

Does anyone have experience with rotary (quadrature) encoders ?
I appear to get two events for every click of rotation.

I am using python to debounce the switch:

Code: Select all | TOGGLE FULL SIZE
`from gpiozero import Buttonimport timeinput_A = Button( 18, bounce_time = .1)input_B = Button( 23, bounce_time = .1)old_a = Trueold_b = Truedef get_encoder_turn():    # return -1, 0, or +1    global old_a, old_b    result = 0    new_a = input_A.is_pressed    new_b = input_B.is_pressed    if new_a != old_a or new_b != old_b :        if old_a == 0 and new_a == 1 :            result = (old_b * 2 - 1)        elif old_b == 0 and new_b == 1 :            result = -(old_a * 2 - 1)    old_a, old_b = new_a, new_b    time.sleep(0.001)    return resultx = 0while True:    change = get_encoder_turn()    if change != 0 :        x = x + change        print(x)`

BillPretty

Posts: 26
Joined: Sun Mar 07, 2021 2:44 pm

Re: Rotary Encoder Help ?

Both signals on the encoder change with each click, they just do it at different times. The code above will respond to both changes.

It looks like your code is similar to the running-sum decoding method, but can be simpler: just return 1 when channel A changes, -1 when channel B changes, and 0 if there's no change.

Then your variable 'x' in the while() loop will alternate between 0 and 1 when A changes first, and between -1 and 0 when B changes first.

Add a conditional to print the value of 'x' when it isn't 0, and you'll get one value that indicates direction per click.

Posts: 63679
Joined: Thu Feb 11, 2010 2:51 pm

Re: Rotary Encoder Help ?

Thanks for the help. The code is from a book I am reading, so I will try your method.

BillPretty

Posts: 26
Joined: Sun Mar 07, 2021 2:44 pm

Re: Rotary Encoder Help ?

I tried to implement your idea without success.
While trouble shooting with a DVM (all I have) I noticed that the output of terminal A and B is a pulse
rather than a steady state. I think my function needs more tests, but I'm not sure how to do this.

Code: Select all | TOGGLE FULL SIZE
`def get_encoder_turn():    # return -1, 0, or +1    global old_a, old_b    result = 0    new_a = input_A.is_pressed    new_b = input_B.is_pressed    if new_a != old_a :        if old_a == 0 and new_a == 1 :            result = 1    if new_b != old_b :   if old_b == 0 and new_b == 1:       result = 1    old_a, old_b = new_a, new_b    time.sleep(0.01)    return result`
Attachments
OutputTable.jpg (9.86 KiB) Viewed 137 times

BillPretty

Posts: 26
Joined: Sun Mar 07, 2021 2:44 pm

Re: Rotary Encoder Help ?

The switch values don't matter.. only whether they've changed since the last time you read them:

Code: Select all | TOGGLE FULL SIZE
`prev_a = 0prev_b = 0def check( a, b ):   global prev_a, prev_b   if ( a != prev_a ):      prev_a = a      return( 1 )      if ( b != prev_b ):      prev_b = b      return( -1 )      return( 0 )count = 0def direction( inc ):   global count      count += inc      if (( inc != 0 ) and ( count != 0 )):      print( count )in_a = [ 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0 ]in_b = [ 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0 ]for n in range( 0,16 ):   direction( check( in_a[ n ], in_b[ n ] ) )   for n in range( 0,16 ):   direction( check( in_a[ 15-n ], in_b[ 15-n ] ) )`
The code above iterates the same set of switch values in opposite directions. Going forward produces 1, going backward produces -1.

The sequences have duplicate values to approximate reading the switches and seeing no change. The loops only produce output when a switch value changes, and the 'count' value is nonzero.

Posts: 63679
Joined: Thu Feb 11, 2010 2:51 pm

Re: Rotary Encoder Help ?

Thanks to Google, I found a Python module called "Encoder" which I used to implement the following code:

Code: Select all | TOGGLE FULL SIZE
`import Encoderenc = Encoder.Encoder(18,23)while True:   x = enc.read()   print (x)`

I get the same results as with my other code (multiple events per click).
I believe I have a hardware problem so I intend to build the circuit shown below;
Attachments
EncoderCircuit 2.jpg (26.92 KiB) Viewed 119 times

BillPretty

Posts: 26
Joined: Sun Mar 07, 2021 2:44 pm

Re: Rotary Encoder Help ?

I have found that the following code works with the schematic shown above.
I used a 0.1uF capacitor and the circuit works reliably.
The 74HC14 works with a Vcc from 2 - 6 volts, so the circuit can also be used with the Arduino Uno.
The software uses a PWM (pin 10) of the Arduino to control the brightness of an LED.
The LED is connected to ground through a 270 ohm resistor.

Code: Select all | TOGGLE FULL SIZE
`# This code works with the Schmitt trigger circuit# It also talks to an Arduino Uno to control the# brightness of an LED using a PWM pin (10) of the Arduinoimport pyfirmata from gpiozero import Buttonimport timeboard = pyfirmata.Arduino('/dev/ttyACM0') led_pin = board.get_pin(' d:10:p') input_A = Button(18)input_B = Button(23)# Counter starts at 50 to avoid negative values# Software needs a test for counter < 0 and > 100counter=50change = 0 LastState=input_A.is_pressedwhile True:      aState=input_A.is_pressed   if aState > LastState:      bState=input_B.is_pressed      if bState != aState:            counter = counter+1      else:            counter = counter -1      change = 1         if aState !=0 and change==1:      print (counter)      led_pin.write( counter / 100.0)   LastState = aState   change = 0`

BillPretty

Posts: 26
Joined: Sun Mar 07, 2021 2:44 pm

Re: Rotary Encoder Help ?

Glad to hear you got things working. Happy hacking!