Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timing is not precise due to use of sleep #3

Closed
geerlingguy opened this issue Mar 12, 2017 · 10 comments
Closed

Timing is not precise due to use of sleep #3

geerlingguy opened this issue Mar 12, 2017 · 10 comments

Comments

@geerlingguy
Copy link
Owner

geerlingguy commented Mar 12, 2017

Something that's totally logical now, but wasn't when I was originally writing the code: If you want to calculate more-or-less precise timings (e.g. 1 picture every 1 second, or 1 picture every 10 seconds), and try to do so to make a specific frame rate, etc... then that's not going to happen if the logic goes:

take_and_store_picture_with_picamera()
sleep(x)

...because take_and_store_picture_with_picamera() takes a non-zero amount of time.

On the Pi Zero W, it actually takes .5s - 1s, and that significantly impacts the time delay in the timelapse.

So I'd like to find a way to more precisely hit the time interval defined in config.yml. Maybe set a timer and have it hit a capture on each interval? Is there a way to thread the actual picture taking in Python? I could whip it up more easily in Node.js or Go, but maybe there's an easy way to tackle this in Python too.

@geerlingguy
Copy link
Owner Author

geerlingguy commented Mar 12, 2017

Looks like the simplest way would be to use threading.Timer: http://stackoverflow.com/a/3393759

import threading

# Interval between tasks, in seconds.
interval = 5.0

def capture():
    threading.Timer(interval, capture).start()
    # Do stuff...

capture()

Documentation here: https://docs.python.org/2/library/threading.html#timer-objects

This might not be the most efficient/perfect way of doing it... it seems that Timer is usually meant to just thread some one-off task in the background one time, and that's it. But I'll see if it's stable over the course of a day or two.

@geerlingguy
Copy link
Owner Author

It's more complicated than that, though... will need some thinking to make sure I'm not resetting all the camera settings over and over and also causing the image interval counter to be more annoying than it has to be.

@geerlingguy
Copy link
Owner Author

Much more complicated. I remember how much I hate multithreaded computing :D

@geerlingguy
Copy link
Owner Author

With the branch in #4, I got the following after a few hundred pictures last night:

Exception in thread Thread-370:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 1082, in run
    self.function(*self.args, **self.kwargs)
  File "timelapse.py", line 49, in capture_image
    thread.start()
  File "/usr/lib/python2.7/threading.py", line 745, in start
    _start_new_thread(self.__bootstrap, ())
error: can't start new thread

Exception in thread Thread-369:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 1082, in run
    self.function(*self.args, **self.kwargs)
  File "timelapse.py", line 57, in capture_image
    camera.capture(dir + '/image{0:05d}.jpg'.format(image_number))
  File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 1423, in capture
    'Timed out waiting for capture to end')
PiCameraRuntimeError: Timed out waiting for capture to end

Might need to to handle that exception (in any case). Not sure what caused it, though.

@geerlingguy
Copy link
Owner Author

Maybe waveform80/picamera#242 (comment) ?

[it was] using up the per-process thread limit, which eventually blocked the camera

@geerlingguy
Copy link
Owner Author

$ cat /proc/sys/kernel/threads-max
5805

See: http://stackoverflow.com/a/344292

But if threading is going to be a pretty annoying thing to deal with, maybe we go back to the old-fashioned sleep() technique, and just use a more precise timer/date functionality...

@geerlingguy
Copy link
Owner Author

Happened again, on 369/370.

@geerlingguy
Copy link
Owner Author

Trying removing the daemonization... might make ctrl-c stuff more difficult.

@geerlingguy
Copy link
Owner Author

Another test now, without the daemonization and wait, which might free up threads and not bump into the limit?

@jamesshannon
Copy link

For future searchers... why not calculate the time for the next picture BEFORE you start taking the first one. E.g.:

time_for_next_pic = time.time() + interval_seconds
camera.capture()
if time.time() > time_for_next_pic:
  # uh oh! Took longer than the interval. Maybe you actually need threading!
else:
  sleep(time_for_next_pic - time.time())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants