From the workshop: Arduino Uno R3 Development Board (ATmega328P) With USB Cable

View product
All articles
Robotics

🦾SG90 Servo Motor with Arduino: How Servos Work, Wiring, Code and a Pan-Tilt Project

What is inside a hobby servo, how a 50 Hz pulse sets its angle, SG90 vs MG996R, how to power servos without resetting your Arduino, and three experiments ending in a joystick pan-tilt head.

TThinking Robot Team 12 min read
SG90 servo motor connected to an Arduino with a 50 Hz pulse diagram and a two-servo pan-tilt head
In this article (16)

A DC motor spins. A stepper motor steps. A servo motor goes to an angle you choose and stays there, even if something pushes against it. That is why servos move robot arms, steer RC cars, aim cameras and flap the wings of science-fair models.

The tiny blue SG90 is most students' first servo. This guide explains what is inside it, how a single Arduino pin tells it where to go, how to power it without resetting your board, and three experiments that end with a two-servo pan-tilt head you control with a joystick.

What is inside a hobby servo

Inside a servo: a control board drives a DC motor through a gear train to the output shaft; a potentiometer on the shaft feeds the actual angle back to the boardA servo is a small closed-loop system: motor, gears, and a potentiometer that reports the shaft angle.

Open up an SG90 and you will find four parts:

PartWhat it does
Small DC motorSpins fast but has very little twisting force
Gear trainSlows the motor down a lot and multiplies its torque
PotentiometerTurns with the output shaft, so its resistance tells the board the shaft angle
Control boardCompares the angle you asked for with the angle the pot reports, and drives the motor until they match

This is closed-loop control: push the horn away from its position and the pot reports the error, so the board pushes back. A plain DC motor has no idea where it is; a servo always does.

How the signal works: 50 Hz pulses

Three servo signals: about 0.5 ms pulse for 0 degrees, about 1.5 ms for 90 degrees and about 2.4 ms for 180 degrees, each repeated every 20 msThe pulse repeats every 20 ms. Only the width of the pulse matters.

A servo has three wires. On the SG90 they are brown (GND), red (+5 V) and orange (signal). The signal is a pulse that repeats every 20 ms, which is 50 times a second (50 Hz). The width of each pulse is the instruction:

Servo library callPulse widthDuty cycle at 50 HzTypical position
write(0)544 µs2.7 %One end
write(45)1,008 µs5.0 %
write(90)1,472 µs7.4 %Centre
write(135)1,936 µs9.7 %
write(180)2,400 µs12.0 %Other end

The Arduino Servo library maps 0°–180° onto 544 µs – 2,400 µs by default:

pulse (µs) = 544 + angle × (2400 − 544) ÷ 180 e.g. 45° → 544 + 45 × 1856 ÷ 180 = 1,008 µs

You will often read that servos use "1 ms to 2 ms, with 1.5 ms at the centre". That is the classic RC standard. Many hobby servos, including most SG90s, only move about 90° on 1–2 ms and need roughly 0.5–2.4 ms for their full travel. Every servo is slightly different, which is why Experiment 3 below finds the real limits of yours. Our servo pulse width calculator converts between angle, pulse width and duty cycle for any range.

SG90 vs MG90S vs MG996R

SG90MG90SMG996R
GearsPlasticMetalMetal
Weight≈ 9 g≈ 13 g≈ 55 g
Operating voltage4.8 V – 6 V4.8 V – 6 V4.8 V – 7.2 V
Stall torque (datasheet)≈ 1.8 kg·cm at 4.8 V≈ 1.8 kg·cm at 4.8 V, ≈ 2.2 at 6 V≈ 9.4 kg·cm at 4.8 V, ≈ 11 at 6 V
Speed (no load)≈ 0.1 s per 60°≈ 0.1 s per 60°≈ 0.17 s per 60° at 4.8 V
CurrentSmall idle current; a few hundred mA when moving or stalledSimilar to SG90Can exceed 2 A when stalled
Best forPan-tilt heads, flaps, light arm jointsSmall arms that get knocked aboutShoulder and base joints, larger robots

Figures are typical datasheet values and vary between manufacturers.

Stall torque is the most the servo can hold before it stops moving. "1.8 kg·cm" means it can hold 1.8 kg at 1 cm from the shaft, or 0.18 kg at 10 cm. Running near stall makes servos hot and noisy, so keep your load well below it.

