Doubt in Threading in gpio pins raspberry pi
my self working on encoders of differential drive robot, i need to read the speed and podition of wheels using two encoders simultaneously. I have used threading library in python even though i started both the functions only the function which has been initiated at first runs while the second doesn't. I am not sure what the resson is , is there anything to be noted while using threading in gpio pins of raspberry pi 3b, if so please help and suggest a solution.
Thanks in advance
from threading import Thread
import RPi.GPIO as GPIO
import time
import datetime
def encoder_right(t1):
...
def encoder_left(t1):
...
t1 = datetime.datetime.now()
Thread1 = Thread(target = encoder_right(t1),daemon = True)
Thread2 = Thread(target = encoder_left(t1),daemon = True)
Thread1.start()
Thread2.start()
Thread1.join()
Thread1.join()
When you create a new threading.Thread object, you need to pass a function to the target parameter. In your code, instead of passing the function object, you are calling the function. That is, when you write:
Thread1 = Thread(target=encoder_right(t1), daemon=True)
You are calling encoder_right(t1); your code never gets beyond this point because you've entered an infinite loop. You never create a thread and you never reach the lines after this code.
You want to write instead:
Thread1 = Thread(target=encoder_right, args=(t1,), daemon=True)
Thread2 = Thread(target=encoder_left, args=(t1,), daemon=True)
This way you're passing the function object in the target parameter, and the Thread object will take care of starting the function in a new thread.
Unrelated to your question, but you only need to call GPIO.setmode(GPIO.BCM) and GPIO.setwarnings(False) once in your program; you don't need to call that in each thread. That is, you could write instead:
def encoder_right(t1):
...
def encoder_left(t1):
...
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
t1 = datetime.datetime.now()
Thread1 = Thread(target=encoder_right, args=(t1,), daemon=True)
Thread2 = Thread(target=encoder_left, args=(t1,), daemon=True)
Thread1.start()
Thread2.start()
Thread1.join()
Thread2.join()
Also! I would avoid giving variables the same name as your functions (e.g., in your function encoder_left you also have a variable named encoder_left). At some point this is going to cause a surprising problem when you try to reference the function and find that you're actually referencing an integer value instead.
Related
I have a script, let's say "sensors.py" in which I have a Class "Meas", that reads measurements from several sensors. These comes from serial ports, program makes some calculations on them and changes the class "self.variable_a value" and another self variables also. The readings are in continuous mode, i.e. the program automatically waits for a message to come from the sensor to the serial port and read whole line (it's done via pyserial library). Some transmit readings at frequency of 10Hz, others 20Hz or 100Hz. This is a really big and messy class, therefore I put it in a separate file.
In my "main.py" script I import this "sensors" file and instantiate the "Meas" Class. Now I have a problem. How can I run immediately some "on_changed_var_a" function in "main" script, only when the "variable_a" in "Meas" object has changed - without consuming CPU power with while loop (constatly checking whether by any chance the variable has not changed) or waiting with time.sleep()? I need to get the sensors readings changes and then run another functions in "main" script in the most efficient way, as fast as possible. Thanks in advance!
EDIT: added example files
"sensors.py" file:
import random
import time
import threading
running = True
class Meas1:
def __init__(self, xyz):
self.xyz = xyz
self.var_a = None
thr1 = threading.Thread(target=self.readings, daemon=True)
thr1.start()
def readings(self):
while running:
# simulating 5Hz sensor readings:
self.var_a = self.xyz * random.randint(1, 1000)
print(self.var_a)
time.sleep(0.2)
"main.py" file:
import time
import sensors
import threading
class MainClass:
def __init__(self):
print("started")
self.sensor1 = sensors.Meas1(xyz=7)
thr_ksr = threading.Thread(target=self.thr_keep_script_running, daemon=True)
thr_ksr.start()
# in this part I would like to run the on_changed_var_a function, immediately when var_a changes
thr_ksr.join()
def on_changed_var_a(self):
print("var_a changed: ", self.sensor1.var_a)
def thr_keep_script_running(self, t=10):
time.sleep(t)
sensors.running = False
print("stopped, sleeping 1 sec")
time.sleep(1)
mc = MainClass()
Not sure why this is tagged mutithreading. You need this function to be run on different thread?
To the problem. The easiest way would be to make Meas call function you will pass to it.
You could make variable_a a property and then in it's setter call the function you want. Function could be passed and assigned to self.call_on_a_change attr for example.
Edit:
I don't think there is a way to make function execute on different thread (well, you could start a new one for that purpose, which sounds like a great solution to me).
Another problem with threads is that you give control to the system. It decides when and for how long which thread runs. So "as fast as possible" is constrained by that.
Nonetheless, you could create a threading.Lock and try to acquire it from main thread. Then in the reading thread upon change you could release the Lock and allow main thread to execute all call_on_a_change. Something like this:
import time
import threading
lock = threading.Lock()
# change to locked
lock.acquire()
a_change_callbacks = []
def on_changed_var_a(new_a):
print(new_a)
def readings():
a_change_callbacks.append(lambda: on_changed_var_a('first `a` change'))
lock.release()
time.sleep(5)
a_change_callbacks.append(lambda: on_changed_var_a('second `a` change'))
lock.release()
time.sleep(5)
a_change_callbacks.append(lambda: on_changed_var_a('third `a` change'))
lock.release()
thr = threading.Thread(target=readings, daemon=True)
thr.start()
while True:
lock.acquire()
for callback in list(a_change_callbacks):
callback()
a_change_callbacks.remove(callback)
if not thr.is_alive():
break
It's not your class model, but I hope it's enough to show the idea :D
I am currently trying to thread two loops in python. One is currently a tkinter loop that displays the the gui I have set up, and the other is a p2p chat function. using 'import threading', defining threads and starting them individually doesn't seem to work. Any suggestions for what method I can use to get these two loops running concurrently?
The code I'm using to start the threads:
thread1 = threading.Thread(target=x.mainloop())
thread1.start()
thread2 = threading.Thread(target=root.mainloop())
thread2.start()
You need to pass the functions without calling them. As is, you're trying to call them, and pass the return value as the target for the thread; since they never return, you never launch the second thread. Try:
thread1 = threading.Thread(target=x.mainloop) # Removed call parens on target
thread1.start()
thread2 = threading.Thread(target=root.mainloop) # Removed call parens on target
thread2.start()
The problem is relatively simple only that I could not find any
answer with a google search for terms:
How to terminate threads in python
How to end while loop using keyboard input in threads etc
So format of the program is this:
import everything necessary
def readingsomething():
DOING SOME WORK in a infinite while loop and sleep for 1 sec
def readingsomeotherthing():
DOING SOME WORK in a infinite while loop and sleep for 2 sec
thread1 = thread.thread(target = readingsomething)
thread2 = thread.thread(target = readingsomeotherthing)
try:
thread1.start()
thread2.start()
thread1.join()
thread2.join()
except KeyboardInterrupt:
save a file and sys.exit()
So when I run the program everything is smooth except when I
press ctrl + c it does not terminate as per keyboardInterrupt
I am losing the data collected as I am unable to save them.
Any suggestions and help will be appreciated.
You could use the synchronized queue Queue as a pipe to send a value to the thread.
It is rather unclear what you're trying to do.
You're talking about loops but I see none in your code.
Also, written like that, you will first wait for thread1 to stop, then wait for thread2 to stop, make sure it's what you want.
Put a timeout inside these 'join' calls, otherwise it prevents the listening of exceptions:
thread1.join()
becomes
thread1.join(10)
You may want to think about the changes it induces on your code.
Working Python 3 example:
from threading import Thread, Event
import time
def readingsomething(stop):
while not stop.isSet():
print('readingsomething() running')
time.sleep(1)
def readingsomeotherthing(stop):
while not stop.isSet():
print('readingsomeotherthing() running')
time.sleep(2)
if __name__ == '__main__':
stop = Event()
thread1 = Thread(target=readingsomething, args=(stop,))
thread2 = Thread(target=readingsomeotherthing, args=(stop,))
thread1.start()
thread2.start()
try:
thread1.join()
thread2.join()
except KeyboardInterrupt:
print('catched KeyboardInterrupt')
stop.set()
#save the file
print('EXIT __main__')
Tested with Python:3.4.2
I have the following script which utilizes threading module in order to save time when doing cycle.
import threading, time, sys
def cycle(start, end):
for i in range(start, end):
pass
#########################################################
thread1 = threading.Thread(target = cycle, args=(1,1000000))
thread2 = threading.Thread(target = cycle, args=(1000001,2000000))
thread1.start()
thread2.start()
print 'start join'
thread1.join()
thread2.join()
print 'end join'
However, I found the the script cost even more time than the one without multi-threads (cycle(1, 2000000)).
What might be the reason and how can I save time?
Threads are often not useful in Python because of the global interpreter lock: only one thread can run Python code at a time.
There are cases where the GIL doesn't cause much of a bottleneck, e.g. if your threads are spending most of their time calling thread-safe native (non-Python) functions, but your program doesn't appear to be one of those cases. So even with two threads, you're basically running just one thread at a time, plus there's the overhead of two threads contending for a lock.
I have multiple methods set up that need to be run simultaneously. I decided to create individual threads for said methods. There is also a method I made with the sole purpose of creating another thread. Here is an example of what I have done. My question is, how can I safely close these threads?
from threading import Thread
....
def startOtherThread():
Thread(target = myMethod).start()
Thread(target = anotherMethod).start()
....
You do not close threads. They will run until your target= method is finished. It is not clear why you are trying to introduce separate method to start a thread: Thread(target=...).start() looks simple enough.
When you work with threads, you have three basic options:
- wait in main thread until child thread is finished using join() function
- just let child thread run by doing nothing
- exit child thread when main thread is over by using setDeamon(True) on the thread object.
Also you need to be aware of GIL (Global Interpreter Lock) in cPython
Here is some basic test code for threads:
import threading
import time
import sys
def f():
sys.stderr.write("Enter\n")
time.sleep(2)
sys.stderr.write("Leave\n")
if __name__ == '__main__':
t0 = threading.Thread(target=f)
t1 = threading.Thread(target=f)
t0.start()
time.sleep(1)
t1.setDaemon(True)
t1.start()
#t1.join()