ESP32 UNO - Motion Sensor - Servo Motor

Need a servo arm that reacts when a person walks past? Hook an HC-SR501 PIR motion sensor and a hobby servo to the ESP32 Uno form board, and the arm swings by itself. The PIR sensor spots body heat, and the servo moves between 0 and 90 degrees as the motion starts and ends. Use the build for a pet gate, a moving camera mount or a small robot arm.

What you will do:

  1. Wire a PIR motion sensor and a servo to the ESP32 Uno
  2. Tune the HC-SR501 time delay, range and trigger jumper
  3. Catch the moment the sensor output changes with digitalRead()
  4. Drive the servo angle with the ESP32Servo library
ESP32 Uno motion sensor servo motor

Hardware Preparation

1×ESP32 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×HC-SR501 Motion Sensor
1×Alternatively, AM312 Mini Motion Sensor
1×Servo Motor
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Buy Note: For controlling multiple servo motors, use the PCA9685 16 Channel PWM Servo Driver Module to save MCU pins and simplify wiring.

Meet the Two Parts

After this part, you know the job of each part in the build.

Part Role in This Build Signal
HC-SR501 PIR sensor Input. Senses infrared heat from a moving body OUT pin, HIGH or LOW
Servo motor Output. Turns its horn to a set angle from 0 to 180 degrees PWM pulse on one wire

For the full pinout and basics of each part, open its own page:

ESP32 Uno Pinout

Your sketch talks to GPIO numbers, while the board labels show Uno names like D2 and D9. Look up both in the picture below before you plug in a wire.

ESP32 Uno pinout diagram

How to Connect

At the end of this part, the sensor and the servo share power and each has its own signal pin.

The wiring diagram between ESP32 Uno Motion Sensor Servo Motor

This image is created using Fritzing. Click to enlarge image

Component Pin ESP32 Uno Pin
Motion Sensor VCC 5V
Motion Sensor OUT D2 (GPIO26)
Motion Sensor GND GND
Servo VCC (red wire) 5V
Servo GND (brown or black wire) GND
Servo Signal (orange or yellow wire) D9 (GPIO13)

Good to know: the HC-SR501 takes 5V power, yet its OUT pin swings only to about 3.3V, so D2 (GPIO26) can read it directly with no level shifter.

※ NOTE THAT:

ESP32 Uno pins use 3.3V logic and are NOT 5V tolerant. Here no 5V signal reaches a board pin: the servo gets 5V on its red wire, but its signal wire only listens to the 3.3V pulse from D9 (GPIO13). Almost every hobby servo accepts that pulse.

Sensor Setup

Set the two screws and the jumper once, and the sensor reacts fast with its widest reach.

Time Delay AdjusterRotate it all the way anti-clockwise.
Detection Range AdjusterRotate it all the way clockwise.
Repeat Trigger SelectorSet the jumper to match the picture.
ESP32 Uno motion sensor initial setting

ESP32 Uno Code - PIR Sensor Moves the Servo

This sketch watches D2 (GPIO26) for a change in the sensor output, prints a line, and sets the servo on D9 (GPIO13) to 90 or 0 degrees.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-motion-sensor-servo-motor */ #include <ESP32Servo.h> #define MOTION_SENSOR_PIN 26 // D2 (GPIO26) reads the PIR sensor OUT pin #define SERVO_PIN 13 // D9 (GPIO13) sends the PWM signal to the servo Servo servo; // servo object that drives the motor // values that change while the sketch runs: int angle = 0; // start angle of the servo arm int prev_motion_state; // sensor reading from the previous pass int motion_state; // sensor reading from this pass void setup() { Serial.begin(9600); // start the Serial Monitor link pinMode(MOTION_SENSOR_PIN, INPUT); // D2 (GPIO26) works as a plain input servo.attach(SERVO_PIN); // link the servo object to D9 (GPIO13) servo.write(angle); motion_state = digitalRead(MOTION_SENSOR_PIN); } void loop() { prev_motion_state = motion_state; // keep the old reading motion_state = digitalRead(MOTION_SENSOR_PIN); // take a fresh reading if (motion_state == LOW && prev_motion_state == HIGH) { // OUT pin changed from HIGH to LOW Serial.println("Motion detected!"); servo.write(90); } else if (motion_state == HIGH && prev_motion_state == LOW) { // OUT pin changed from LOW to HIGH Serial.println("Motion stopped!"); servo.write(0); } }

