First of all, I learned Python on my own from online tutorials and (mostly) learning by doing, so I might did some strange things in my code. :)
So, I am working om my first bigger project with Raspberry Pi, and for that I need codes running parallel. I wrote this part of my code for managing a simple D-pad:
Problematic code
import threading
import time
import pigpio
# input from the D-pad goes to these pins
BUTT_UP = 12
BUTT_LEFT = 16
BUTT_CENTER = 25
BUTT_RIGHT = 20
BUTT_DOWN = 21
class dpad_monitoring(threading.Thread):
'''thread for monitoring the D-Pad'''
def __init__(self, thread_ID, butt_up, butt_left, butt_center, butt_right, butt_down, res = 10.00):
threading.Thread.__init__(self)
self.running = True
self.thread_ID = thread_ID
# number of checks per sec
self.res = res
# key pins
self._pins = [butt_up, butt_left, butt_center, butt_right, butt_down]
#key monitor
self.last_pressed = 0
'''key numbers:
UP LEFT CENTER RIGHT DOWN
1 2 3 4 5 '''
# setting up GPIO
self.pi = pigpio.pi()
for i in range(0, len(self._pins)):
self.pi.set_mode(self._pins[i], pigpio.INPUT)
self.pi.set_pull_up_down(self._pins[i], pigpio.PUD_UP)
def stop(self):
'''stopping the thread cleanly'''
self.pi.stop()
self.running = False
def run(self):
'''checks which button is pressed as many times per sec as specified
in the res variable in init. If any of them is pressed, it suspends itself
until self.last_pressed is set to 0 again by main()'''
while self.running:
states = []
for i in range(0, len(self._pins)):
state = not self.pi.read(self._pins[i]) # pi.read returns 1L if the pin is high,
states.append(state) # what means the button is not pressed, 0L when pressed
for i in range(0, len(states)):
if states[i]:
self.last_pressed = i+1
'''UGLY AS SHIT but works now, will change to locks after the code works'''
if self.last_pressed != 0 :
while self.last_pressed != 0:
pass
else:
time.sleep(1/self.res)
print 'im groot' # for debugging
def main():
print 'ok' #debug
dpad = dpad_monitoring(0, BUTT_UP, BUTT_LEFT, BUTT_CENTER, BUTT_RIGHT, BUTT_DOWN)
dpad.run()
print 'okey' #debug again
while i != 3:
i = dpad.last_pressed
if i == 1:
print 'UP'
dpad.last_pressed = 0
if i == 2:
print 'LEFT'
dpad.last_pressed = 0
if i == 4:
print 'RIGHT'
dpad.last_pressed = 0
if i == 5:
print 'DOWN'
dpad.last_pressed = 0
print 'CENTER, stopping'
time.sleep(0.5)
dpad.stop()
if __name__ == '__main__':
main()
The problem is when I run the code, I get this:
ok
im groot
im groot
im groot
im groot
im groot
im groot
... (endless groot)
So it seems the code gets stuck at dpad.run(). Now AFAIK, the main point of threading is that the code continues after calling the run() function and can interact with the threading object, so I don't know what the he'll is going on. Could you, all experts, help me out please?
(Since the code after dpad.run() never ran, I don't know if it works, it may be all garbage. :P
The strange thing is that this simple test code works with no problem:
Cool code:
import threading
import time
class thread1(threading.Thread):
def __init__(self, threadID, start_from):
threading.Thread.__init__(self)
self.threadID = threadID
self.i = start_from
self.running = True
def run(self):
while self.running:
time.sleep(1)
self.i = self.i+1
def stop(self):
self.running = False
class thread2(threading.Thread):
def __init__(self, threadID, start_from):
threading.Thread.__init__(self)
self.threadID = threadID
self.i = start_from
self.running = True
def run(self):
while self.running:
time.sleep(0.5)
self.i = self.i+10
def stop(self):
self.running = False
thread1 = thread1(1, 10)
thread2 = thread2(2, 1)
thread1.start()
thread2.start()
for j in range(30):
print thread1.i, thread2.i
time.sleep(0.3)
thread1.stop()
thread2.stop()
The output is
10 1
10 1
10 11
10 11
11 21
11 31
11 31
12 41
12 41
12 51
13 61
13 61
13 71
13 71
14 81
14 91
14 91
15 101
15 101
15 111
16 121
16 121
16 131
16 131
17 141
17 151
17 151
18 161
18 161
18 171
------------------
(program exited with code: 0)
Press return to continue
So there I got the main thread plus the two other run parallel, unlikely to the previous code. What the he'll is going on?
Instead of
dpad.run()
do
dpad.start()
When calling run() directly you are skipping the whole threading functionality and using it as a regular class.
Related
I am writing a program for Raspberry Pi that is utilizing multiple function in classes. I have one class that is dedicated to determining when a capacitive touch sensor is clicked and another one class dedicated to determining the weight from HX711 chip. I want to automatize all: when click the capacitive sensor the cell start the weight scale and then, when I click the capacitive sensor for the second times the system call the function cleanAndExit() but I don't know how I can do this stuff.
import time
import sys
import RPi.GPIO as GPIO
from hx711 import HX711
GPIO.setmode(GPIO.BCM)
padPin = 21
GPIO.setup(padPin, GPIO.IN)
class WeightScale:
def cleanAndExit(self):
print "Clean GPIO..."
GPIO.cleanup()
print "Complete!"
sys.exit()
def cliccato(self):
hx = HX711(5, 6)
hx.set_reading_format("LSB", "MSB")
hx.reset()
hx.tare()
hx.set_reference_unit(-421)
while True:
time.sleep(0.1)
n = 100
//Run for max 100 seconds and create an array with the last value from weight scale sensor
for i in range (1, n):
val = max(0, int (hx.get_weight(5)))
add = []
hx.power_down()
hx.power_up()
time.sleep(0.6)
add.append(val)
add1 = []
add1.append(add[-1:])
print add1
time.sleep(1)
class TouchSensor:
def click(self):
alreadyPressed = False
while True:
padPressed = GPIO.input(padPin)
if padPressed and not alreadyPressed:
print "click"
time.sleep(2)
c=WeightScale()
t=TouchSensor()
In order you to correctly create a class, you need to define an init method with in the class definition. So for example:
class TouchSensor:
def __init__(self):
self.padPin = 21
def click(self):
alreadyPressed = False
while True:
padPressed = GPIO.input(padPin)
if padPressed and not alreadyPressed:
print "click"
time.sleep(2)
Then once you create your object of that class, it is initialized with padPin = 21. Then you use the methods within each class to perform what you're calling 'functions.'
t = TouchSensor()
t.click()
Try making adjustments and post whatever errors you end up with!
I make some adjustments to my code:
import time
import sys
from multiprocessing import Process
import RPi.GPIO as GPIO
from hx711 import HX711
GPIO.setmode(GPIO.BCM)
padPin = 21
GPIO.setup(padPin, GPIO.IN)
class WeightScale:
def cleanAndExit(self):
print ("Clean GPIO...")
GPIO.cleanup()
print ("Complete!")
sys.exit()
def pesatura(self):
hx = HX711(5, 6)
hx.set_reading_format("LSB", "MSB")
hx.reset()
hx.tare()
hx.set_reference_unit(-421)
while t.status==True:
time.sleep(0.1)
n = 100
for i in range (1, n):
val = max(0, int (hx.get_weight(5)))
add = []
hx.power_down()
hx.power_up()
time.sleep(0.6)
add.append(val)
add1 = []
add1.append(add[-1:])
print (add1)
time.sleep(1)
cleanAndExit()
class TouchSensor:
def __init__(self):
self.status = False
def changeStatus(self):
if self.status == False:
self.status = True
print (self.status)
else:
self.status = False
print (self.status)
def click(self):
while True:
padPressed = GPIO.input(padPin)
if padPressed:
print ("click")
t.changeStatus()
alreadyPressed = padPressed
time.sleep(0.5)
c=WeightScale()
t = TouchSensor()
if __name__ == '__main__':
p1 = Process (target = t.click())
p1.start()
p2 = Process (target = c.pesatura())
p2.start()
I have added a multiprocessing function and method changeStatus for the button click,I want to use it to start the loop of pesatura(self) when self.status==True and after, when self.Status== False (another click) start cleanAndExit(). But when I start the script it gives me the error ''cleanAndExit() takes exactly 1 argument (0 given)''.
I'm new to threading and even newer to python I went through multiple questions and for some reason I cannot get it right.
I have an application that displays LED (number) State (true/false) now I want it to blink so it turns on waits 2 seconds then turns off waits 2 seconds. I display what state it is on after each change. I have created 2 of those LEDs one has delay between blinks of 2 seconds one 5 so my predicted output of those two would be like:
LED: 15 State: True
LED: 16 State: True
LED: 16 State: False
LED: 15 State: False
and instead I get
LED: 15 State: True
LED: 15 State: False
LED: 16 State: True
LED: 16 State: False
And the code itself:
import time
from threading import Thread
class ledController(Thread):
#static variables
def __init__(self, GPIO, state=False): # x = " " - Default variable if user leaves it empty
self.GPIO = GPIO
self.state = state #Default LED state is off
def ledSwitch(self):
self.state = not self.state
def ledON(self):
self.state = True
def ledOFF(self):
self.state = False
def ledBlink(self, duration):
self.ledON()
print(self.ledDetails())
time.sleep(duration)
self.ledOFF()
print(self.ledDetails())
time.sleep(duration)
def ledDetails(self):
return "LED: " + str(self.GPIO) + " State: " + str(self.state)
redLED = ledController(15)
blueLED = ledController(16, True)
redLED.ledBlink(5)
blueLED.ledBlink(2)
You are deriving your controllers from Thread, but you are not using the thread methods at all.
Because of that, all your methods are executed synchronously, and thats how the output is generated.
You should make a run() method in your derived class, and then start the thread by using .start().
Also see the documentation:
run() - Method representing the thread’s activity.
You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.
You didn't used multi-threading functionality at all. You just derived the Thread module methods in you class, but not used them.
Here is another way of implementing multi-thread program using thread module:
import time
import thread
class ledController():
#static variables
def __init__(self, GPIO, state=False): # x = " " - Default variable if user leaves it empty
self.GPIO = GPIO
self.state = state #Default LED state is off
def ledSwitch(self):
self.state = not self.state
def ledON(self):
self.state = True
def ledOFF(self):
self.state = False
def ledBlink(self, duration):
self.ledON()
print(self.ledDetails())
time.sleep(duration)
self.ledOFF()
print(self.ledDetails())
time.sleep(duration)
def ledDetails(self):
return "LED: " + str(self.GPIO) + " State: " + str(self.state) + '\n'
redLED = ledController(15)
blueLED = ledController(16, True)
try:
thread.start_new_thread( redLED.ledBlink, (5, ) )
thread.start_new_thread( blueLED.ledBlink, (2, ) )
except:
print "Error: unable to start thread"
Works as below:
>>> ================================ RESTART ================================
>>>
>>> LED: 15 State: True
LED: 16 State: True
LED: 16 State: False
LED: 15 State: False
Quoted from here:
And here is a sample for using Thread sub-classes (as you did it):
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
print_time(self.name, self.counter, 5)
print "Exiting " + self.name
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
print "Exiting Main Thread"
That works as below:
Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 09:10:03 2013
Thread-1: Thu Mar 21 09:10:04 2013
Thread-2: Thu Mar 21 09:10:04 2013
Thread-1: Thu Mar 21 09:10:05 2013
Thread-1: Thu Mar 21 09:10:06 2013
Thread-2: Thu Mar 21 09:10:06 2013
Thread-1: Thu Mar 21 09:10:07 2013
Exiting Thread-1
Thread-2: Thu Mar 21 09:10:08 2013
Thread-2: Thu Mar 21 09:10:10 2013
Thread-2: Thu Mar 21 09:10:12 2013
Exiting Thread-2
I am writing a web server that will log temperatures. The user clicks "collect data" on the web interface, that then triggers a flask function to run a "collect temperature" function which just collects temperature data indefinitely. I then want to be able for the user to hit a "stop data collection" button that would stop the collect temperature function while loop.
The problem (my understanding at least) boils down to something like the following code:
class myClass:
counterOn = 0
num = 0
def __init__(self):
self.num = 0
def setCounterOn(self, value):
self.counterOn = value
def printCounterOn(self):
print self.counterOn
def count(self):
while True:
if self.counterOn == 1:
self.num += 1
print self.num
time.sleep(1)
then the server file:
myCounter = myClass.myClass()
myCounter.setCounterOn(1)
myCounter.count()
time.sleep(5)
myCounter.setCounterOn(0)
Ideally I would like the server file to create a counter object, then turn on and off the counter function externally. As it functions now, it is stuck in the while loop. I tried threading only to discover you can't pause or stop a thread. Am I looking at this completely wrong, or is it as simple as a try/except?
Edit:
The external file idea is great. I was having some trouble parsing the text file consistantly across my functions and wound up stumbleing across ConfigParsers to read .ini files. I think I'm going to go that way since eventually I want to have a PID controller controlling the temperature and it will be great to be able to store configurations externally.
I implemented just a while loop that looped forever and only recorded if it saw the config file configured to collect. The problem was that, in my flask file, i would run
#app.route('/startCollection', methods=['POST'])
def startCollectData():
print "collectPressed"
config.read('congif.ini')
config.set('main', 'counterOn', '1')
with open('config.ini', 'w') as f:
config.write(f)
C.count()
return "collect data pressed"
#app.route('/stopCollection', methods=['POST'])
def stopCollectData():
print "stop hit"
config.read('config.ini')
config.set('main', 'counterOn', '0')
with open('config.ini', 'w') as f:
config.write(f)
C.count()
return "stop pressed"
def count(self):
while True:
self.config.read('config.ini')
print self.num
time.sleep(1)
if self.config.get('main', 'counterOn') == '1':
self.num += 1
From my observation, the startDataCollection was getting stuck on count(). It would never return data, so then when i would try to stop data collection, the flask script wouldn't be there to interpret the stop command.
So i moved on to the mutex. That is exactly the functionality i thought would come out of the box with threads. It seems to be working fine, other than there is usually a really long delay in the 2nd time i stop collection.
#app.route('/')
def main():
print "MYLOG - asdf"
cls.start()
cls.pause()
return render_template('index.html')
#app.route('/startCollection', methods=['POST'])
def startCollectData():
print "collectPressed"
cls.unpause()
return "collect data pressed"
#app.route('/stopCollection', methods=['POST'])
def stopCollectData():
print "stop hit"
cls.pause()
return "collect data pressed"
results in the following output if i click start, stop, start, then stop:
collectPressed
1
10.240.0.75 - - [22/Apr/2016 15:58:42] "POST /startCollection HTTP/1.1" 200 -
2
3
4
5
6
7
8
9
stop hit
10.240.0.207 - - [22/Apr/2016 15:58:51] "POST /stopCollection HTTP/1.1" 200 -
collectPressed
10
10.240.0.166 - - [22/Apr/2016 15:58:57] "POST /startCollection HTTP/1.1" 200 -
11
12
13
14
15
16
stop hit
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
10.240.0.75 - - [22/Apr/2016 15:59:24] "POST /stopCollection HTTP/1.1" 200 -
So i hit stop, then it collects for 20 seconds, and then it finally stops. My collection points are going to be 5 minutes apart, so its not a big deal, but just curious.
import threading
import time
class myThread(threading.Thread):
num = 0
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
self.mutex = threading.Lock()
self.paused = False
def pause(self):
if(not self.paused):
self.mutex.acquire()
self.paused = True
def unpause(self):
self.mutex.release()
self.paused = False
def run(self):
print "starting" + self.name
while True:
self.mutex.acquire()
self.num += 1
print self.num
time.sleep(1)
self.mutex.release()
Anyways, thanks for the help. I've been stuck on how to handle this for about 4 months and its great to finally make some progress on it!
Edit 2
Actually, just ran it again and it took 100 seconds for it to actually stop counting. Thats not going to cut it. Any idea whats going on?
I would try using threads again. The fact of the matter is that you have a computation that needs to run, while another instruction sequence (namely the GUI logic) also needs to execute.
I would approach the problem with mutex's (a standard concurrency control technique) which should be able to supply a pause/unpause functionality:
import time
import threading
class myClass(threading.Thread):
num = 0
def __init__(self):
super(myClass, self).__init__()
self.num = 0
self.mutex = threading.Lock()
self.paused = False
def pause(self):
if(not self.paused):
self.mutex.acquire()
self.paused = True
def unpause(self):
self.mutex.release()
self.paused = False
def run(self):
while True:
self.mutex.acquire()
self.num += 1
print self.num
time.sleep(1)
self.mutex.release()
cls = myClass()
cls.start()
time.sleep(10)
cls.pause()
time.sleep(2)
cls.unpause()
time.sleep(2)
And this should output: (or something similar)
1
2
3
4
5
6
7
8
9
10
(wait)
11
12
It's my second day in Python, I found it's a really cool language and I want to try different things in it.
Is it possible to call an object and create a daemon of that object's method which would change the objects attributes?
from multiprocessing import Process
import time
class Foo(object):
def __init__(self):
self.number = 1
# this attribute...
def loop(self):
while 1:
print self.number
# ...is changed here
self.number += 1
time.sleep(1)
if __name__ == '__main__':
f = Foo()
p = Process(target=f.loop)
p.deamon = True # this makes it work in the background
p.start()
# proceed with the main loop...
while 1:
time.sleep(1)
print f.number * 10
The result:
1
10
2
10
3
10
4
10
...
Why doesn't f.loop() change the self.number of f? They are both part of the same class Foo().
What can I change to receive this output:
1
10
2
20
3
30
4
40
...
/edit 1:
I tried this, with the same result (why?):
class Foo(Process):
def __init__(self):
super(Foo, self).__init__()
self.daemon = True # is daemon
self.number = 1
self._target = self.loop # on start() it will run loop()
def loop(self):
while 1:
print self.number
self.number += 1
time.sleep(1)
if __name__ == '__main__':
f = Foo() # is now Process
f.start() # runs f.loop()
while 1:
time.sleep(1)
print f.number * 10
Same output as before.
You're using multiprocessing. The short (and somewhat simplified) answer is that processes to do not share memory by default. Try using threading instead.
If you're hell bent on experimenting with shared memory and processes then look at sharing state in the documentation on multiprocessing.
Also daemon doesn't do what you think it does. If a process creates children then it will attempt to kill all it's daemonic children when it exits. All Processes will work in the background, you just need to start them.
#KSFT
currently frustrated by my inability to either decipher the formatting on stackoverflow OR make a simple python script work...
whats wrong here?
the program prompts for input to determine the value of dwell but it does not result in an led turning on.
import threading
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(7, GPIO.OUT)
frequency = 0.05
dwell = 0.01
def get_input():
while True:
dwell=raw_input("Brightness: ")
input_thread=threading.Thread(target=get_input())
input_thread.start()
while True:
time.sleep(frequency)
GPIO.output(7, 1)
time.sleep(dwell)
GPIO.output(7, 0)
input_thread=threading.Thread(target=get_input())
is wrong!
input_thread=threading.Thread(target=get_input)
is right!
threading
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
If you want to give arg to get_input ,you need to give it throw args and kwargs.
Example:
1 #!/usr/bin/python
2 #current's number of threads
3 import threading
4 import time
5
6 def worker():
7 print "test"
8 time.sleep(1)
9
10 for i in xrange(5):
11 t = threading.Thread(target=worker)
12 t.start()
13
14 print "current has %d threads" % (threading.activeCount() - 1)
target=worker().
target=worker.