Arduino Servo Motor Control — Wiring, Code & Angles Explained
A servo motor is a motor that moves to a specific angle on command. Unlike DC motors that spin continuously, servos rotate to 0°, 90°, 180° — or any position in between. The SG90 is the standard starter servo; the MG996R is the metal-gear version for heavier loads.
Time to complete: 10 minutes
Skill level: Beginner
How Servos Work
Servos use PWM (Pulse Width Modulation) to set position:
- 1 ms pulse → 0° (full counterclockwise)
- 1.5 ms pulse → 90° (center)
- 2 ms pulse → 180° (full clockwise)
The Arduino Servo library handles all the PWM timing. You just call servo.write(angle) with a value from 0 to 180.
SG90 vs MG996R Comparison
| Specification | SG90 | MG996R |
|---|---|---|
| Type | Plastic gear | Metal gear |
| Torque | 1.8 kg·cm | 9.4 kg·cm |
| Speed | 0.12 sec/60° | 0.15 sec/60° |
| Operating voltage | 4.8–6V | 4.8–7.2V |
| Current (no load) | 100 mA | 150 mA |
| Current (stall) | 360 mA | 2,500 mA |
| Weight | 9 g | 55 g |
| Size | 22 × 12 × 29 mm | 40 × 20 × 43 mm |
| Price | ~$1 | ~$4 |
Choose SG90 for: small robots, 3D printer parts, RC planes, lightweight arms
Choose MG996R for: robot arms, pan/tilt camera mounts, heavy steering applications
Servo Pinout (Universal)
Servo connectors have 3 wires. Color varies by brand:
| Signal | JR/Futaba color | HiTec color |
|---|---|---|
| Ground | Black or Brown | Black |
| Power (VCC) | Red | Red |
| Signal (PWM) | Orange or Yellow | White |
Wiring — Arduino Uno/Nano
For SG90 (low current, fine from Arduino 5V pin):
| Servo Wire | Arduino |
|---|---|
| Brown/Black (GND) | GND |
| Red (VCC) | 5V |
| Orange/Yellow (Signal) | Digital pin 9 |
For MG996R (high current — use external power):
| Servo Wire | Connection |
|---|---|
| Brown/Black (GND) | GND (Arduino GND AND external supply GND — share ground) |
| Red (VCC) | External 5V supply (1A+), NOT Arduino 5V pin |
| Orange/Yellow (Signal) | Arduino digital pin 9 |
The MG996R can draw up to 2.5A at stall — far more than an Arduino's 5V pin can provide (500 mA from USB). Using the Arduino's 5V for MG996R risks damaging the Arduino.
Install the Servo Library
The Servo library is included with Arduino IDE. No installation needed.
In Arduino IDE, just add #include <Servo.h> at the top of your sketch.
Code — Set a Specific Angle
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9); // Signal wire connected to digital pin 9
myServo.write(0); // Move to 0°
delay(1000);
myServo.write(90); // Move to 90° (center)
delay(1000);
myServo.write(180); // Move to 180°
delay(1000);
myServo.write(90); // Return to center
}
void loop() {
// Nothing — servo holds position
}
Code — Sweep (Back and Forth)
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9);
}
void loop() {
// Sweep from 0° to 180°
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle);
delay(15); // 15 ms per degree = ~2.7 sec for full sweep
}
// Sweep from 180° back to 0°
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
delay(15);
}
}
Code — Control with Potentiometer
Turn a potentiometer to control servo angle in real time:
#include <Servo.h>
Servo myServo;
const int POT_PIN = A0;
void setup() {
myServo.attach(9);
Serial.begin(9600);
}
void loop() {
int potValue = analogRead(POT_PIN); // 0–1023
int angle = map(potValue, 0, 1023, 0, 180); // Map to 0–180°
myServo.write(angle);
Serial.print("Pot: ");
Serial.print(potValue);
Serial.print(" Angle: ");
Serial.println(angle);
delay(15);
}
map() converts the potentiometer range (0–1023) to servo angle range (0–180°). This is the most common servo control pattern in robotics.
Code — Control with Serial Commands
Type angles into Serial Monitor to position the servo:
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9);
myServo.write(90); // Start at center
Serial.begin(9600);
Serial.println("Enter angle (0-180):");
}
void loop() {
if (Serial.available() > 0) {
int angle = Serial.parseInt();
if (angle >= 0 && angle <= 180) {
myServo.write(angle);
Serial.print("Moved to: ");
Serial.print(angle);
Serial.println("°");
} else {
Serial.println("Invalid angle. Enter 0-180.");
}
// Clear remaining characters in buffer
while (Serial.available()) Serial.read();
}
}
Project — Pan/Tilt Camera Mount
Control two servos for horizontal (pan) and vertical (tilt) camera movement:
#include <Servo.h>
Servo panServo; // Horizontal rotation
Servo tiltServo; // Vertical rotation
const int PAN_PIN = 9;
const int TILT_PIN = 10;
int panAngle = 90;
int tiltAngle = 90;
void setup() {
panServo.attach(PAN_PIN);
tiltServo.attach(TILT_PIN);
panServo.write(panAngle);
tiltServo.write(tiltAngle);
Serial.begin(9600);
Serial.println("Commands: W/S = tilt up/down, A/D = pan left/right");
}
void loop() {
if (Serial.available() > 0) {
char cmd = Serial.read();
switch (cmd) {
case 'a': panAngle = max(0, panAngle - 5); break; // Pan left
case 'd': panAngle = min(180, panAngle + 5); break; // Pan right
case 'w': tiltAngle = min(180, tiltAngle + 5); break; // Tilt up
case 's': tiltAngle = max(0, tiltAngle - 5); break; // Tilt down
}
panServo.write(panAngle);
tiltServo.write(tiltAngle);
Serial.print("Pan: ");
Serial.print(panAngle);
Serial.print(" Tilt: ");
Serial.println(tiltAngle);
}
}
Connect both servos to GND and 5V (external supply for MG996R). Pan servo signal to pin 9, tilt servo signal to pin 10.
Simulate on Wokwi
Wokwi supports servo motors. The servo shows its current angle in real time:
- Go to wokwi.com → New Project → Arduino Uno
- Add a Servo component
- Connect signal to pin 9, VCC to 5V, GND to GND
- Paste the sweep code and click Play — watch the servo rotate
See the Wokwi guide for setup instructions.
Troubleshooting
Servo jitters at target angle:
- Add a 100 µF capacitor between 5V and GND near the servo
- Underpowered: use external power supply instead of Arduino 5V
- Other PWM devices on the same board can interfere
Servo moves to position then slowly drifts:
- Usually a cheap servo with worn internal potentiometer
- Try
myServo.detach()after reaching position — releases PWM signal and stops fighting the position
Servo doesn't reach full 0° or 180°:
- Some servos' range is 0–170° or 10–180°. Adjust the
map()output range - Use
myServo.writeMicroseconds(544)for true 0° andmyServo.writeMicroseconds(2400)for true 180°
Servo buzzes loudly and draws high current:
- Mechanical obstruction — don't force past mechanical limits
- Voltage too low — servo stalls trying to reach position
Multiple servos stutter when one moves:
- Power issue. Connect all servos to an external 5V supply. Share the GND with Arduino GND.
Frequently Asked Questions (FAQ)
What's the difference between a servo and a DC motor? A DC motor spins continuously at a set speed. A servo moves to a specific angle and holds that position. Servos have built-in position feedback (internal potentiometer) and control electronics.
Can Arduino control a servo without the Servo library? Yes, using analogWrite() on a PWM pin with the correct duty cycle. But the Servo library makes it trivial — use it.
How many servos can one Arduino Uno control? Up to 12 servos (pins that support Servo.attach()). Power is the limiting factor — use an external supply for more than 2–3 servos.
Can I control a 360° continuous rotation servo? Yes. Use the same Servo library. write(90) = stop, write(0) = full speed one direction, write(180) = full speed other direction.
What voltage does the SG90 servo need? 4.8V to 6V. At 5V it works fine from Arduino's 5V pin for low-torque applications. For heavy loads, use a dedicated 5V 2A power supply.
How do I make the servo move smoothly without jerking? Use small increments with delays — like the sweep code example. Alternatively, use easing functions or the SlowServo library for acceleration/deceleration curves.
Related Guides
- PIR Motion Sensor — Trigger servo on motion detection
- HC-SR04 Ultrasonic Sensor — Distance-based servo control
- Wokwi Simulator Guide — Test servo projects online
- Arduino Nano vs Uno — Board choice for robotics projects