Good to know: the classic Servo.h library does not build for the ESP32 Uno. The sketch includes ESP32Servo.h instead, which keeps the same attach() and write() calls.

Upload and Test

  1. First time with this board? Set it up with ESP32 Uno - Getting Started before you continue.
  2. Build the circuit by following the wiring table above.
  3. Plug in the USB Type-C cable between the ESP32 Uno and your computer.
  4. Select the board in Arduino IDE: pick ESP32 Dev Module and the COM port of the board (CH340).
  5. Add the servo library. In the Library Manager, type ESP32Servo and install the release by Kevin Harrington.
  6. Paste the sketch into a new Arduino IDE window.
  7. Click Upload and wait for "Done uploading".
  8. Open the Serial Monitor and set it to 9600 baud.
  9. Walk past the sensor about one meter away, then stand still.
  10. Watch the servo horn swing and read the lines in the Serial Monitor.
  11. Pro tip: tape a paper flag to the servo horn. The bigger arm makes each move easy to see from across the room while you test the range screw.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
Motion detected! Motion stopped! Motion detected! Motion stopped! Motion detected!
Ln 11, Col 1
ESP32 Dev Module on COM15
2

Video: Motion-Activated Door

See the ESP32 Uno build in action in the video below.

The end of the video shows an automatic door: a servo opens it and a buzzer beeps when someone comes close. Here is that sketch for the ESP32 Uno.

Part ESP32 Uno Pin
Motion Sensor OUT D2 (GPIO26)
Door Servo Signal D5 (GPIO16)
Buzzer D6 (GPIO27)
#include <ESP32Servo.h> #define SENSOR_PIN 26 // D2 (GPIO26) reads the PIR sensor OUT pin #define SERVO_PIN 16 // D5 (GPIO16) drives the door servo #define BUZZER_PIN 27 // D6 (GPIO27) drives the buzzer Servo servo; int motion_state = LOW; // sensor reading from this pass, starts LOW int prev_motion_state = LOW; // sensor reading from the previous pass, starts LOW void setup() { Serial.begin(9600); // open the Serial Monitor link at 9600 baud pinMode(SENSOR_PIN, INPUT); // D2 (GPIO26) listens to the sensor pinMode(BUZZER_PIN, OUTPUT); // D6 (GPIO27) sends sound to the buzzer servo.attach(SERVO_PIN); servo.write(0); noTone(BUZZER_PIN); } void beep() { for (int i = 0; i < 2; i++) { tone(BUZZER_PIN, 5000); delay(100); noTone(BUZZER_PIN); delay(100); } } void loop() { prev_motion_state = motion_state; // move the last reading into the "old" slot motion_state = digitalRead(SENSOR_PIN); // read the sensor OUT pin again // OUT rose from LOW to HIGH, so someone is moving if (prev_motion_state == LOW && motion_state == HIGH) { Serial.println("Motion detected!"); // tell the Serial Monitor servo.write(180); beep(); // put extra actions for "someone arrived" here } // OUT fell from HIGH to LOW, so the movement is over else if (prev_motion_state == HIGH && motion_state == LOW) { Serial.println("Motion stopped!"); // tell the Serial Monitor servo.write(0); beep(); // put extra actions for "area is clear" here } }

When someone arrives, the servo opens to 180 degrees and the buzzer gives two short beeps. When the area is clear, the door swings back to 0 degrees with two more beeps.

Code Explanation

Code Part What It Does
#include Loads the servo library made for the ESP32 Uno PWM hardware
MOTION_SENSOR_PIN 26 and SERVO_PIN 13 Name the GPIO numbers behind D2 and D9
servo.attach(SERVO_PIN) Starts the PWM signal for the servo on GPIO13
prev_motion_state and motion_state Hold the old and the new sensor reading
if / else if checks Run only when the reading changes, then print a line and call servo.write()

Because the sketch reacts only to a change, the servo moves once per event and stays still in between.

ESP32 Uno vs UNO R4 for This Project

Moving this build from the UNO R4 to the ESP32 Uno changes the library line and the pin numbers in code.

Item Arduino UNO R4 ESP32 Uno
Logic voltage 5V 3.3V
Sensor pin in code 2 26 (D2)
Servo pin in code 9 13 (D9)
Servo library Servo.h ESP32Servo.h
WiFi and Bluetooth WiFi model only WiFi plus Bluetooth Classic and BLE
Arduino IDE board Arduino UNO R4 WiFi ESP32 Dev Module

