Skip to content
This repository was archived by the owner on Mar 23, 2019. It is now read-only.

Commit

Permalink
Added enhanced RotaryEncoder class
Browse files Browse the repository at this point in the history
Added Button class
  • Loading branch information
andig committed Mar 1, 2013
1 parent 613384e commit cb15283
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 0 deletions.
38 changes: 38 additions & 0 deletions gaugette/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import wiringpi
import time

class Button:

# button states
OFF = 0 # button inactive (not pressed)
PRESS = 1 # button pressed and quickly released
LONG = 2 # button pressed and still held
ACTIVE = 3 # button pressed but not yet released (internal state)

def __init__(self, pin, longpress=0.3):
self.pin = pin
self.longpress = longpress
self.state = Button.OFF
self.io = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_PINS)
self.io.pinMode(self.pin, self.io.INPUT)
self.io.pullUpDnControl(self.pin, self.io.PUD_UP)

def get_state(self):
state = self.io.digitalRead(self.pin) ^ 1 # low-active

# button state model
if self.state == Button.PRESS: self.state = Button.OFF

if self.state == Button.OFF and state:
self.state = Button.ACTIVE
self.pressed = time.time()
elif self.state == Button.ACTIVE:
if state:
if time.time()-self.pressed >= self.longpress: self.state = Button.LONG
else:
self.state = Button.PRESS
elif self.state == Button.LONG and not state:
self.state = Button.OFF

#if self.state not in [Button.OFF, Button.ACTIVE]: print("Button: %s" % ["OFF","PRESS","LONG","ACTIVE"][self.state])
return self.state
133 changes: 133 additions & 0 deletions gaugette/rotary_encoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#----------------------------------------------------------------------
# rotary_encoder.py from https://github.com/guyc/py-gaugette
# Guy Carpenter, Clearwater Software
#
# This is a class for reading quadrature rotary encoders
# like the PEC11 Series available from Adafruit:
# http://www.adafruit.com/products/377
# The datasheet for this encoder is here:
# http://www.adafruit.com/datasheets/pec11.pdf
#
# This library expects the common pin C to be connected
# to ground. Pins A and B will have their pull-up resistor
# pulled high.
#
# Usage:
#
# import gaugette.rotary_encoder
# A_PIN = 7 # use wiring pin numbers here
# B_PIN = 9
# encoder = gaugette.rotary_encoder.RotaryEncoder(A_PIN, B_PIN)
# while 1:
# delta = encoder.delta() # returns 0,1,or -1
# if delta!=0:
# print delta
import wiringpi
import math
import threading
import time
class RotaryEncoder(object):
#----------------------------------------------------------------------
# Pass the wiring pin numbers here. See:
# https://projects.drogon.net/raspberry-pi/wiringpi/pins/
#----------------------------------------------------------------------
def __init__(self, a_pin, b_pin):
self.a_pin = a_pin
self.b_pin = b_pin
self.gpio = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_PINS)
self.gpio.pinMode(self.a_pin, self.gpio.INPUT)
self.gpio.pullUpDnControl(self.a_pin, self.gpio.PUD_UP)
self.gpio.pinMode(self.b_pin, self.gpio.INPUT)
self.gpio.pullUpDnControl(self.b_pin, self.gpio.PUD_UP)
self.last_delta = 0
self.r_seq = self.rotation_sequence()
# Gets the 2-bit rotation state of the current position
# This is deprecated - we now use rotation_sequence instead.
def rotation_state(self):
a_state = self.gpio.digitalRead(self.a_pin)
b_state = self.gpio.digitalRead(self.b_pin)
r_state = a_state | b_state << 1
return r_state
# Returns the quadrature encoder state converted into
# a numerical sequence 0,1,2,3,0,1,2,3...
#
# Turning the encoder clockwise generates these
# values for switches B and A:
# B A
# 0 0
# 0 1
# 1 1
# 1 0
# We convert these to an ordinal sequence number by returning
# seq = (A ^ B) | B << 2
#
def rotation_sequence(self):
a_state = self.gpio.digitalRead(self.a_pin)
b_state = self.gpio.digitalRead(self.b_pin)
r_seq = (a_state ^ b_state) | b_state << 1
return r_seq
# Returns offset values of -2,-1,0,1,2
def get_delta(self):
delta = 0
r_seq = self.rotation_sequence()
if r_seq != self.r_seq:
delta = (r_seq - self.r_seq) % 4
if delta==3:
delta = -1
elif delta==2:
delta = int(math.copysign(delta, self.last_delta)) # same direction as previous, 2 steps
self.last_delta = delta
self.r_seq = r_seq
return delta

class Worker(threading.Thread):
def __init__(self, a_pin, b_pin):
threading.Thread.__init__(self)
self.lock = threading.Lock()
self.encoder = RotaryEncoder(a_pin, b_pin)
self.daemon = True
self.delta = 0
def run(self):
while True:
delta = self.encoder.get_delta()
with self.lock:
self.delta += delta
time.sleep(0.001)
def get_delta(self):
# revisit - should use locking
with self.lock:
delta = self.delta
self.delta = 0
return delta


# extension by [email protected]

class RotaryEncoder2(rotary_encoder.RotaryEncoder):
#----------------------------------------------------------------------
# Pass the wiring pin numbers here. See:
# https://projects.drogon.net/raspberry-pi/wiringpi/pins/
#----------------------------------------------------------------------
def __init__(self, a_pin, b_pin):
self.ao = self.bo = 1
super(RotaryEncoder2, self).__init__(a_pin, b_pin)

def rotation_sequence(self):
a_state = self.gpio.digitalRead(self.a_pin)
b_state = self.gpio.digitalRead(self.b_pin)
r_seq = (a_state << 1) | b_state
return r_seq

# Returns offset values of -1,0,1
def get_delta(self):
delta = 0
r_seq = self.rotation_sequence()
if r_seq != self.r_seq:
if self.r_seq == 3:
if r_seq == 1:
delta = 1
else:
delta = -1
self.r_seq = r_seq
return delta

0 comments on commit cb15283

Please sign in to comment.