5 SG90 Servo Projects That Move With Purpose
Build precision control projects: robot arm, pan-tilt camera, pet feeder, smart door lock, and line-following robot
The SG90 micro servo motor is one of the most useful precision actuators in maker projects. It rotates to a specific angle (typically 0-180°) based on a PWM signal from your Arduino. Unlike DC motors, you don't need motor drivers — servos work directly from Arduino pins. In this guide, we'll build five precision control projects that use servo motors to create purposeful, repeatable motion.
Topics covered: Servo library, PWM control, angle calibration, position holding, force measurement, pan-tilt mechanics, gripper design.
What You'll Need
- SG90 servo motor (×1-4 depending on project)
- Arduino Nano or Uno (×1)
- Jumper wires
- 5V power supply (servo can draw significant current)
- Potentiometer (for manual control projects)
- Push button (for trigger projects)
How the SG90 Servo Works
The SG90 uses PWM (pulse width modulation) to set position. A 50Hz signal (20ms period) with pulse widths between 1ms (0°) and 2ms (180°) controls the shaft position. The servo holds its position against resistance thanks to internal gears.
Arduino SG90 Servo
Pin 9 ────── Signal (yellow/orange)
5V ────── VCC (red)
GND ────── GND (brown)
Critical: Never drive the servo directly from the Arduino's 5V pin during continuous operation. Use a separate 5V 1A supply for any servo project.
// WF1 Run #040 - Basic Servo Sweep
#include <Servo.h>
#define SERVO_PIN 9
Servo myServo;
void setup() {
myServo.attach(SERVO_PIN);
myServo.write(0); // Start at 0 degrees
}
void loop() {
// Sweep from 0 to 180 degrees
for (int angle = 0; angle <= 180; angle += 1) {
myServo.write(angle);
delay(15); // Allow servo to reach position
}
delay(1000);
// Sweep back from 180 to 0 degrees
for (int angle = 180; angle >= 0; angle -= 1) {
myServo.write(angle);
delay(15);
}
delay(1000);
}
Project 1: Robot Arm Pick and Place
Goal: A 4-DOF (degree of freedom) robot arm that can pick up a small object from one location and place it in another.
Hardware
- 4× SG90 servo motors
- Arduino Mega (for enough PWM pins)
- 5V 3A power supply
- Acrylic or 3D printed arm parts
- Small gripper/clamp at end
Code
// WF1 Run #040 - Project 1: Robot Arm
#include <Servo.h>
#define BASE_SERVO 2
#define SHOULDER_SERVO 3
#define ELBOW_SERVO 4
#define GRIPPER_SERVO 5
#define GRIP_OPEN 0
#define GRIP_CLOSE 60
Servo base, shoulder, elbow, gripper;
void moveServo(Servo s, int targetAngle, int stepDelay = 20) {
int current = s.read();
int step = (targetAngle > current) ? 1 : -1;
while (current != targetAngle) {
current += step;
s.write(current);
delay(stepDelay);
}
}
void setup() {
base.attach(BASE_SERVO);
shoulder.attach(SHOULDER_SERVO);
elbow.attach(ELBOW_SERVO);
gripper.attach(GRIPPER_SERVO);
gripper.write(GRIP_CLOSE); // Start gripper closed
delay(500);
// Home position
moveServo(base, 90);
moveServo(shoulder, 90);
moveServo(elbow, 90);
}
void loop() {
// Pick position
moveServo(base, 30);
moveServo(shoulder, 120);
moveServo(elbow, 60);
gripper.write(GRIP_OPEN);
delay(500);
// Descend and grip
moveServo(elbow, 30);
gripper.write(GRIP_CLOSE);
delay(500);
// Lift and rotate
moveServo(elbow, 60);
moveServo(base, 150);
moveServo(shoulder, 90);
// Release
gripper.write(GRIP_OPEN);
delay(1000);
}
Project 2: Pan-Tilt Camera Mount
Goal: A camera mount that automatically tracks a moving person using a PIR sensor, or can be manually aimed with a joystick.
Hardware
- 2× SG90 servo motors (pan + tilt)
- Arduino Nano
- HC-SR501 PIR sensor (for motion tracking)
- Joystick module (for manual control)
- ESP32-CAM or webcam
Code
// WF1 Run #040 - Project 2: Pan-Tilt Camera
#include <Servo.h>
#define PAN_SERVO 9
#define TILT_SERVO 10
#define PIR_PIN 7
#define JOYSTICK_X A0
#define JOYSTICK_Y A1
#define PAN_MIN 0
#define PAN_MAX 180
#define TILT_MIN 30
#define TILT_MAX 120
Servo panServo;
Servo tiltServo;
int panAngle = 90;
int tiltAngle = 60;
bool autoMode = true;
void setup() {
panServo.attach(PAN_SERVO);
tiltServo.attach(TILT_SERVO);
panServo.write(panAngle);
tiltServo.write(tiltAngle);
pinMode(PIR_PIN, INPUT);
Serial.begin(115200);
}
void loop() {
int xRead = analogRead(JOYSTICK_X);
int yRead = analogRead(JOYSTICK_Y);
// Joystick threshold to avoid drift
if (xRead < 400) {
panAngle = max(PAN_MIN, panAngle - 2);
autoMode = false;
} else if (xRead > 600) {
panAngle = min(PAN_MAX, panAngle + 2);
autoMode = false;
}
if (yRead < 400) {
tiltAngle = max(TILT_MIN, tiltAngle - 2);
autoMode = false;
} else if (yRead > 600) {
tiltAngle = min(TILT_MAX, tiltAngle + 2);
autoMode = false;
}
panServo.write(panAngle);
tiltServo.write(tiltAngle);
// If no manual input for 5 seconds, return to auto mode
if (!autoMode) {
delay(5000);
autoMode = true;
}
delay(50);
}
Project 3: Automatic Pet Feeder
Goal: A timed pet feeder that dispenses a portion of food at set times each day, with a manual feed button.
Hardware
- SG90 servo motor
- Arduino Nano
- DS3231 RTC module
- Push button
- LED indicator
- Food hopper (3D printed or repurposed container)
Code
// WF1 Run #040 - Project 3: Automatic Pet Feeder
#include <Servo.h>
#include <Wire.h>
#include <RTClib.h>
#define SERVO_PIN 9
#define BUTTON_PIN 7
#define FEED_LED 8
#define FEED_HOUR_1 8 // 8:00 AM
#define FEED_HOUR_2 18 // 6:00 PM
#define SERVO_OPEN 90
#define SERVO_CLOSE 0
RTC_DS3231 rtc;
Servo feederServo;
bool alreadyFed1 = false;
bool alreadyFed2 = false;
void dispenseFood() {
Serial.println("Dispensing food...");
feederServo.write(SERVO_OPEN);
delay(3000); // Open for 3 seconds
feederServo.write(SERVO_CLOSE);
delay(500);
}
void setup() {
Serial.begin(115200);
feederServo.attach(SERVO_PIN);
feederServo.write(SERVO_CLOSE);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(FEED_LED, OUTPUT);
if (!rtc.begin()) {
Serial.println("RTC not found");
}
// Set time: rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
void loop() {
DateTime now = rtc.now();
// Timed feeding
if (now.hour() == FEED_HOUR_1 && !alreadyFed1) {
dispenseFood();
alreadyFed1 = true;
} else if (now.hour() != FEED_HOUR_1) {
alreadyFed1 = false;
}
if (now.hour() == FEED_HOUR_2 && !alreadyFed2) {
dispenseFood();
alreadyFed2 = true;
} else if (now.hour() != FEED_HOUR_2) {
alreadyFed2 = false;
}
// Manual button feed
if (digitalRead(BUTTON_PIN) == LOW) {
dispenseFood();
digitalWrite(FEED_LED, HIGH);
delay(500);
digitalWrite(FEED_LED, LOW);
}
delay(1000);
}
Project 4: Smart Door Lock
Goal: A door lock that can be triggered by a keypad code or RFID card, with servo-driven deadbolt and status LED.
Hardware
- SG90 servo motor (high torque version recommended)
- Arduino Nano
- 4×4 keypad
- RFID RC522 module (optional)
- Red/Green LED indicators
- 3D printed lock mechanism
Code
// WF1 Run #040 - Project 4: Smart Door Lock
#include <Servo.h>
#include <Keypad.h>
#define SERVO_PIN 9
#define GREEN_LED 10
#define RED_LED 11
#define LOCKED_ANGLE 0
#define UNLOCKED_ANGLE 90
#define CODE_LENGTH 4
const char correctCode[] = {'1', '2', '3', '4'};
Servo lockServo;
char enteredCode[CODE_LENGTH];
int codeIndex = 0;
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {2, 3, 4, 5};
byte colPins[COLS] = {6, 7, 8, 9};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void unlockDoor() {
lockServo.write(UNLOCKED_ANGLE);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW);
Serial.println("UNLOCKED");
delay(5000); // Auto-lock after 5 seconds
lockServo.write(LOCKED_ANGLE);
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
Serial.println("LOCKED");
}
void setup() {
Serial.begin(115200);
lockServo.attach(SERVO_PIN);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
lockServo.write(LOCKED_ANGLE);
digitalWrite(RED_LED, HIGH);
}
void loop() {
char key = keypad.getKey();
if (key) {
Serial.print("Key: ");
Serial.println(key);
if (key == '#') {
// Check code
bool correct = true;
for (int i = 0; i < CODE_LENGTH; i++) {
if (enteredCode[i] != correctCode[i]) {
correct = false;
break;
}
}
if (correct) {
unlockDoor();
} else {
Serial.println("WRONG CODE");
digitalWrite(RED_LED, HIGH);
delay(500);
}
codeIndex = 0;
} else if (key == '*') {
// Clear
codeIndex = 0;
Serial.println("Cleared");
} else {
if (codeIndex < CODE_LENGTH) {
enteredCode[codeIndex++] = key;
}
}
}
}
Project 5: Line-Following Robot Steering
Goal: A small robot car that steers using a servo motor to follow a black line on a white surface.
Hardware
- SG90 servo motor (for steering)
- Arduino Nano
- 2× IR infrared line sensors
- 2× DC motors (for rear wheels)
- Motor driver module (L298N)
- Robot car chassis
Code
// WF1 Run #040 - Project 5: Line-Following Robot
#include <Servo.h>
#define STEERING_SERVO 9
#define LEFT_MOTOR 10
#define RIGHT_MOTOR 11
#define IR_LEFT A0
#define IR_RIGHT A1
#define LINE_BLACK LOW // IR sensor reads LOW on black line
#define STEER_LEFT 30
#define STEER_CENTER 90
#define STEER_RIGHT 150
#define MOTOR_SPEED 150
Servo steeringServo;
void setup() {
steeringServo.attach(STEERING_SERVO);
steeringServo.write(STEER_CENTER);
pinMode(LEFT_MOTOR, OUTPUT);
pinMode(RIGHT_MOTOR, OUTPUT);
pinMode(IR_LEFT, INPUT);
pinMode(IR_RIGHT, INPUT);
Serial.begin(115200);
}
void loop() {
int leftIR = digitalRead(IR_LEFT);
int rightIR = digitalRead(IR_RIGHT);
Serial.print("L:");
Serial.print(leftIR);
Serial.print(" R:");
Serial.println(rightIR);
if (leftIR == LINE_BLACK && rightIR == LINE_BLACK) {
// On the line — go straight
steeringServo.write(STEER_CENTER);
analogWrite(LEFT_MOTOR, MOTOR_SPEED);
analogWrite(RIGHT_MOTOR, MOTOR_SPEED);
} else if (leftIR == LINE_BLACK) {
// Line is to the left — steer left
steeringServo.write(STEER_LEFT);
analogWrite(LEFT_MOTOR, MOTOR_SPEED / 2);
analogWrite(RIGHT_MOTOR, MOTOR_SPEED);
} else if (rightIR == LINE_BLACK) {
// Line is to the right — steer right
steeringServo.write(STEER_RIGHT);
analogWrite(LEFT_MOTOR, MOTOR_SPEED);
analogWrite(RIGHT_MOTOR, MOTOR_SPEED / 2);
} else {
// Lost the line — stop and search
analogWrite(LEFT_MOTOR, 0);
analogWrite(RIGHT_MOTOR, 0);
}
delay(10);
}
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Servo jitters or oscillates | Insufficient power | Use a dedicated 5V supply with at least 1A current |
| Servo won't rotate fully | Mechanical obstruction | Check for cable interference or gear binding |
| Servo gets hot | Continuous strain | Don't hold max-load position for long periods; use torque-appropriate servo |
| Servo makes grinding noise on startup | Initial position mismatch | Move to 90° before attaching horn |
| IR sensor gives wrong readings | Ambient IR interference | Shield sensors from direct sunlight |
Start Here
Affiliate disclosure: As an Amazon Associate, I earn from qualifying purchases.
The right parts make the difference:
SG90 Micro Servo Motor — Affordable and reliable for most projects.
Arduino Mega 2560 — Enough PWM pins for multi-servo projects.
SG90 High Torque Version — Metal gears and more torque for heavier loads.
4x4 Matrix Keypad — For door lock and menu projects.
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
Tags: Arduino SG90 Servo Motor Control Robotics Arduino Projects Automation






Top comments (0)