An Easy Raspberry Pi Motion Sensing Camera with a PIR sensor and the Pi Camera Module

The basic parts for a motion sensing camera

While you can also drive a motion sensing camera via image processing on a webcam, a less processor and power intensive means is to only activate the camera when motion is sensed instead. For this a PIR Motion Sensor can be used and processing can track the signal from that device instead.

For this example I used:

Schematic

Raspberry Pi Motion Sensing Camera schematic
Wiring of PIR to GPIO header

If the PIR sensor is oriented sensor upward and pins on the bottom and sensitivity and timing potentiometers on the top in the drawing:

  • The top left pin (5V) on the GPIO header goes to the left pin on the PIR sensor.
  • The 3rd pin from the top left on the top row of the GPIO header (GND) goes to the right pin on the PIR sensor.
  • The middle pin on the PIR sensor connects to the 6th pin from the left on the bottom row of the GPIO header (GPIO 17)

Enabling the Motion Sensing Camera

  • You may need to enable SSH if you have a fresh full install of Raspbian 11 so that you can remotely manage things.
  • dtoverlay=imx219 may have to be added to /boot/config.txt to properly recognize the camera:
.
.
# Enable DRM VC4 V3D driver
dtoverlay=vc4-kms-v3d
dtoverlay=imx219
max_framebuffers=2
.
.
  • If you’re trying to use libcamera-hello to test the camera out, you may need to enable Glamor:

To do this enter sudo raspi-config at a terminal window and then choose Advanced OptionsGlamor and Yes. Finally quit raspi-config and let it reboot your Raspberry Pi.

https://www.raspberrypi.com/documentation/accessories/camera.html#getting-started

Capturing on motion detect

The following python code will capture images to /home/pi/image_captures when the motion sensor is triggered.

import RPi.GPIO as GPIO
import time
import os
import datetime

SENSOR_PIN=17

GPIO.setmode(GPIO.BCM)
GPIO.setup(SENSOR_PIN, GPIO.IN)

def my_callback(channel):
    # yes, datetime.datetime... the first is the datetime module
	today = datetime.datetime.now()
    # format a timestamp for each image capture
	date_time = today.strftime("%Y-%d-%m-%H:%M:%S")
    # be sure /home/pi/image_captures exists!
	os.system(f'libcamera-still -n -t 1 -o /home/pi/image_captures/capture{date_time}.jpg')
try:
	GPIO.add_event_detect(SENSOR_PIN, GPIO.RISING, callback=my_callback)
	while True:
		time.sleep(100)
except KeyboardInterrupt:
	print("Finish...")

GPIO.cleanup()

Adjusting sensitivity and debouncing/time delay

The left potentiometer (when facing it with the dome up) adjusts the delay between successive triggers. Turning the farthest counterclockwise reduces the time delay between triggers to the shortest time possible and clockwise the longest. If the triggers are too frequent, turn clockwise. I left mine turned to shortest time possible.

The right potentiometer adjusts the sensitivity (amount of motion) required to trigger an event. I found a couple different PIR sensors behaved significantly differently, but generally wanted this as far clockwise (most sensitive) as possible, but I wanted to trigger with as little motion as possible.

Auto starting the script

For experimentation, you’ll probably SSH in or connect to a keyboard and monitor… but for a more “production” setup, you’ll want the script to start running as soon as it boots. You can add an invocation to just before the exit 0 in /etc/rc.local:

.
.
.
sudo -u pi python /home/pi/pir.py &
exit 0

Note that I’m switching to the pi user with sudo -u pi so that I write to the pi user’s home directory with pi user permissions.

Next Steps

  • Synchronize the output from your motion sensing camera to cloud storage (with S3)
  • Notify that new motion has been detected using SNS
  • Explore a less expensive option using a Linode server with a flat bandwidth allocation instead of PUT object and per GB egress charges