PiLauwers
Posts: 1
Joined: Wed Nov 29, 2017 8:16 pm

Minimalistic rotary encoder with gpiozero

Wed Nov 29, 2017 10:27 pm

A rotary encoder is an electronic device that converts a rotation in an electric signal. This post applies to the cheap mechanical incremental rotary encoders with three wires (A,B and ground) and an obvious click every time you turn them a bit.
rotary encoder.jpg
rotary encoder.jpg (3.86 KiB) Viewed 197 times
I was inspired by the Ultimate rotary encoder switch decoder post from hrvoje, but I use python with the gpiozero library to simplify the code. Gpiozero is, a simple interface to GPIO devices with Raspberry Pi.

The result is simple and clean code, but you might get a false event now and again.

hrvoje uses the fact that each turn from one stable position to the next results in four state transitions on pins A and B, but we are only interested in the last transition. We don't need the intermediate transitions to determine the direction.
With this in mind, there are only two transitions that interest us:
  • Pin B rising while A is active is a clockwise turn
  • Pin A rising while B is active is an anti clockwise turn
Maybe a diagram can make this more clear.
Moving from left to right corresponds to turning clockwise.
Moving from right to left corresponds to turning anti clockwise
incremental rotary encoder.svg.png
incremental rotary encoder.svg.png (22.88 KiB) Viewed 197 times
Attach the rotary encoder to the raspberry pi. Of course you can use other GPIO pins, just adapt the code accordingly.
  • Pin A to GPIO2
  • Pin B to GPIO3
  • Gnd to any ground pin
There is no need for pull-up resistors (the pi has in build pull-up resistors) or debouncing capacitors (they could help to avoid false events).
Using gpiozero, each pin of the rotary encoder can be manipulated as a button. The signal of a button goes high when it's pressed. So the rising edge of a pin corresponds to a when_pressed event in gpiozero terminology.
Two event handlers are created, one for each pin, but the event is only relevant when the other pin is active (high) at the time of the event (remember pin B rising while A is active is a clockwise turn).

That results in the following python code (make sure you have the gpiozero library installed)

Code: Select all

#!/usr/bin/python

from gpiozero import Button

pin_a = Button(2,pull_up=True)         # Rotary encoder pin A connected to GPIO2
pin_b = Button(3,pull_up=True)         # Rotary encoder pin B connected to GPIO3

def pin_a_rising():                    # Pin A event handler
    if pin_b.is_pressed: print("-1")   # pin A rising while A is active is a clockwise turn

def pin_b_rising():                    # Pin B event handler
    if pin_a.is_pressed: print("1")    # pin B rising while A is active is a clockwise turn

pin_a.when_pressed = pin_a_rising      # Register the event handler for pin A
pin_b.when_pressed = pin_b_rising      # Register the event handler for pin B

input("Turn the knob, press Enter to quit.\n")
Running the code and turning the knob will result in

Code: Select all

$ ./rotary-test.py 
Turn the knob, press Enter to quit.
1
1
1
-1
-1
1
In general, it's not a good idea to execute many statements in an event handler (interrupt routine). One way to deal with this would be to use a queue where events are posted by the event handler and then handled later by the main function:

Code: Select all

#!/usr/bin/python

from gpiozero import Button
import Queue

eventq = Queue.Queue()

pin_a = Button(2)                      # Rotary encoder pin A connected to GPIO2
pin_b = Button(3)                      # Rotary encoder pin B connected to GPIO3

def pin_a_rising():                    # Pin A event handler
    if pin_b.is_pressed: eventq.put(-1)# pin A rising while A is active is a clockwise turn

def pin_b_rising():                    # Pin B event handler
    if pin_a.is_pressed: eventq.put(1) # pin B rising while A is active is a clockwise turn

pin_a.when_pressed = pin_a_rising      # Register the event handler for pin A
pin_b.when_pressed = pin_b_rising      # Register the event handler for pin B

while True:
    message = eventq.get()
    print(message)
I hope this example encourages you to turn the knob.

Return to “Interfacing (DSI, CSI, I2C, etc.)”

Who is online

Users browsing this forum: No registered users and 9 guests