A servo holding a 10 cm arm with a 50 g load at the tip and a 20 g arm: total torque 600 g·cm, which is one third of the SG90's stall torqueAdd up weight × distance for everything the servo has to hold, with the arm horizontal.

Powering servos safely

This is where most servo projects go wrong. When a servo starts moving, it draws a sudden burst of current. One small SG90 doing light work is usually fine from the Arduino's 5V pin while testing. Two or more servos, or any servo under load, are not. The 5V supply sags, the Arduino resets or behaves strangely, and the USB port can shut down.

Servo supplyVoltageGood forNotes
4 × AA NiMH rechargeable4.8 V2–4 small servosIdeal voltage for SG90s
5 V, 2 A (or bigger) adapter5 VBench projects, pan-tiltSimple and steady
2 × 18650 (7.4 V) + 5 V–6 V buck converter or UBEC5 V – 6 VMobile robotsCheck the converter's current rating
Uno 5V pin5 VOne unloaded SG90 for testing onlyAdding a 470 µF capacitor helps

Add a 470 µF – 1000 µF electrolytic capacitor (10 V or higher) across the servo supply, close to the servos, with the stripe (−) to GND. It supplies the short current bursts and stops jitter. For help choosing a battery pack, see our robot battery guide.

Experiment 1: the sweep

Wiring for the first experiments: SG90 signal on D9, potentiometer wiper on A0, both powered from the Uno's 5V and GND through breadboard railsOne SG90 on D9 and a 10 kΩ potentiometer on A0. Use the same wiring for Experiments 1, 2 and 3.

You need: Arduino Uno, one SG90 with a horn fitted, a 10 kΩ potentiometer, breadboard and jumper wires.

  1. Connect the servo: brown → GND, red → 5V, orange → D9.
  2. Upload the sketch. The Servo library comes with the Arduino IDE.
  3. Watch the horn sweep slowly from one end to the other and back.
cpp
#include <Servo.h>

Servo myServo;

void setup() {
  myServo.attach(9);            // signal wire on D9
}

void loop() {
  for (int angle = 0; angle <= 180; angle++) {
    myServo.write(angle);
    delay(15);                  // time for the servo to follow
  }
  for (int angle = 180; angle >= 0; angle--) {
    myServo.write(angle);
    delay(15);
  }
}

Try this: change delay(15) to delay(1). The code now asks for 180° in under 0.2 s, but an SG90 needs about 0.1 s for every 60°, so at least 0.3 s for 180°. It cannot keep up and turns back before reaching the ends.

Experiment 2: control the angle with a knob

Connect the potentiometer's outer pins to 5V and GND and its middle pin (wiper) to A0, as in the diagram.

cpp
#include <Servo.h>

Servo myServo;
const int POT = A0;

void setup() {
  myServo.attach(9);
  Serial.begin(9600);
}

void loop() {
  int raw = analogRead(POT);               // 0 ... 1023
  int angle = map(raw, 0, 1023, 0, 180);   // 0 ... 180 degrees
  myServo.write(angle);
  Serial.println(angle);
  delay(20);
}

Turn the knob and the servo follows (the Serial Monitor shows the angle). You have built a position-control system: the knob sets the target, the servo's internal feedback does the rest.

Experiment 3: find your servo's real limits

  1. Upload this sketch and open the Serial Monitor at 9600 baud.
  2. Type 1500 and press Enter. The servo should go to its centre.
  3. Try 1000, then 800, 700, 600... until the horn stops moving further. Do the same upwards from 2000.
  4. As soon as you hear the servo buzz without moving, it is pushing against its end stop. Back off by 50 µs and note that value.
cpp
#include <Servo.h>

Servo s;

void setup() {
  Serial.begin(9600);
  s.attach(9, 500, 2500);       // allow a wider range for testing
  s.writeMicroseconds(1500);
  Serial.println("Type a pulse width (500-2500) and press Enter");
}

void loop() {
  if (Serial.available()) {
    int us = Serial.parseInt();
    if (us >= 500 && us <= 2500) {
      s.writeMicroseconds(us);
      Serial.print("Pulse: ");
      Serial.print(us);
      Serial.println(" us");
    }
  }
}

Once you know your servo's limits, use them in your own projects with attach(pin, minUs, maxUs). Then write(0) and write(180) reach the true ends without straining the gears.

Project: a joystick-controlled pan-tilt head

