Pi based Trail Camera

Ahoy!

I have been building a basic trail camera with a spare raspberry pi and my limited knowledge of python programming, I have run into an issue with the python script and I hope someone can help.

I am using a PIR sensor connected to a the Pi and falling or rising edge detection (I don’t remember which) to trigger the recording, which is working well, once I have started recording I am using time.sleep(30) then terminating the recording; however if an animal triggers a second motion event during the time.sleep(30) is there a way I can interrupt the script and reset the timer but keep the original recording going?

essentially, I would like a motion sensitive camera that could capture a cat running past (I end up with a 30 second long video of a blurry cat) or a deer hanging out for 30 minutes eating some grass (I end up with a 30 minute 30 second video of the deer)

I don’t have the actual code I have written with me but the camera recording part looks a lot like this (taken from an online tutorial)

any ideas how I can make the video length more dynamic?

import time

import picamera



with picamera.PiCamera() as camera:

    camera.start_preview()

    camera.start_recording('/home/pi/Desktop/video.h264')

    time.sleep(30)

    camera.stop_recording()

    camera.stop_preview()
1 Like

Can you possibly dig up and post all of the code? It would be very helpful in figuring out the best way to glue it all together and include re-triggering on the PIR sensor.

What you would likely need is some kind of threading- Python can do this quite simply, although it can be a painful concept to get your head around if it’s not familiar.

In short:

  • PIR sensor is constantly checked by a ‘thread’
  • When the PIR sensor is triggered, +30 seconds is added to the camera_timeout variable
  • If the camera_timeout variable is greater than 0, the camera capture should begin
  • The code should sit in a while camera_timeout > 0 loop, subtracting 1 from camera_timeout every second
  • When camera_timeout hits 0, the camera capture should end

This is a very basic, and imperfect, example of how it should work, but gives us the basis for more advanced tinkering.

2 Likes

sure, I wasn’t at home when I posted the original message.

video = 1

import RPi.GPIO as GPIO
import time
import picamera

GPIO.setmode(GPIO.BCM)
PIR_PIN = 7
GPIO.setup(PIR_PIN, GPIO.IN)
camera = picamera.PiCamera()
camera.rotation = 180

def MOTION(PIR_PIN):
    global video
    print "motion Detected\n"
    camera.start_preview()
    camera.start_recording('/home/pi/Desktop/video%03d.h264' % video)
    video += 1
    time.sleep(30)
    camera.stop_recording()
    camera.stop_preview()
    time.sleep(1)
    print "Ready\n"

try:
    GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=MOTION)
    while 1:
        time.sleep(100)

except KeyboardInterrupt:
    print "Quit"
GPIO.cleanup()

this is the code I have so far. it is a bit of a hack from various sources but functions apart from the dynamic video length

I wasn’t sure how to number the videos so I created a variable and increase it by one each time motion is detected.

1 Like

This might be over-engineered and might not work since I’m not on my Pi at the moment, but should do what you want. Worth noting that each time the PIR is triggered will add 30s to the timer, that might need some tweaking?

import thread
import time
from Queue import Queue
import RPi.GPIO as GPIO
import picamera

GPIO.setmode(GPIO.BCM)
PIR_PIN = 7
GPIO.setup(PIR_PIN, GPIO.IN)
camera = picamera.PiCamera()
camera.rotation = 180

event_queue = Queue()

def trigger_process():
    video = 1
    recording_started = False
    recording_timeout = 30.

    while True:
        if not event_queue.empty():
            # Dequeue
            event = event_queue.get()
        
            if event == 'Extend':
                if recording_started:
                    # Continue recording
                    recording_timeout = recording_timeout + 30.
                else:
                    # Start recording
                    print "Start Recording"
                    recording_timeout = 30.
                    recording_started = True
                    camera.start_preview()
                    camera.start_recording('/home/pi/Desktop/video%03d.h264' % video)
                    video += 1
                
            if event == 'Quit':
                thread.exit()
            
        if recording_started and recording_timeout <= 0.:
            #Stop recording
            print "Stop Recording"
            recording_started = False
            camera.stop_recording()
            camera.stop_preview()
        elif recording_started:
            recording_timeout = recording_timeout - 0.1
    
    time.sleep(0.1)

def motion(PIR_PIN):
    print "motion Detected\n"
    event_queue.put('Extend')
        
try:
    thread.start_new_thread( trigger_process, () )
    GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=motion)

    while 1:
        time.sleep(100)

except KeyboardInterrupt:
    event_queue.put('Quit')
    print "Quit"
2 Likes

