jameswing
Posts: 3
Joined: Tue Aug 12, 2014 10:58 pm

looping until flag set outside loop

Mon Aug 25, 2014 12:27 am

I'm a Python newb. I'm trying to set a (global?) flag in one place, and have a loop terminate as a result. The loop never terminates -- it seems it isn't really checking the value (or else I'm a newb and missing something obvious). How can I do this?

Code: Select all

#!/usr/bin/python
import numpy as np
import picamera
import picamera.array
import datetime

minimum_still_interval = 5
motion_detected = False
camera = picamera.PiCamera()
last_still_capture_time = datetime.datetime.now()

# The 'analyse' method gets called on every frame processed while picamera
# is recording h264 video.  It gets an array (a) of motion vectors from the GPU.
class DetectMotion(picamera.array.PiMotionAnalysis):
    def analyse(self, a):
        if datetime.datetime.now() > last_still_capture_time + \
                datetime.timedelta(seconds=minimum_still_interval):
            a = np.sqrt(
                np.square(a['x'].astype(np.float)) +
                np.square(a['y'].astype(np.float))
            ).clip(0, 255).astype(np.uint8)
            # If there're more than 10 vectors with a magnitude greater
            # than 60, then say we've detected motion
            if (a > 60).sum() > 10:
                print('movement!')
                motion_detected = True

with DetectMotion(camera) as output:
    try:
        camera.resolution = (640, 480)
        camera.framerate= 10
        camera.start_recording('/dev/null', format='h264', motion_output=output)
        while True:  # loop forever
            while not motion_detected: # this never fails the test!  wth?!  :( 
                print('waiting')
                camera.wait_recording(1)
            print ('stopping recording') # we never reach this point  :evil: 
            camera.stop_recording()
            motion_detected = False
            filename = '/home/pi/picam/img' + \
                    datetime.datetime.now().strftime('%Y-%m-%dT%H.%M.%S.%f') + '.jpg'
            print('capturing %s' % filename)
            camera.capture(filename, format='jpeg', use_video_port=True)
            camera.start_recording('/dev/null', format='h264', motion_output=output)
    finally:
        camera.close()
Here is the output:

Code: Select all

waiting
waiting
waiting
movement!
waiting
waiting
movement!
waiting
movement!
waiting
movement!
.
.
.
Note the lack of 'stopping recording' that should occur after each 'movement!' line.
To simplify, I'm trying to do the following pseudocode with Python, but failing to terminate the loop:

Code: Select all

exit = false

function processStuff() {
   ...
   exit = true
}

while (exit == false) {
   invoke (processStuff)
}
print ('done') // if this were Python. we'd never get here.

User avatar
kusti8
Posts: 3439
Joined: Sat Dec 21, 2013 5:29 pm
Location: USA

Re: looping until flag set outside loop

Mon Aug 25, 2014 4:17 pm

Look into multithreading since the compiler by default only executes one thing at a time.
There are 10 types of people: those who understand binary and those who don't.

User avatar
PeterO
Posts: 5879
Joined: Sun Jul 22, 2012 4:14 pm

Re: looping until flag set outside loop

Mon Aug 25, 2014 4:32 pm

kusti8 wrote:Look into multithreading since the compiler by default only executes one thing at a time.
This is not a threading issue. If you look at the output provided the two functions are both getting executed (by some previously set up threading I expect).

The issue is python's (IMO bizzare) scope model. I don't have a good understanding of it myself and I always have to write some "test code" to confirm I've got it right, but I believe both functions need to indicate that they are to use the global variable "motion_detected" otherwise each will have its own local variable. I could be wrong though !

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
paddyg
Posts: 2541
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: looping until flag set outside loop

Mon Aug 25, 2014 8:46 pm

As @peterO says it's slightly boggling and the first solution is to avoid global variables, but if you can't then put a line at the beginning of the function explicitly declaring them as global. If you don't do that then python will try and figure out what you might be intending by creating a new variable with the same name but local scope if you attempt to change the value of a variable with the same name as one with global scope... but if you (previously) use the variable on the right side of an assignment it will use the value of the global variable. If the variable is an object then it will do something different (look it up). You will only get a warning that there might be a problem if you do things in a sequence that (according to python's internal logic) are ambiguous.

Which is a long way of saying that if you get into the habit of using global variables, at some stage you will up till two in the morning tearing your hair out.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

jameswing
Posts: 3
Joined: Tue Aug 12, 2014 10:58 pm

Re: looping until flag set outside loop

Tue Aug 26, 2014 1:09 pm

Thanks guys! You are awesome. :P I guess I should have mentioned that "camera.start_recording(...)" started another thread in the background that calls the "DetectMotion.alalyse" method. I'll try not to make you deduce it from the output next time I beg for free help. :)

Indeed I was up 'till 2am pulling out my hair -- Paddy is as wise as Peter's beard is large. I must say that I love languages that do *less* for you and simply throw an error when you fail to declare something before you use it, but Python is pretty darned fast & easy. I guess everything is a tradeoff.

It was as simple as adding "global motion_detected" immediately after the "def analyse(self, a):" to prevent it from scoping the variable locally upon compilation, just as you guys said.

For the next poor schmuck with bald patches on his head who finds this in the wee hours, read this:
http://www.python-course.eu/global_vs_l ... iables.php

Return to “Python”