Pan-tilt wiring: pan servo signal on D9, tilt servo signal on D10, both powered from a separate 5 V supply with a 470 µF capacitor; joystick on A0 and A1; all grounds joinedServos get power from the external 5 V supply. The Arduino only sends signals, and all grounds are joined.

A pan-tilt bracket holds two servos: the bottom one turns left and right (pan), the top one tilts up and down. Mount an HC-SR04 on it and your robot can look around without turning its body.

PartConnects to
Pan servo signal (orange)D9
Tilt servo signal (orange)D10
Both servo red wiresExternal 5 V supply +
Both servo brown wiresExternal supply − and Arduino GND
Joystick +5V / GNDArduino 5V / GND
Joystick VRx / VRyA0 / A1
cpp
#include <Servo.h>

Servo pan, tilt;
const int JOY_X = A0, JOY_Y = A1;
int panAngle = 90, tiltAngle = 90;

// Joystick reading (0-1023, about 512 at rest) -> step of -2 ... +2 degrees
int joyStep(int raw) {
  int offset = raw - 512;
  if (abs(offset) < 60) return 0;           // dead zone around the centre
  if (offset > 300) return 2;
  if (offset > 0) return 1;
  if (offset < -300) return -2;
  return -1;
}

void setup() {
  pan.attach(9);
  tilt.attach(10);
  pan.write(panAngle);
  tilt.write(tiltAngle);
}

void loop() {
  int dx = joyStep(analogRead(JOY_X));
  int dy = joyStep(analogRead(JOY_Y));
  panAngle = constrain(panAngle + dx, 0, 180);
  tiltAngle = constrain(tiltAngle + dy, 30, 150);  // keep clear of the bracket
  pan.write(panAngle);
  tilt.write(tiltAngle);
  delay(15);
}

Push the stick and the head moves; let go and it stays where it is. That is because the joystick changes the angle a little each loop instead of setting it directly. The tilt range is limited to 30°–150° so the top servo cannot crash into the bracket; adjust these numbers for your own mount. If an axis moves the wrong way, change + dx to - dx (or + dy to - dy).

Troubleshooting

ProblemLikely causeFix
Arduino resets when the servo movesServo powered from the Uno's 5VSeparate 5 V supply, common ground, 470 µF capacitor
Servo jitters or twitches at restWeak supply, noise, or loose GNDShorter wires, capacitor, solid ground connection
Servo does nothingNo common ground, or wrong pinJoin all grounds; check the signal pin number in attach()
Only moves about 90°Pulse range too narrow for this servoFind the limits (Experiment 3) and use attach(pin, min, max)
Motors on D9/D10 stop changing speedServo library uses Timer1 on the UnoMove motor PWM to pins 3, 5, 6 or 11

Where to go next

Frequently asked questions

Why does my Arduino reset when the servo moves?

The servo's starting current pulls the 5 V supply down, and the Arduino's microcontroller resets when its supply drops too low. Power the servos from a separate 5 V – 6 V supply, join the grounds, and add a 470 µF capacitor across the servo supply.

Can I connect an SG90 to a 9 V battery?

No. The SG90 is rated for about 4.8 V – 6 V, and a 9 V battery can damage it. A 9 V PP3 battery also cannot supply much current. Use 4 × AA NiMH cells, a 5 V adapter, or a Li-ion pack with a 5 V – 6 V regulator.

How many servos can an Arduino Uno control?

The Servo library can drive up to 12 servos on an Uno. In practice, power is the limit, not pins. For larger projects, such as a hexapod with 18 servos, use a 16-channel PCA9685 servo driver board and a supply rated for several amps.

What is a continuous rotation servo?

It is a servo without position feedback, so it spins like a geared motor. write(90) (roughly) stops it, while values towards 0 or 180 spin it faster in either direction. It is useful for small wheeled robots but cannot go to an angle.

Can I use a servo with an ESP32?

Yes. Use the ESP32Servo library, which works like the Arduino Servo library (see our Arduino vs ESP32 vs Pico comparison for other differences). The ESP32's 3.3 V signal is normally enough for an SG90, but the servo still needs its own 5 V supply and a common ground.

Try the calculators

T

Thinking Robot Team

Thinking Robot is a team of engineers and educators in Pune who design electronics and robotics kits and run hands-on workshops for students and schools. Spotted a mistake or have a question? Get in touch.

Filed under#Robotics#Arduino#Electronics#Tutorial

Keep learning

WhatsApp