How do I run routines where timing is critical?

S

S. David Rose

Hello All!
I am new to Python, and wanted to know if I might ask you a question
regarding timing.

I want a main loop which takes photos from 8 different web-cams, each can
be addressed by http://ip-addr/image.jpg. That's the easy part, but I want
to have 2 cameras poll 3-times a second, 4 cameras poll 2 times a second,
and the remaining 2 cameras poll once a second. I have found lots of info
suggesting the use of threads for this, all using sleep to have a single
event fire every second or so. But, what I'd like to do is have a loop
which does not need to 'sleep' but can rather evaluate where I am in the
second and then have that logic trigger the event.

In otherwords,

While 1
if second >1.00 and <1.25
Camera 1 & camera 2
Camera 5 & camera 6 & camera 7 & camera 8

if second >1.25 and < 1.50
Camera 1 & camera 2

if second >1.50 and <1.75
Camera 1 & camera 2
Camera 5 & camera 6 & camera 7 & camera 8

if second >1.75 and < 2.0
Camera 1 & camera 2

if second >1.00 and < 1.334
Camera 3 & camera 4

if second > 1.334 and < 1.667
Camera 3 & camera 4

if second > 1.667 and < 2.000
Camera 3 & camera 4

Please don't be too harsh with me. I'm still new, and am still quite
actively learning, but I've searched a bit on this and can't seem to find
it on my own.

Thank you in advance!
Dave Rose
Stamford, CT - USA
 
P

Paul Rubin

S. David Rose said:
I want a main loop which takes photos from 8 different web-cams,
each can be addressed by http://ip-addr/image.jpg. That's the easy
part, but I want to have 2 cameras poll 3-times a second, 4 cameras
poll 2 times a second, and the remaining 2 cameras poll once a
second. I have found lots of info suggesting the use of threads for
this, all using sleep to have a single event fire every second or
so. But, what I'd like to do is have a loop which does not need to
'sleep' but can rather evaluate where I am in the second and then
have that logic trigger the event.

You have to do some pretty advanced stuff if you want to make sure of
accurate timing. But if you just want to sleep for 1/4 of a second and
can tolerate some slop, you can say

import time
time.sleep(0.25)

I.e. you don't have to sleep an integer number of seconds.
 
D

Dennis Lee Bieber

Hello All!
I am new to Python, and wanted to know if I might ask you a question
regarding timing.

First off, based on your subject line: Define "critical".
Remember, Python is a byte-coded interpreted language, not something
running at machine-code level.
I want a main loop which takes photos from 8 different web-cams, each can
be addressed by http://ip-addr/image.jpg. That's the easy part, but I want
to have 2 cameras poll 3-times a second, 4 cameras poll 2 times a second,
and the remaining 2 cameras poll once a second. I have found lots of info
suggesting the use of threads for this, all using sleep to have a single
event fire every second or so. But, what I'd like to do is have a loop
which does not need to 'sleep' but can rather evaluate where I am in the
second and then have that logic trigger the event.

I hope you intend to dedicate most of the CPU time to this
polling loop. sleep() maps directly to an OS service call, taking
practically no CPU.

The traditional polling loop normal relies on testing an
externally set "address" -- IE, a keyboard status register that goes
"high" when a key has been pressed; when the loop reads the high state,
it reads the data register, then resets (if the data read doesn't
automatically reset) the status register.

Your timing loop, to work as a poll, will require you to
constantly ask the OS for the current system time, compute the
difference from a base time, and perform the capture on certain values
of the difference.

I should ask -- how long does it take to transfer the image?
You are asking for two cameras at 0.333sec intervals... That means each
camera can only consume 0.1667sec for a transfer (this is also ignoring
that the other cameras may also be involved. 8 cameras at 0.125sec each,
processed in sequence, will require a full second. BUT... by your specs,
[email protected] means 6 images per second, [email protected] is another 8 images, and
[email protected] is 2 images... Or a total of 16 images to be transferred EVERY
second -- or one image every 0.0625 seconds. Include the overhead needed
to calculate the current time fraction for each test.


Pseudo-code:

t0 = int(time.clock() * 1000) # floating seconds -> integer millisec
loop
diff = int(time.clock() * 1000) - t0
if (diff % 333) < some_slop_parameter:
capture the 3/second cameras
if (diff % 500) < some_slop_parameter:
capture the 2/second cameras
if (diff % 1000) < some_slop_parameter:
capture the 1/second cameras


Where "some_slop_parameter" is a value to allow for non-exact intervals
(better hope it is smaller than the empty loop time)... Normally you'd
be looking for the modulo to be 0.0 to signal that the interval has been
reached, but since you can't ensure the loop will hit that tightly, use
something like 10 milliseconds (experiment to ensure it doesn't hit a
single camera capture twice).


Threads make it much simpler... Though you still risk a bit of
drift by the time a capture takes (unless you've allowed for capture
time when setting the sleep interval). Two approaches: one thread per
camera, where you initialize each thread by that camera's sleep
interval; or one thread per sleep interval, where you initialize with
both the interval AND a list of the cameras to be captured.

--
 
H

Hemanth P.S.

You can do something like this. I am assuming you can poll with 2
cameras every 0.3 seconds instead of 0.33333333... seconds.

# start of code
class Camera():
def __init__(self, clickInterval):
self.clickInterval = clickInterval
#
#

# List of camera objects with their periodicity
cameraList = [Camera(0.3), Camera(0.3), Camera(0.5), Camera(0.5), \
Camera(0.5), Camera(0.5), Camera(1), Camera(1)]

globalTime = 0.0 # counter to keep track of current time
import time

while True:
time.sleep(0.1) # 0.1 seconds is the granularity
globalTime += 0.1
# examine each camera if it needs to capture at this moment
for camera in cameraList:
if globalTime % camera.clickInterval == 0.0:
click(camera) # capture image from this camera
#
#
#
# end of code

You have to add additional parameters to the Camera class to define
it's
address, etc. Every 0.1 second you determine which of the cameras to
be clicked and then capture images from those cameras.

--Hemanth P.S.
 
J

Jeff Epler

IMO you want an event-driven structure.

import heapq, math, time

events = []

The event loop looks something like this: (all untested)
def sleep_until(when):
now = time.time()
if when > now:
time.sleep(when-now)

def add_event(when, callback):
heapq.heappush(events, (when, callback))

def eventloop():
while events:
when, callback = heapq.heappop(events)
sleep_until(when)
callback()

A camera might be something like this: (again, all untested)
class Camera:
def __init__(self, number, frequency):
self.number = number
self.frequency = frequency
self.reschedule()

def __repr__(self):
return "<Camera %d (frequency %d/sec)>" % (self.number, self.frequency)

def take_photo(self):
print "Taking photo from", self, "at", time.time() % 60

def reschedule(self):
now = time.time()
f = self.frequency
next = math.floor(now * f + 1) / f
add_event(next, self.callback)

def callback(self):
self.take_photo()
self.reschedule()

The main program would create 8 cameras and run the event loop:
def main():
frequency = [3, 3, 2, 2, 2, 2, 1, 1]
cameras = [Camera(i, f) for (i, f) in enumerate(frequency)]
eventloop()

if __name__ == '__main__':
main()

The calculation of the "next" in reschedule is intended to find the next
"1/frequency" time. This means that if a camera has frequency=2, and
fires at time 1.6, it will next fire at time 2.0---even if the last time
it schedule itself, it was scheduled for time 1.0 and was delayed by 0.6
seconds. I suspect that if the system can't keep up with all the
cameras, that this will result in the cameras being serviced
"round-robin" with equal frequency, which may or may not be acceptable.
It also means that after a temporary slowdown (background disk activity)
clears up, the cameras will immediately return to their given speed in
Hz, rather than trying to take the appropriate number of photos to the
number of seconds that have passed, in quick succession.

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFA2jqLJd01MZaTXX0RAia6AKCSIT2vPFjxX/Uv8B36dTXV74wTRACeNwCl
qO3MZ75g3u3Cwmurcei6gK8=
=Od1P
-----END PGP SIGNATURE-----
 
T

Terry Reedy

S. David Rose said:
I want a main loop which takes photos from 8 different web-cams, each can
be addressed by http://ip-addr/image.jpg.

Public web cams generally update once every few seconds, or slower, so I
presume these are private cameras on a private net.
That's the easy part, but I want
to have 2 cameras poll 3-times a second, 4 cameras poll 2 times a second,
and the remaining 2 cameras poll once a second.

Your proto-code below shows the 'remaining 2' being polled 4 times a
second.

How long does it take to 'poll' a camera and process the data and be ready
for another? IOW,
I have found lots of info
suggesting the use of threads for this, all using sleep to have a single
event fire every second or so.

(Stackless tasklets might also be a possibility, but I have 0 experience
therewith).
Once a second will not get you several times a second. Unless cameras
respond 'immediately', you may need to make several requests and process
replies as they come.
But, what I'd like to do is have a loop
which does not need to 'sleep' but can rather evaluate where I am in the
second and then have that logic trigger the event.

In otherwords,

While 1
if second >1.00 and <1.25
Camera 1 & camera 2
Camera 5 & camera 6 & camera 7 & camera 8

if second >1.25 and < 1.50
Camera 1 & camera 2

if second >1.50 and <1.75
Camera 1 & camera 2
Camera 5 & camera 6 & camera 7 & camera 8

if second >1.75 and < 2.0
Camera 1 & camera 2

if second >1.00 and < 1.334
Camera 3 & camera 4

if second > 1.334 and < 1.667
Camera 3 & camera 4

if second > 1.667 and < 2.000
Camera 3 & camera 4

How critical is the timing? Above suggests some sloppiness is allowed. If
so, following schedule might work (where '3A' is first 3-time-a-second
camera, etc).

0.00 3A,3B
pause
0.25 2A,2B,2C,2D
0.33 3A,3B
pause
0.50 1A,1B
pause
0.66 3A,3B
0.75 2A,2B,2C,2D
pause
and repeat

pause periods could be used to process previously collected data.

Terry J. Reedy
 
T

Tim Lesher

S. David Rose said:
But, what I'd like to do is have a loop
which does not need to 'sleep' but can rather evaluate where I am in the
second and then have that logic trigger the event.

Sounds like you're writing your own scheduler. You might want to look
into the 'sched' module.
 
J

Josef Dalcolmo

Why can't I read the original posting?

this may have something to do with my Newsreader (I am using Sylpheed-Claws-W32 0.9.10 as Mail- and Newsreader), but it may also be related to the source of the mail. Is this perhaps a MS-Outlook specific thing?

If someone, who can read the original message (by S. David Rose) can help me (for example by sending the header), this may be useful to debug the problem.

- Josef
 
P

Peter Otten

Josef said:
Why can't I read the original posting?

this may have something to do with my Newsreader (I am using
Sylpheed-Claws-W32 0.9.10 as Mail- and Newsreader), but it may also be
related to the source of the mail. Is this perhaps a MS-Outlook specific
thing?

I use KNode and don't see it either. Perhaps it has something to do with the
news server.

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,069
Latest member
SimplyleanKetoReviews

Latest Threads

Top