The same wiring works as-is, because the wires stay on D2, D9, 5V and GND. Only change the two pin numbers and the include line.

Go Wireless: Remote Servo Override

After this part, you have an idea for a phone control on top of the sensor.

The ESP32 Uno has WiFi and Bluetooth built in. Keep the PIR sensor as the automatic trigger, and add a slider or a rotator on your phone to open the gate by hand. This helps when a visitor stands too still for the sensor to see.

Try These Next

  • Hold the servo at 90 degrees for 5 seconds after the last motion, then close it.
  • Sweep the servo slowly with a for loop instead of one big jump.
  • Add an LED on another pin that lights while the servo is open.

Troubleshooting

Problem Possible Cause Solution
No COM port appears in Arduino IDE CH340 driver missing or a charge-only USB cable Install the CH340 driver and use a USB cable that carries data
Upload stops at "Failed to connect" or "Waiting for download" Board did not enter upload mode Hold the BOOT button while the upload starts, then release it
Error "Servo.h - No such file or directory" The sketch still uses the AVR servo library Install ESP32Servo and include ESP32Servo.h
Servo never moves Signal wire on the wrong pin, or no 5V on the red wire Put the signal on D9 (GPIO13) and check 5V and GND
Servo buzzes or the board restarts when it moves USB port cannot give enough current Feed the servo from a separate 5V supply and join its GND with the board GND
Sensor reacts with nobody in front The PIR is still warming up, or a heat source is nearby Wait one minute after power-up and aim it away from heaters and sunny windows
Servo moves late or stays open long Time delay screw turned up Turn the time delay screw fully anti-clockwise
Messages appear but look like random symbols Serial Monitor baud does not match Set the Serial Monitor to 9600 baud

FAQ

How far away can the HC-SR501 notice a person?

Up to about 7 meters with the range screw turned fully clockwise. The view angle is about 110 degrees. Turn the screw the other way to shrink the reach to about 3 meters.

Do I need a resistor between the PIR OUT pin and D2?

No. The OUT pin gives about 3.3V when HIGH, which is a safe level for the ESP32 Uno input. You can wire it straight to D2 (GPIO26).

Can the 5V header pin power both the servo and the sensor?

Yes, for one small servo like the SG90. The 5V pin takes its power from USB. A bigger servo or two servos need an external 5V supply with a shared GND.

Will my old UNO R4 sketch run on the ESP32 Uno without changes?

Not quite. Change Servo.h to ESP32Servo.h and use the GPIO numbers 26 and 13 instead of 2 and 9. The rest of the logic stays the same.

Can I plug Uno shields into the ESP32 Uno for this build?

Many shields fit the headers, but the board runs at 3.3V logic. Check that the shield does not push a 5V signal into a board pin. Also note that A4 and A5 are not I2C on this board.

Which Arduino IDE setting do I use to upload to the ESP32 Uno?

Install the "esp32 by Espressif Systems" core, then pick ESP32 Dev Module and the CH340 COM port. The board uses a CH340 USB chip, so Windows may need its driver first.

How do I change how far the servo turns?

Edit the numbers inside servo.write(). For example, write servo.write(120) to open wider. Keep the value between 0 and 180.

Can I add a second servo that moves at the same time?

Yes. Create a second Servo object, attach it to another PWM pin such as D3 (GPIO25), and call write() on both in the same if block.

What if my project needs more pins than the Uno headers give?

The ESP32 Uno has a few extra holes near the power header: GPIO32 and GPIO33 (I/O, PWM, analog on ADC1, so they also work while WiFi is on) and GPIO15 (I/O, PWM, analog on ADC2). Solder pin headers to them and write the GPIO number in code. For this build, GPIO32 or GPIO33 is a good place for a second PIR sensor or another servo. Two warnings: GPIO15 and GPIO0 (the IO0 pin at the unused Uno NC spot) are boot strapping pins, and a wrong connection can stop the board from booting or uploading, so use GPIO32/33 first. Never use the six holes under the digital header (SD0 to SD3, CMD, CLK = GPIO6 to GPIO11). They connect to the flash chip, and using them crashes the board.

Can I get a phone alert when the sensor sees someone?

Yes. The ESP32 Uno has WiFi and Bluetooth, so you can send the motion state to a web page or a phone app. Start with one of the links in the Go Wireless section.

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!