Motion Alarm — First Arduino Build
I picked up an Inland Nano at Micro Center — their in-house Arduino Nano clone — and wanted to get something blinking and beeping before committing it to a real project. The result was a motion-triggered alarm: PIR sensor on a breadboard, buzzer, LED, done in about an hour using components from a cheap starter kit.
My son walked in while I was testing it, immediately set it off, thought it was hilarious, and spent the next ten minutes walking past it on purpose. He now wants to turn it into a booby trap for his bedroom door. We might actually do that.
This was also my first microcontroller project. Everything else I’ve built has been on a Raspberry Pi — a full Linux box — so this felt like a different discipline. I’ll get to that at the end.
What it does
When the PIR sensor detects motion, the buzzer sounds and the LED flashes — both pulsing at 100ms intervals — until the sensor stops detecting movement. Simple, but satisfying when it actually works.
What you need
Everything except the Nano and cable is in a standard Arduino starter kit. The Keyes kit from Micro Center has the PIR sensor, buzzer, LEDs, and resistors all included.
| Component | Qty | Notes | Source |
|---|---|---|---|
| Arduino Nano | 1 | Inland Nano 3 (ATmega328P, CH340 USB-serial) | https://www.microcenter.com/product/643085/inland-nano-3-microcontroller |
| PIR Motion Sensor | 1 | HC-SR501 — included in most starter kits | |
| Active Buzzer | 1 | Module with VCC/GND/S pins — not a bare component | |
| LED | 1 | 5mm, any color | |
| Resistor | 1 | 220Ω for LED current limiting | |
| Breadboard | 1 | Half-size or larger | |
| USB-A to USB-C cable | 1 | Data-capable — charge-only cables won't work |
Wiring
Everything runs off USB power through the Nano — no external supply needed. Total draw is around 125mA, well under the 500mA USB limit.
| Component | Pin | Arduino Nano |
|---|---|---|
| PIR Sensor | VCC | 5V |
| PIR Sensor | GND | GND |
| PIR Sensor | OUT | D2 |
| Active Buzzer | VCC | 5V |
| Active Buzzer | GND | GND |
| Active Buzzer | S | D8 |
| LED (via 220Ω) | Anode | D13 |
| LED | Cathode | GND |
One thing that caught me: the Keyes buzzer is a module, not a bare component. It has an onboard transistor driver, so the S pin takes a logic signal — you’re not driving the buzzer directly. I wired it directly the first time and got nothing. Check if yours has the same 3-pin format before wiring.
The sketch
No external libraries. Pure Arduino built-ins, 36 lines.
const int PIR_PIN = 2;
const int BUZZER_PIN = 8;
const int LED_PIN = 13;
void setup() {
pinMode(PIR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
// PIR sensors need ~30s to calibrate on power-up
Serial.println("Calibrating PIR sensor...");
for (int i = 0; i < 30; i++) {
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
}
Serial.println("Ready.");
}
void loop() {
if (digitalRead(PIR_PIN) == HIGH) {
Serial.println("Motion detected!");
while (digitalRead(PIR_PIN) == HIGH) {
digitalWrite(BUZZER_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
delay(100);
}
Serial.println("All clear.");
}
}
The alarm runs in a loop while the PIR pin stays HIGH rather than for a fixed duration. I tried a fixed 3-second timeout first and it felt wrong — the alarm would cut off mid-motion and then immediately retrigger. Tracking the pin directly is simpler and more correct.
PIR quirk — calibration delay: On power-up the sensor needs about 30 seconds to stabilize. The LED blinks slowly during that window so you know it’s not ready yet. Don’t set it off across the room and wonder why nothing happens.
Adjusting hold time: The HC-SR501 has two small potentiometers on the back. The one labelled Tx controls how long the output stays HIGH after detecting motion — fully counterclockwise is up to ~5 minutes, fully clockwise is ~5 seconds. I turned mine fully clockwise so the alarm clears quickly after someone walks past.
Flashing
You’ll need arduino-cli — install with brew install arduino-cli on a Mac, then from the repo root:
# One-time: install the AVR core
bash scripts/setup-arduino-cli.sh
# Compile and flash (close any serial monitor first — it holds the port)
bash projects/motion-alarm/scripts/deploy.sh
Default port is /dev/cu.usbserial-210. If the Nano shows up on a different port:
bash projects/motion-alarm/scripts/deploy.sh /dev/cu.usbserial-XXXX
To watch calibration and trigger events over serial:
arduino-cli monitor -p /dev/cu.usbserial-210
On switching from Pi to Arduino
All my previous projects were on a Raspberry Pi — full Linux, SSH in, install packages, write Python, babysit a systemd service. An Arduino is a completely different model: no OS, no filesystem, no shell. You write one sketch, flash it, and the board runs that sketch forever.
It’s actually simpler. There’s nothing to misconfigure, no services to start, no SD card to image. The feedback loop is faster too — compile and flash takes a few seconds, and the serial output tells you exactly what the sketch is doing.
The toolchain felt more approachable than I expected. arduino-cli handles everything from the command line, and the sketch itself is essentially C with a handful of familiar functions. If you’ve written any C — or even Java — the structure is immediately recognizable.
If this sounds like fun and you don’t have an Arduino yet: a starter kit from Micro Center runs around $25–30 and includes everything on the parts list above except the Nano itself (~$12 for the Inland). That’s a $40 entry point to get something actually working in an afternoon.
What’s next
The plan is to turn this into a proper door alarm. Instead of a PIR sensor — which triggers on any movement in the room — we’ll swap in an IR break-beam: a transmitter and receiver mounted on opposite sides of the door frame. It only triggers when someone actually crosses the threshold. Harder to accidentally set off, much more satisfying as a booby trap.