thank you major_tomm, it didn’t quite work and I wasn’t able to debug it… but your code along with gadgetoids advice has sent me in the right direction… I still have a couple of things to iron out but I am really close now, I will post back when complete.

1 Like

Sorry about that, I created the threaded framework and sort of just shoved the camera stuff on top without testing it. If I had to guess, it’s probably that you need to move the camera stuff declared at the top into the main method: trigger_process.

2 Likes

I would just like to say that for a keen photographer who is about to receive their first pi cam - this thread has been somewhat of an eye-opener… 8) My appreciation to all parties.

I appreciate the effort major_tomm, I will try moving the camera stuff later on, I have only been chipping away for 20/30 minutes a night.

ZooC0d3, I love the camera module, it is really simple to get working (for a novice like me) but offers tons of potential!

1 Like

it is a bit clunky but up and running. I had an issue with starting and stopping recordings that didn’t exist, so introduced a recording variable.

when motion is detected by GPIO rising the counter is set to 30 (regardless of any other state)

if the counter = more than 0 but recording is 0: it will set recording to 1 and start the recording
if the counter = more than 0 and recording = 1: every second 1 is subtracted from the counter
if the counter = 0 and recording = 1: the recording is stopped, video is increased by 1 (used for the file numbers) and recording is set to 0
if the counter = 0 and the recording = 0: it runs in idle

counter = 0
recording = 0
video = 1

import RPi.GPIO as GPIO
import time
import picamera

GPIO.setmode(GPIO.BCM)
PIR_PIN = 7
GPIO.setup(PIR_PIN, GPIO.IN)
camera = picamera.PiCamera()
camera.rotation = 180

print "trail camera v1.0\n"
time.sleep(1)
print "ready\n"
time.sleep(1)

def motion(PIR_PIN):
    global counter
    print "motion detected\n"
    counter = 30
    time.sleep(1)

GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=motion)

while True:
    if counter > 0:
        if recording == 0:
            recording = 1
            print "recording\n"
            camera.start_recording('/home/pi/Desktop/video%03d.h264' % video)
            time.sleep(1)
        if recording == 1:
            print (counter)
            print ""
            time.sleep(1)
            counter -= 1
    if counter == 0:
        if recording == 0:
            print "idle\n"
            time.sleep(5)
        if recording == 1:
            print "recording stopped\n"
            camera.stop_recording()
            video += 1
            recording = 0
            time.sleep(1)

try:
    while 1:
        time.sleep(100)

except KeyboardInterrupt:
    print "Quit"
GPIO.cleanup()

the last thing to solve is putting the video in an MP4 container, I have installed MP4Box and can convert the videos in terminal, I just need to work out how to run this in the python script.

MP4Box -fps 30 -add myvid.h264 myvid.mp4

1 Like

Hi,

I just got my PIR Sensor connected to my PiZW and it works using the Python code in this thread (Bootnut).

Personally I lack the skill of programming. However I would like to modify the code that I get a time stamp ( timeofday ) shown on the console whenever motion is detected.

Where should that print timeofday be inserted and which syntax ?

A few questions concerning the code:

  • I don´t need camera preview , so either line delete camera.start_preview() or uncomment with #
  • print “motion Detected\n” ? the \n what does it mean ?
  • three time.sleep(xxx) are listed in the code 30, 100, 1 ? time in seconds ?

Thanks in advance for any help

calleblyh
soutwest archipelago Finland

Python’s datetime.datetime.now() has a fairly useful default to-string method, so you can just:

import datetime
print(datetime.datetime.now())

Or use string formatting:

print("The time is {}".format(datetime.datetime.now()))

That should do the trick, yes!

\n is the escape code for newline. It would be the same as the, slightly convoluted,:

print("""Some text
""")

Yup! That’s time in seconds. It can be a float, too, like 0.1 seconds.

1 Like

It’s been a while since I looked at this code, I put the print “motion Detected\n” part in so I could see what the software is doing when I was throwing this together. I think the \n was just so it looked better.

“Personally I lack the skill of programming.” This was my first major pi project, I’m not a coder, I just stitched stuff together until it worked. Take a look at Carrie Ann Philbins book in the store, I find it really helpful :) or just random tutorials / examples online

1 Like

I keep telling people this- my career is just the logical conclusion of this technique :D

3 Likes

Thanks a lot, exactly what I needed

calleblyh

It really is the best method, I’m slightly jealous you made it into a job!

Hi, I have adopted this python code for my surveillance camera. Now I would like to get a smaller preview window as compared to raspivid -p 200,200,320,240 . Alternatively to take a snapshot when motion is detected. Unfortunately I dont know how to write this code. So asking for help on the forum.

Thanks in advance

CalleBlyh
/Helsinki