Are you saying that it takes 50 seconds to get your first  value returned, or it takes 50 seconds for every  value to be returned - that is, you can only poll once every 50 seconds, no matter how long the GPS has been on and running?
Two things jump out at me:
A long initial wait is normal. Having to wait that long every time  isn’t.  How are you calling the GPS?  Are you asking it to initialize every time?
I don’t know enough about your GPS module to really comment, but I do know that most GPS modules have a way to “save” the current location and/or localization constants so that on subsequent startups the GPS already has an idea of where it is - so it can locate the near satellites more easily.
Sounds like you have an interesting project there!  Since I have a Dexter GPS module in my bag of tricks, I’d really be interested in how this works out for you.  Please keep us in the loop!
#!/usr/bin/env python3
import dextergps
import time
print("Initializing GPS")
g = dextergps.GROVEGPS()
counter = 0
while True:
try:
g.read()
if g.quality < 1:
counter +=1
print("waiting for quality data - try {}".format(counter), end = '\r')
if g.satellites < 3:
counter +=1
print("waiting for greater than three satellites: {} try {}".format(g.satellites, counter), end = '\r')
else:
counter = 0
print("\n")
print("lat: {} {} lon: {} {} time: {}".format(g.lat, g.NS, g.lon, g.EW, g.timestamp))
time.sleep(1)
except KeyboardInterrupt:
print("cntr-c detected, cleaning up")
break
except Exception as msg:
print("Exception {}".format(str(msg)))
break
Are you near a window or outdoors? (reception indoors is notably poor)
The default read() tries fifty times, once every half second, so in bad conditions it will probably take 25 seconds to return.
If you were to make g global and put the g.read() in a separate thread, you can have the reading of the device going on in the background, and the value fetch (g.lat, g.lon, g.timestamp) would be nearly instantaneous. (make sure g.timestamp is recent or g.quality is >0 or some sort of value trust test is valid.)
Thinking about your problem, I realized I didn’t have a basic threading example handy. I had a multiprocessing example, but not a threading example. Thanks for the push; I now have this little “one threading” example:
#!/usr/bin/env python3
# FILE: thread_example.py
# USAGE: ./thread_example.py
import threading
import time
# define a threaded thing class
class Thing (threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.value1 = 0
self.value2 = 0
self.exitFlag = False
print("Thing.__init__ complete")
def run(self):
while (self.exitFlag is not True):
self.value2 += 1
print("Thing updated value2: {}".format(self.value2))
time.sleep(2)
print("exitFlag set, stopping thread")
def main():
# create a thing
thing = Thing()
# start the thing
thing.start()
while True:
try:
print("Main reading thing - value1: {} value2: {}".format(thing.value1, thing.value2))
time.sleep(0.5)
except KeyboardInterrupt:
print("ctrl-c detected - telling thing to exit")
thing.exitFlag = True
thing.join()
break
if __name__ == "__main__":
main()
Looks like logfile() and savephoto() need to be told about globals
And I don’t know if you can synchronize multiple threads to quit using keyboard interrupt. You need to make a threading test program with no grove stuff, just a main that creates four threads, starts them, waits for keyboardinterrupt or “thread signals it has a problem or ended”, then sets the “alltheadsexit” flag or event, and then waits for t in thread list join(). There are examples on the Internet you should study. I don’t have one handy. There are several ways, you will have to get your threading example to start, stop, and handle errors, then extend it with your grove, file, and display stuff.
As it is, I think you will need to kill your program with ps -ef | grep program name, and kill nnn. From a second cmd shell.
Looks like logfile() and savephoto() need to be told about globals
What meaning?
just a main that creates four threads, starts them, waits for keyboardinterrupt or “thread signals it has a problem or ended”, then sets the “alltheadsexit” flag or event, and then waits for t in thread list join(). There are examples on the Internet you should study.
The issue is on thread… I really don’t understand how I can resolve the issue…
I need to thank you again for causing the reminder - “global somevar” is only needed when a function wants to make assignment to a module/file level variable.
That said, there is no variable “g” at the file/module level for these two functions to access, so add:
This is what I was talking about that “I don’t think using KeyboardInterrupt to kill everything off will work.” It forces an unhandled exception to cause everything to quit. You might want to put a print statement in the cleanup to be sure that KeyboardInterrupt causes the cleanup to happen.
My understanding of sys.exit() in a thread is that it kills only that thread, not all the threads.
That’s peculiar. Python has what is called a GIL (Global Interpreter Lock) and that essentially limits a Python program to one real thread, no matter how many threads you spawn.
The only difference is when spawning different processes within a Python program - that’s when > you actually need locks around shared resources.
Your program seems to behave as if there are multiple processes going in parallel.
Edit : Actually, I looked at the source code and I realized that the actual atomic I2C transfers > are thread-safe because there’s the GIL in Python, but there aren’t locks to make the > macro transactions (or as we should call them API calls) safe. The idea is that calling a function of the API is composed of multiple other I2C transfers. Since there’s no lock around these groups of atomic I2C transfers, when accessing the GrovePi concurrently, the API calls will overlay each other and cause your issue."
This library and the other ones too are not thread-safe. You cannot call the GrovePi from multiple threads or processes as that will put the GrovePi into a broken state.
In case you need to reset the GrovePi from your Raspberry Pi, check this section.
The functions don’t verify if the input parameters are valid and therefore the parameters have to be verified/validated before that. Calling a function with improper parameters can result in an undefined behavior for the GrovePi.
Correct me if I am wrong, but didn’t Cleoqc say that - by default - mutexes are not used, but there is a setting somewhere, (I think it was something like “mutex = true” that would default everything to using mutexes?
I remember saying that if it’s such a desirable thing, why isn’t it the default - and your reply was that “it’s a part of the pedagogy”. (And then I made a snarky comment that went something like “if jumping off a building is a bad idea, does that mean we should do it, just to learn not to do it?” Â
I can’t find it right now - do you remember that posting?
grovepi is not a class, and does not offer mutex protected methods. The user must either put all grovepi accesses in a single thread and use a thread_lock, or create a mutex protected grovepi class, or create a mutex, and use it:
import threading
gplock = threading.Lock()
.
.
def any_func_that_accesses_grovepi()
global gplock
with gplock:
grovepi.xxx()
If it is the I2C of grovepi that you are worried about, then you can use the dexter I2C_mutex:
from I2C_mutex import Mutex
.
.
gpmutex = Mutex() # or Mutex(debug=True)
.
.
.
def any_func_that_uses_grovepi()
global gpmutex
with gpmutex:
grovepi.xxxx()