Black Lives Matter - Action and Equality. ... Adafruit is open and shipping.
0

Rotary encoder support on RPI with Blinka
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Rotary encoder support on RPI with Blinka

by cache_return on Tue Apr 14, 2020 9:40 am

I have read that CircuitPython supports rotary encoders via rotaryio. I was trying to attach two of these via GPIO on a raspberry Pi and use adafruit-blinka to run them, but I can't find the function. Does it exist?

cache_return
 
Posts: 8
Joined: Tue Sep 19, 2017 2:59 pm

Re: Rotary encoder support on RPI with Blinka

by tannewt on Tue Apr 14, 2020 4:51 pm

I don't believe Blinka support rotaryio because it is implemented at a low level that may be challenging within Linux.

tannewt
 
Posts: 1685
Joined: Thu Oct 06, 2016 8:48 pm

Re: Rotary encoder support on RPI with Blinka

by cache_return on Tue Apr 14, 2020 8:12 pm

I don't believe it's supported either. If this is true, the question is what do I do?

cache_return
 
Posts: 8
Joined: Tue Sep 19, 2017 2:59 pm

Re: Rotary encoder support on RPI with Blinka

by tannewt on Wed Apr 15, 2020 4:13 pm

What are you trying to use the rotary encoders for?

tannewt
 
Posts: 1685
Joined: Thu Oct 06, 2016 8:48 pm

Re: Rotary encoder support on RPI with Blinka

by cache_return on Thu Apr 16, 2020 1:05 pm

Encoder 1: Volume control (via mpc volume+/-1) and Play/Pause (via mpc toggle).
Encoder 2: Scroll up/down (with up arrow and down arrow) and Enter key.

I am finding a lot of examples where people have attempted this, but I was hoping blinka would be less buggy than the ones I tried.

cache_return
 
Posts: 8
Joined: Tue Sep 19, 2017 2:59 pm

Re: Rotary encoder support on RPI with Blinka

by tannewt on Fri Apr 17, 2020 1:26 pm

I'd recommend picking up a cheap external CircuitPython board like an ItsyBitsy M4. It can translate the rotary encoders to USB HID which can control the Raspberry Pi. This is a good guide for it: https://learn.adafruit.com/rotary-encoder/circuitpython

tannewt
 
Posts: 1685
Joined: Thu Oct 06, 2016 8:48 pm

Re: Rotary encoder support on RPI with Blinka

by cache_return on Tue Apr 21, 2020 9:42 am

Here is how I solved the problem. It's not perfect (sometimes the scrolling jitters a little), but it's pretty good.

Code: Select all | TOGGLE FULL SIZE
import os
import signal
import subprocess
import sys
import threading

class RotaryEncoder:
  """
  A class to decode mechanical rotary encoder pulses.

  Ported to RPi.GPIO from the pigpio sample here:
  http://abyz.co.uk/rpi/pigpio/examples.html
  """

  def __init__(self, gpioA, gpioB, callback=None, buttonPin=None, buttonCallback=None):
    """
    Instantiate the class. Takes three arguments: the two pin numbers to
    which the rotary encoder is connected, plus a callback to run when the
    switch is turned.

    The callback receives one argument: a `delta` that will be either 1 or -1.
    One of them means that the dial is being turned to the right; the other
    means that the dial is being turned to the left. I'll be damned if I know
    yet which one is which.
    """

    self.lastGpio = None
    self.gpioA    = gpioA
    self.gpioB    = gpioB
    self.callback = callback

    self.gpioButton     = buttonPin
    self.buttonCallback = buttonCallback

    self.levA = 0
    self.levB = 0

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(self.gpioA, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(self.gpioB, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    GPIO.add_event_detect(self.gpioA, GPIO.BOTH, self._callback)
    GPIO.add_event_detect(self.gpioB, GPIO.BOTH, self._callback)

    if self.gpioButton:
      GPIO.setup(self.gpioButton, GPIO.IN, pull_up_down=GPIO.PUD_UP)
      GPIO.add_event_detect(self.gpioButton, GPIO.FALLING, self._buttonCallback, bouncetime=500)


  def destroy(self):
    GPIO.remove_event_detect(self.gpioA)
    GPIO.remove_event_detect(self.gpioB)
    GPIO.cleanup()

  def _buttonCallback(self, channel):
    self.buttonCallback(GPIO.input(channel))

  def _callback(self, channel):
    level = GPIO.input(channel)
    if channel == self.gpioA:
      self.levA = level
    else:
      self.levB = level

    # Debounce.
    if channel == self.lastGpio:
      return

    # When both inputs are at 1, we'll fire a callback. If A was the most
    # recent pin set high, it'll be forward, and if B was the most recent pin
    # set high, it'll be reverse.
    self.lastGpio = channel
    if channel == self.gpioA and level == 1:
      if self.levB == 1:
        self.callback(1)
    elif channel == self.gpioB and level == 1:
      if self.levA == 1:
        self.callback(-1)

cache_return
 
Posts: 8
Joined: Tue Sep 19, 2017 2:59 pm

Please be positive and constructive with your questions and comments.