Learn how to use a PIR motion sensor with the Raspberry Pi to detect motion. We’ll show you how to wire the sensor to the Raspberry Pi GPIOs and write a Python script that does a certain task when it detects motion. To write the Python script, we’ll use the gpiozero interface.
Table of Contents
Throughout this tutorial, we’ll cover the following main topics:
- Introducing the PIR Motion Sensor
- Wiring a PIR Motion Sensor to the Raspberry Pi
- Detect Motion with the Raspberry Pi using gpiozero
Prerequisites
Before continuing with this tutorial, check the following prerequisites.
- Get familiar with the Raspberry Pi board—if you’re not familiar with the Raspberry Pi, you can read our Raspberry Pi Getting Started Guide here.
- You must know how to run and create Python files on your Raspberry Pi. We like to program our Raspberry Pi via SSH using an extension on VS Code. We have a detailed tutorial about that subject: Programming Raspberry Pi Remotely using VS Code (Remote-SSH).
- Know how to use the Raspberry Pi GPIOs so that you know how to wire the circuit properly. Read the following tutorial: Raspberry Pi Pinout Guide: How to use the Raspberry Pi GPIOs?
Introducing the PIR Motion Sensor
A PIR motion sensor detects changes in infrared light in its field of view. This makes it ideal for detecting humans or animals because it will pick up living things (or heat-emitting objects) that move within its range but not inanimate objects.
You can program the Pi to react to changes in infrared light by triggering an event such as turning on a light, sounding an alarm, sending a notification, or, as we’ll do in this project, simply printing a message in the shell.
The PIR motion sensor outputs a HIGH signal on the Data pin when it detects movement, or a LOW signal if it doesn’t. It only has three pins: VCC, GND, and Data.
Wiring a PIR Motion Sensor to the Raspberry Pi
The PIR motion sensor has three pins: VCC, GND, and Data. You should connect VCC to the 3V3 pin, GND to a GND pin, and the Data pin to a suitable Raspberry Pi GPIO—we’ll connect it to GPIO 18 (take a look at the Raspberry Pi pinout).
PIR Motion Sensor | Raspberry Pi |
Vin/3v3 | 3.3V |
Data | GPIO 18 (or another GPIO of your choice) |
GND | GND |
We’ll use the AM312 Mini PIR Motion sensor because it works with 3V3 volts, which is perfect for the Raspberry Pi.
Here’s a list of components you need for this project:
- Raspberry Pi Board – read Best Raspberry Pi Starter Kits
- Mini PIR Motion Sensor
- Breadboard
- Jumper Wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Detect Motion with the Raspberry Pi using gpiozero
After wiring the PIR motion sensor to the Raspberry Pi GPIOs, we can write a Python script to detect the state of the sensor, and thus check whether motion is detected or not. To write that script, we’ll use the gpiozero library.
The gpiozero library provides a collection of interfaces for everyday components like LEDs, buttons, potentiometers, sensors, and much more.
It provides an interface called MotionSensor, designed especially for motion sensors. It comes with several properties and functions that are useful to use with this kind of sensor.
The gpiozero library should already be installed if you’re running Raspberry Pi OS — if not, you can run:
python3 -m pip install gpiozero
Detect Motion – Python Script
The following script prints a different message in the shell depending on whether the sensor is detecting motion or not. Create a new Python file called motion-sensor.py and copy the following code.
# Complete Project Details: https://RandomNerdTutorials.com/raspberry-pi-detect-motion-pir-python/
from gpiozero import MotionSensor
from signal import pause
pir = MotionSensor(18)
def motion_function():
print("Motion Detected")
def no_motion_function():
print("Motion stopped")
pir.when_motion = motion_function
pir.when_no_motion = no_motion_function
pause()
How the Code Works
Continue reading to learn how the code works.
Importing Libraries
First, you import the MotionSensor component from the gpiozero library to handle the pushbutton. Then, you also need to import the pause() function from the signal module to keep your program running so that it can detect motion events.
from gpiozero import MotionSensor
from signal import pause
Declaring the Motion Sensor
Next, you create a MotionSensor object called pir that refers to GPIO 18, which is the GPIO that the motion sensor is connected to. Change the number if you’re using another GPIO.
pir = MotionSensor(18)
When you create and use this MotionSensor object, your program knows that GPIO 18 is connected to a PIR motion sensor.
You can pass other useful arguments to the MotionSensor class, but the default ones should work just fine by default. If your PIR motion sensor is not working as expected, you might want to try to play with its properties.
MotionSensor(pin, *, queue_len=1, sample_rate=10, threshold=0.5, partial=False, pin_factory=None)
Here’s what these parameters mean:
- pin: the GPIO the button is connected to.
- queue_len: length of the queue used to store values read from the sensor. The default is 1 which disables the queue. If your motion sensor is particularly “twitchy” you may wish to increase this value.
- sample_rate: the default value is 10—this is the number of values to read from the sensor and append to the internal queue per second.
- threshold: by default, it’s 0.5 seconds. When the average of all values in the internal queue rises above this value, the sensor will be considered active—it means motion was detected.
- partial: when False (the default), the object will not return a value for is_active until the internal queue has filled with values. Only set this to True if you require values immediately after object construction.
- pin_factory: this is an advanced feature that you won’t probably need to use or worry about.
Detect Motion Events
You can use the when_motion and when_no_motion handlers to detect when the sensor detected motion or not and associate a function to run when each event is detected.
when_motion
In the following line, when motion is detected (when_motion), it runs the motion_function that will print a message on the shell indicating that motion was detected. You can call whenever function you want to do any other different task.
pir.when_motion = motion_function
Here’s the definition of the motion_function:
def motion_function():
print("Motion Detected")
when_no_motion
You can do something similar for when the sensor stops detecting motion. In this case, when the when_no_motion event is detected, we call the no_motion_function function that prints a message on the shell.
pir.when_no_motion = no_motion_function
Here’s the definition of no_motion_function:
def no_motion_function():
print("Motion stopped")
Instead of simply printing messages on the shell, you can associate any other function that you need to run when those motion events are detected, for example, turning on/off and LED, sending a notification message, etc.
Keep the Program Running
In the end, we call the pause() function. It keeps the program running even after all the code has run through to detect events—in this case, it’s continuously checking the motion sensor state.
pause()
In summary…
1) To detect motion using a PIR motion sensor with the Raspberry Pi, you can use the MotionSensor interface of the gpiozero library. You need to import it first like this:
from gpiozero import MotionSensor
2) Define the GPIO that the motion sensor is connected to:
pir = MotionSensor(GPIO_NUMBER_OF_YOUR_CHOICE)
3) Then, use the when_motion() and when_no_motion() event handlers to run a function when motion is detected or stopped:
pir.when_motion = FUNCTION_TO_RUN_WHEN_MOTION_IS_DETECTED
pir.when_no_motion = FUNCTION_TO_RUN_WHEN_MOTION_STOPS
Demonstration
Save your Python file. Then run it on your Raspberry Pi. Run the following command:
python motion-sensor.py
Move your hand in front of the PIR motion sensor.
You should get a message on the shell mentioning that motion was detected.
After a few seconds, if it’s no longer detecting motion, you’ll a message saying that motion stopped.
You can stop the execution of the program by pressing CTRL+C.
Other Useful Methods
The MotionSensor interface provides other useful additional methods.
- wait_for_motion(timeout): it pauses the execution of the script until motion is detected or until the timeout is reached. By default, there isn’t a timeout, so the program will wait on that line of code indefinitely until motion is detected.
- wait_for_no_motion(timeout): pause the execution of the script until the motion sensor stops sensing motion or until the timeout is reached.
- motion_detected: returns True if the current value exceeds the threshold (motion detected) or False otherwise.
Wrapping Up
In this tutorial, you learned how to use the PIR motion sensor with the Raspberry Pi and run different tasks whether motion is detected or not using the gpiozero library.
We have another tutorial that shows how to send an email notification when motion is detected:
We hope you found this tutorial useful. If you’re a beginner to the Raspberry Pi, you can get started with the following tutorials:
- Getting Started with Raspberry Pi
- Raspberry Pi Pinout Guide
- Programming Raspberry Pi Remotely using VS Code (Remote-SSH)
You can check all our Raspberry Pi projects on the following link:
Thanks for reading.
First, I love your content and it’s incredible how detailed yet comprehensive you are. I identified two challenges using this guide:
1.
python3 -m pip gpiozero
should bepython3 -m pip install gpiozero
as it’s missing the action (install).2. I’m using a Raspberry Pi 5 so maybe this is specific to the new model, but I was forced to run the script as sudo and I had to export an environment variable as well. export GPIOZERO_PIN_FACTORY=native
This is because it would cause an error (missing default pin factory) without it.
Hi.
Thanks. Yes, the “install” was missing.
I haven’t tested this on a Raspberry Pi 5. I’ll take a look at that detail.
Regards,
Sara