Here is the Bumper Class with polling thread to read the bumpers asynchronously from the consumer (test main() in the same file) and my control-c handler that can call a class object's cancel function to kill the thread and clean up: (I have the feeling I don't need the global statements.)
[code]
#
# myPyLib.py SUPPLIMENTAL PYTHON FUNCTIONS
#
# v0.1 19June2016
import time
import sys
import signal
# ######### CNTL-C #####
# Callback and setup to catch control-C and quit program
_funcToRun=None
def signal_handler(signal, frame):
print '\n** Control-C Detected'
if (_funcToRun != None):
_funcToRun()
sys.exit(0)
# Setup the callback to catch control-C
def set_cntl_c_handler(toRun):
global _funcToRun
_funcToRun = toRun
signal.signal(signal.SIGINT, signal_handler)
[/code]
[code]
#!/usr/bin/python
#
# bumbersClass.py BUMPERS SENSOR CLASS
#
import PDALib
import myPDALib
import myPyLib
import time
import sys
import threading
class Bumpers():
# CLASS VARS (Avail to all instances)
# Access as Bumpers.class_var_name
pollThreadHandle=None # the SINGLE read sensor thread for the Bumpers class
tSleep=0.033 # time for read_sensor thread to sleep after each read op
# Bumpers are on the Pi Droid Alpha MCP23S17 DIO expander
# Wired to use internal pull-up power of the MCP23S17
# Bumper value is negative logic - 0 means bumper activated, normal 1
LeftBumperDIO=18
RightBumperDIO=17
RearBumperDIO=16
# Allowable Bumpers.state values
NONE = 0
# Single bumpers
LEFT = 1
RIGHT = 2
REAR = 4
# Combinations
FRONT = 3
LEFTREAR = 5
RIGHTREAR= 6
ALL = 7
# Not possible
UNKNOWN = 8
# THE STATE OF EACH BUMPER and the combined BUMPERS state
# (class vars because there are only one physical bumper)
# note: can get rid of left(), right(), rear() methods by using these vars direct
leftState= UNKNOWN
rightState=UNKNOWN
rearState= UNKNOWN
state= UNKNOWN #0,1=L,2=R,3=L+R(front),4=Rear,...
# use to print Bumper.state var
bumperStrings=["NONE", "LEFT", "RIGHT", "FRONT", "REAR",
"LEFTREAR", "RIGHTREAR", "ALL", "UNKNOWN"]
# end of class vars definition
def __init__(self):
# SINGLETON TEST
if (Bumpers.pollThreadHandle!=None):
print "Second Bumpers Class Object, not starting pollingThread"
return None
# Set Bumper DIO channels as input for now
PDALib.pinMode(Bumpers.LeftBumperDIO, PDALib.INPUT)
PDALib.pinMode(Bumpers.RightBumperDIO,PDALib.INPUT)
PDALib.pinMode(Bumpers.RearBumperDIO, PDALib.INPUT)
# Set internal pull-ups on bumper channels
PDALib.setDioBit( PDALib.DIO_GPPU, 8 ) # set LeftBumper pin 16 pull-up
PDALib.setDioBit( PDALib.DIO_GPPU, 9 ) # set RightBumper pin 17 pull-up
PDALib.setDioBit( PDALib.DIO_GPPU, 10 ) # set RearBumper pin 18 pull-up
# threading target must be an instance
Bumpers.pollThreadHandle = threading.Thread( target=self.pollBumpers,
args=(Bumpers.tSleep,))
Bumpers.pollThreadHandle.start()
#end init()
# BUMPER THREAD WORKER METHOD TO READ BUMPERS
def pollBumpers(self,tSleep=0.01):
print "pollBumpers started with %f" % tSleep
t = threading.currentThread() # get handle to self (pollingBumpers thread)
while getattr(t, "dorun", True): # check the dorun thread attribute
self.read()
time.sleep(tSleep)
print("dorun went false. Stopping pollBumpers thread")
def read(self): #READ THE BUMPERS - can be used as poll or directly
Bumpers.leftState= Bumpers.LEFT - Bumpers.LEFT * \
PDALib.digitalRead(Bumpers.LeftBumperDIO)
Bumpers.rightState= Bumpers.RIGHT - Bumpers.RIGHT * \
PDALib.digitalRead(Bumpers.RightBumperDIO)
Bumpers.rearState= Bumpers.REAR - Bumpers.REAR * \
PDALib.digitalRead(Bumpers.RearBumperDIO)
Bumpers.state = Bumpers.leftState + Bumpers.rightState + Bumpers.rearState
return Bumpers.state
def status(self):
return Bumpers.state
def left(self):
return Bumpers.leftState
def right(self):
return Bumpers.rightState
def rear(self):
return Bumpers.rearState
def toString(self,bumperState=UNKNOWN):
if (bumperState==Bumpers.UNKNOWN):
bumperState= Bumpers.state
return Bumpers.bumperStrings[bumperState]
def cancel(self):
print "bumpers.cancel() called"
self.pollThreadHandle.dorun = False
myPDALib.PiExit()
# ##### BUMPER CLASS TEST METHOD ######
# creates two instances, only the first should start the read() thread
# the first time through the main() while loop, the sensors may not have been read yet
# so bumpers.status() and each bumper may have a value of 8/UNKNOWN
def main():
# note: lowercase bumpers is object, uppercase Bumpers is class (everywhere in code)
bumpers=Bumpers() #create an instance which starts the read bumpers thread
bumpersNoThreadStart=Bumpers() # Test a second instance of class
myPyLib.set_cntl_c_handler(bumpers.cancel) # Set CNTL-C handler
while True:
print "\n"
print "bumpers.state: %d %s" % (bumpers.status(), bumpers.toString())
print "left():%d rear():%d right():%d" % (
bumpers.left(),
bumpers.rear(),
bumpers.right() )
time.sleep(1)
#end while
if __name__ == "__main__":
main()
[/code]