5 HC-SR501 PIR Motion Sensor Projects That React to Your Presence
Build presence-triggered projects: automatic night light, smart display, wildlife camera, motion doorbell, and intelligent shelf
The HC-SR501 PIR motion sensor is one of the most popular passive infrared sensors in the maker world. It detects body heat (infrared radiation) from moving people (and animals) within its field of view. In this guide, we'll build five complete presence-triggered projects using this $2 sensor — from a simple auto night light to a full wildlife camera system.
Topics covered: Arduino programming, PIR sensor integration, threshold logic, relay control, camera triggers, event-driven automation, physical build tips.
Affiliate disclosure: As an Amazon Associate, I earn from qualifying purchases.
Affiliate links: HC-SR501 PIR Sensor on Amazon | Arduino Nano on Amazon | Jumper wires on Amazon
What You'll Need
- HC-SR501 PIR sensor (×5 for complete builds, or ×1 for sequential testing)
- Arduino Nano or Uno (×1)
- USB cable for programming
- Breadboard and jumper wires
- 5V relay module (for night light and display projects)
- LED strip (5V) or bulb with holder (for night light)
- Raspberry Pi camera module or USB webcam (for wildlife camera)
- Piezo buzzer (for doorbell project)
- 16×2 LCD I2C display (for display and shelf projects)
- Power supply (5V 2A for LED strip)
How the HC-SR501 Works
Before diving into the projects, let's understand the sensor's operation:
Arduino HC-SR501
Pin 7 ────── OUT (digital signal)
5V ────── VCC
GND ────── GND
Detection mechanism:
- Sensor uses a passive pyroelectric element that detects changes in infrared levels
- A Fresnel lens wideens the detection field to ~120° and ~7 meters
- When a warm body (human/animal) moves across the detection zones, the signal changes
- Sensor outputs a HIGH (3.3V) digital signal for the duration of detected motion
- After motion stops, output goes LOW after a set timeout (adjustable via potentiometer)
// Basic PIR read
int pirPin = 7;
void setup() {
pinMode(pirPin, INPUT);
Serial.begin(115200);
}
void loop() {
int motion = digitalRead(pirPin);
if (motion == HIGH) {
Serial.println(&tag=hfchang-20"Motion detected!");
} else {
Serial.println("No motion.");
}
delay(200);
}
Project 1: Automatic Night Light
Goal: Turn on an LED strip or bulb when someone enters the room, automatically turn it off after they leave.
Hardware
- HC-SR501 PIR sensor
- Arduino Nano
- 5V relay module
- 5V LED strip (warm white) or 5V bulb
- 5V 2A power supply
Wiring
HC-SR501: OUT→Pin 7, VCC→5V, GND→GND
Relay: Signal→Pin 8, VCC→5V, GND→GND
COM → LED strip positive, NO → 5V power
Code
// WF1 Run #035 - Project 1: Automatic Night Light
// HC-SR501 PIR + LED Strip via Relay
#define PIR_PIN 7
#define RELAY_PIN 8
#define MOTION_TIMEOUT_MS 5000 // keep light on for 5s after last motion
bool lightOn = false;
unsigned long lastMotionTime = 0;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // start with light off
Serial.println("Night light ready.");
}
void loop() {
int motion = digitalRead(PIR_PIN);
if (motion == HIGH) {
lastMotionTime = millis();
if (!lightOn) {
setLight(true);
}
Serial.println("Motion detected - light ON");
}
// Turn off after timeout with no motion
if (lightOn && (millis() - lastMotionTime > MOTION_TIMEOUT_MS)) {
setLight(false);
Serial.println("Timeout - light OFF");
}
delay(100);
}
void setLight(bool on) {
digitalWrite(RELAY_PIN, on ? HIGH : LOW);
lightOn = on;
}
Build Notes
- Mount the PIR sensor near the entrance door, facing into the room
- Adjust the two potentiometers on the HC-SR501:
- Sensitivity (Sx): Clockwise = longer detection range (~7m), counter-clockwise = shorter (~3m)
- Time (Tx): Clockwise = longer hold time (~300s), counter-clockwise = shorter (~5s)
- Set Tx to minimum (5s) and let the Arduino handle the timeout for more precise control
- The relay handles AC or DC loads — verify your relay rating matches your bulb
Want a custom enclosure or PCB for this project? I offer rapid prototyping and sensor integration on Fiverr.
Project 2: Smart Display Sign
Goal: A display that wakes up and shows a welcome message when someone approaches.
Hardware
- HC-SR501 PIR sensor
- Arduino Nano
- 16×2 LCD I2C display
- 5V relay module (for backlight)
- 5V LED backlight strip
Wiring
HC-SR501: OUT→Pin 7, VCC→5V, GND→GND
LCD I2C: SDA→A4, SCL→A5, VCC→5V, GND→GND
Relay: Signal→Pin 8, VCC→5V, GND→GND (controls LCD backlight power)
Code
// WF1 Run #035 - Project 2: Smart Display Sign
// HC-SR501 + 16x2 LCD I2C + Relay Backlight
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define PIR_PIN 7
#define RELAY_PIN 8
#define MOTION_TIMEOUT_MS 8000 // display stays on 8s after last motion
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool displayOn = false;
unsigned long lastMotionTime = 0;
const char* messages[] = {
"Hello, Guest! ",
"Welcome to the ",
" Showroom! "
};
int msgIndex = 0;
unsigned long lastScroll = 0;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // backlight off initially
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Smart Display ");
lcd.setCursor(0, 1);
lcd.print("Waiting... ");
delay(2000);
lcd.clear();
Serial.println("Smart display ready.");
}
void loop() {
int motion = digitalRead(PIR_PIN);
if (motion == HIGH) {
lastMotionTime = millis();
if (!displayOn) {
wakeDisplay();
}
Serial.println("Motion detected - display ON");
}
if (displayOn) {
// Scroll messages every 3 seconds
if (millis() - lastScroll > 3000) {
scrollMessage();
lastScroll = millis();
}
// Turn off after timeout
if (millis() - lastMotionTime > MOTION_TIMEOUT_MS) {
sleepDisplay();
Serial.println("Timeout - display OFF");
}
}
delay(100);
}
void wakeDisplay() {
displayOn = true;
digitalWrite(RELAY_PIN, HIGH); // power on backlight
lcd.backlight();
msgIndex = 0;
scrollMessage();
lastScroll = millis();
}
void sleepDisplay() {
displayOn = false;
digitalWrite(RELAY_PIN, LOW); // power off backlight
lcd.noBacklight();
lcd.clear();
}
void scrollMessage() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(messages[msgIndex]);
lcd.setCursor(0, 1);
lcd.print(messages[(msgIndex + 1) % 3]);
msgIndex = (msgIndex + 2) % 3;
}
Build Notes
- The relay cuts power to the LCD backlight to completely darken the display when idle (saves power)
- The 16×2 LCD draws ~1.5mA with backlight off, ~25mA with backlight on
- For outdoor use, swap the 16×2 LCD for an OLED display — they are sunlight-readable and have no backlight
- Position the PIR sensor to cover the primary viewing angle (~120° field, aim at chest height)
Need help sourcing an outdoor-rated display or writing custom messages? I can help with component selection and firmware on Fiverr.
Project 3: Wildlife Camera
Goal: Automatically capture photos or videos when animals move past a trail camera setup.
Hardware
- HC-SR501 PIR sensor
- Arduino Nano
- Raspberry Pi Camera Module (or USB webcam)
- 5V relay module (for camera power control)
- SD card module (optional, for local storage)
- 5V 2A power supply (or 4×AA battery pack)
- Weatherproof enclosure (IP65 box)
Wiring
HC-SR501: OUT→Pin 7, VCC→5V, GND→GND
Relay: Signal→Pin 8, VCC→5V, GND→GND (controls camera power)
Camera: Connected via Pi GPIO or USB to Arduino (simplified: just trigger notification)
Code
// WF1 Run #035 - Project 3: Wildlife Camera
// HC-SR501 PIR + Camera Trigger
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#define PIR_PIN 7
#define RELAY_PIN 8
#define SD_CS_PIN 10
#define TRIGGER_PIN 9 // camera trigger output
#define COOLDOWN_MS 30000 // 30s between captures (prevents memory flooding)
bool cameraPowered = false;
unsigned long lastCaptureTime = 0;
int photoCount = 0;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // camera off
digitalWrite(TRIGGER_PIN, LOW);
// Initialize SD card
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD card init failed!");
} else {
Serial.println("SD card ready.");
}
Serial.println("Wildlife camera ready.");
}
void loop() {
int motion = digitalRead(PIR_PIN);
if (motion == HIGH) {
unsigned long now = millis();
// Cooldown check
if (now - lastCaptureTime < COOLDOWN_MS) {
Serial.print("Cooldown active. Next capture in ");
Serial.print((COOLDOWN_MS - (now - lastCaptureTime)) / 1000);
Serial.println("s");
return;
}
lastCaptureTime = now;
capturePhoto();
}
delay(100);
}
void capturePhoto() {
Serial.println("Motion detected! Capturing photo...");
// Power on camera
digitalWrite(RELAY_PIN, HIGH);
cameraPowered = true;
delay(2000); // camera boot time
// Trigger camera (implementation depends on your camera interface)
digitalWrite(TRIGGER_PIN, HIGH);
delay(100);
digitalWrite(TRIGGER_PIN, LOW);
Serial.println("Photo captured!");
// Log to SD card
File logFile = SD.open("capture.log", FILE_WRITE);
if (logFile) {
photoCount++;
logFile.print("Photo #");
logFile.print(photoCount);
logFile.print(" captured at ");
logFile.println(millis());
logFile.close();
}
// Power off camera to save battery
digitalWrite(RELAY_PIN, LOW);
cameraPowered = false;
Serial.print("Total photos: ");
Serial.println(photoCount);
}
Build Notes
- The HC-SR501 can detect animals (warm bodies) up to 7m away — position based on your target species
- Small mammals (rodents) have less IR signature — lower the sensor sensitivity or use a focused lens
- For a Raspberry Pi camera, use the
raspistillcommand viasystem()call in Arduino logic or a separate Pi script - Weatherproofing: use a silicone-sealed IP65 enclosure, and poke a small hole for the PIR lens
- The 30-second cooldown prevents rapid-fire captures from long-detected motion (e.g., someone walking slowly)
- For battery operation, use a 5V USB power bank (~10,000mAh for ~3 weeks of standby)
Building a custom trail camera housing or need help with the Pi camera integration? I offer electronics prototyping and build services on Fiverr.
Project 4: Motion Doorbell
Goal: Detect visitors and sound a chime, with visual alert and optional SMS notification.
Hardware
- HC-SR501 PIR sensor
- Arduino Nano
- Piezo buzzer (passive)
- RGB LED (for visual alert)
- Push button (manual chime override)
- 220Ω resistors (×3 for RGB LED)
Wiring
HC-SR501: OUT→Pin 7, VCC→5V, GND→GND
Buzzer: Signal→Pin 6, VCC→5V, GND→GND
RGB LED: R→Pin 3, G→Pin 4, B→Pin 5 (via 220Ω resistors each)
Button: Signal→Pin 9, INPUT_PULLUP, GND→GND
Code
// WF1 Run #035 - Project 4: Motion Doorbell
// HC-SR501 PIR + Piezo Buzzer + RGB LED
#define PIR_PIN 7
#define BUZZER_PIN 6
#define RGB_R_PIN 3
#define RGB_G_PIN 4
#define RGB_B_PIN 5
#define BUTTON_PIN 9
#define CHIME_DURATION_MS 2000
#define COOLDOWN_MS 5000 // prevent rapid re-triggers
bool visitorAlert = false;
unsigned long lastChimeTime = 0;
bool chimeActive = false;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RGB_R_PIN, OUTPUT);
pinMode(RGB_G_PIN, OUTPUT);
pinMode(RGB_B_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
digitalWrite(BUZZER_PIN, LOW);
setRGB(0, 0, 0); // all off
Serial.println("Motion doorbell ready.");
}
void loop() {
int motion = digitalRead(PIR_PIN);
int button = digitalRead(BUTTON_PIN);
// Motion detected
if (motion == HIGH) {
unsigned long now = millis();
if (now - lastChimeTime > COOLDOWN_MS) {
lastChimeTime = now;
triggerChime();
}
}
// Manual button press
if (button == LOW) {
triggerChime();
}
// Manage chime lifecycle
if (chimeActive && (millis() - lastChimeTime > CHIME_DURATION_MS)) {
stopChime();
}
delay(50);
}
void triggerChime() {
Serial.println("Visitor detected! Sounding chime...");
chimeActive = true;
lastChimeTime = millis();
// Play two-tone chime
playTone(880, 300); // A5 for 300ms
delay(100);
playTone(1047, 400); // C6 for 400ms
// Flash blue LED for visual alert
flashRGB(0, 0, 255, 3, 200);
}
void playTone(int frequency, int durationMs) {
tone(BUZZER_PIN, frequency, durationMs);
delay(durationMs);
noTone(BUZZER_PIN);
}
void stopChime() {
chimeActive = false;
noTone(BUZZER_PIN);
setRGB(0, 0, 0);
}
void setRGB(int r, int g, int b) {
digitalWrite(RGB_R_PIN, r);
digitalWrite(RGB_G_PIN, g);
digitalWrite(RGB_B_PIN, b);
}
void flashRGB(int r, int g, int b, int times, int delayMs) {
for (int i = 0; i < times; i++) {
setRGB(r, g, b);
delay(delayMs);
setRGB(0, 0, 0);
delay(delayMs);
}
}
Build Notes
- Position the PIR sensor above the door frame, angled slightly downward (covers ~120° cone from ~1.5m height)
- The standard HC-SR501 has a 5-second minimum "off" time after the Tx potentiometer-set duration — factor this into your cooldown
- The passive piezo buzzer draws ~5mA — can run directly from Arduino pins
- For a louder chime, use an active buzzer through a relay, or a small speaker driven by an LM386 amplifier
- The manual push button provides a backup "classic" doorbell function
Need a louder chime mechanism or help with enclosure design? I build custom doorbell systems on Fiverr.
Project 5: Smart Shelf Sensor
Goal: Detect when items are picked from or returned to a shelf, and display inventory status.
Hardware
- HC-SR501 PIR sensor (×3 for multiple shelves)
- Arduino Nano
- 16×2 LCD I2C display
- 5V power supply
Wiring
HC-SR501 #1 (top shelf): OUT→Pin 7, VCC→5V, GND→GND
HC-SR501 #2 (mid shelf): OUT→Pin 12, VCC→5V, GND→GND
HC-SR501 #3 (bot shelf): OUT→Pin 13, VCC→5V, GND→GND
LCD I2C: SDA→A4, SCL→A5, VCC→5V, GND→GND
Code
// WF1 Run #035 - Project 5: Smart Shelf Sensor
// 3x HC-SR501 PIR + 16x2 LCD I2C Inventory Display
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define PIR_TOP 7
#define PIR_MID 12
#define PIR_BOT 13
#define MOTION_TIMEOUT_MS 3000 // consider item "returned" after 3s of no motion
LiquidCrystal_I2C lcd(0x27, 16, 2);
struct ShelfZone {
int pin;
bool occupied;
unsigned long lastMotion;
const char* name;
};
ShelfZone zones[3] = {
{PIR_TOP, false, 0, "Top Shelf "},
{PIR_MID, false, 0, "Mid Shelf "},
{PIR_BOT, false, 0, "Bot Shelf "}
};
void setup() {
Serial.begin(115200);
for (int i = 0; i < 3; i++) {
pinMode(zones[i].pin, INPUT);
}
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Smart Shelf v1.0");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(2000);
lcd.clear();
Serial.println("Smart shelf ready.");
}
void loop() {
unsigned long now = millis();
for (int i = 0; i < 3; i++) {
int motion = digitalRead(zones[i].pin);
if (motion == HIGH) {
zones[i].lastMotion = now;
if (!zones[i].occupied) {
zones[i].occupied = true; // item picked
Serial.print(zones[i].name);
Serial.println("item picked!");
}
} else if (zones[i].occupied && (now - zones[i].lastMotion > MOTION_TIMEOUT_MS)) {
// Item returned (no motion for 3s while marked as occupied)
zones[i].occupied = false;
Serial.print(zones[i].name);
Serial.println("item returned!");
}
}
updateDisplay();
delay(100);
}
void updateDisplay() {
lcd.setCursor(0, 0);
// Line 1: shelf status
for (int i = 0; i < 3; i++) {
lcd.print(zones[i].occupied ? '[', ')');
lcd.print(' ');
}
// Line 2: inventory summary
int picked = countOccupied();
lcd.setCursor(0, 1);
if (picked == 0) {
lcd.print("All items present ");
} else {
lcd.print("Items picked: ");
lcd.print(picked);
lcd.print(" ");
}
}
int countOccupied() {
int count = 0;
for (int i = 0; i < 3; i++) {
if (zones[i].occupied) count++;
}
return count;
}
Build Notes
- The PIR sensor detects body heat from hands, not objects directly — so the logic is "hand present = item being picked"
- Mount sensors underneath each shelf, pointing upward toward the items
- For better accuracy, use IR reflective sensors (like TCRT5000) across the shelf width — these detect the physical presence of an object
- The 3-second motion timeout handles hand repositioning without false "returned" triggers
- This project can scale to a full pantry/frig monitoring system with more sensors
Want to expand this to a full smart pantry system with web monitoring? I build inventory tracking and IoT solutions on Fiverr.
Troubleshooting Table
| Problem | Cause | Solution |
|---|---|---|
| PIR always outputs HIGH | Sensor too sensitive, sees own heat | Reposition sensor away from Arduino, add shielding |
| PIR doesn't detect motion | Lens covered or dirty | Clean lens with soft cloth, check 5s Tx delay has elapsed |
| Relay clicks but load doesn't activate | Load voltage/wattage exceeds relay rating | Check relay spec — use SSR for high-power loads |
| LCD shows garbled text | I2C address mismatch | Scan I2C addresses, update LiquidCrystal_I2C(0x27, 16, 2)
|
| Camera doesn't trigger | Camera boot time too short | Increase delay(2000) after power-on in capturePhoto() |
| Night light flickers | PIR retriggers during timeout | Verify Tx potentiometer is set to minimum (5s) |
| Multiple motion events for one pass | Fresnel lens creates multiple detection zones | Use a cardboard tube to narrow the field of view |
Shopping List
| Component | Quantity | Amazon Link |
|---|---|---|
| HC-SR501 PIR Sensor | ×5 | Buy on Amazon |
| Arduino Nano | ×1 | Buy on Amazon |
| Jumper Wires | 1 pack | Buy on Amazon |
| 5V Relay Module | ×3 | Buy on Amazon |
| 16×2 LCD I2C Display | ×1 | Buy on Amazon |
| Piezo Buzzer | ×1 | Buy on Amazon |
| RGB LED | ×1 | Buy on Amazon |
| 5V LED Strip | ×1 | Buy on Amazon |
| 5V 2A Power Supply | ×1 | Buy on Amazon |
| Breadboard | ×1 | Buy on Amazon |
Next Steps
- Combine sensors: Add an HC-SR04 ultrasonic sensor for distance-based confirmation — reduces false triggers
- Wireless integration: Add an ESP8266 WiFi module to send motion events to Home Assistant or Blynk
- Solar power: Power outdoor projects with a 5V solar panel + 18650 battery management module
- Custom PCB: Once your prototype is stable, design a custom PCB to reduce wiring clutter
Next Step: From Scene to Sensor, Without Writing Code
If this guide gave you ideas for your own setup — but you're not sure which sensors and outputs work best for your specific space — I can help you map that out.
I offer a personalized interactive device design guide at Fiverr:
👉 https://www.fiverr.com/phd_hfchang/generate-an-arduino-interactive-prototypef
What you get:
- A custom guide based on your actual scene (not generic recommendations)
- Sensor selection matched to user behavior and physical constraints
- Interaction logic without needing to write code from scratch
- Testing methodology with pass/fail criteria for each output
This article is part of the **WF1 Projects* series. Previous: 5 HC-SR04 Ultrasonic Sensor Projects. Next: Environmental Sensor Integrations.*






Top comments (0)