Home · ← Blog posts

Robotics

What Is a Servo Motor and How Does It Work? Arduino Wiring, Code and Angle Control

Probot Studio

What we'll do

  1. Look inside a servo and see how it holds an angle.
  2. Set the angle yourself with pulse width in a live sandbox.
  3. Wire a servo to an Arduino and write a sweep sketch and a potentiometer sketch.
  4. Cover 360 degree servos, servo vs stepper vs DC motor, and the power mistakes that reset boards.

Why it's useful: for a robot arm, a flap that opens or a gripper, a servo is the shortest path: one signal wire, one line of code, the angle you asked for.

On the left the servo signal changes between 1 ms, 1.5 ms and 2 ms pulses; on the right the servo, seen from above, turns its horn to 0, 90 and 180 degrees to match

What is a servo motor used for?

A servo motor turns to the angle you give it and stays there. Hobby servos like the SG90 usually cover about half a turn and are controlled through a single signal wire.

How does a servo motor work?

Inside a servo as a flow chart: the signal tells the control board the target angle, the board compares it with the angle measured by the potentiometer and runs the DC motor, gears trade speed for torque, the output shaft turns, and the potentiometer reports the new angle

Inside a servo there is a small DC motor, a gear train, a potentiometer and a control board. The board compares the angle you asked for with the angle the potentiometer measures, and runs the motor until the gap is gone.

How do you set a servo's angle?

Pulse width sets the angle: the Arduino sends a short 5 V pulse every 20 ms, and the servo only looks at how long that pulse lasts. Per the SG90 datasheet, 1.5 ms is the middle, about 1 ms is one end and about 2 ms is the other.

The Arduino Servo library maps angles onto a wider range by default:

Command Pulse it sends
servo.write(0) 544 µs
servo.write(90) 1472 µs
servo.write(180) 2400 µs
servo.writeMicroseconds(1500) 1500 µs

That range is wider than the standard 1-2 ms, so some servos hit their end stop at write(0) or write(180) and buzz. The Arduino docs warn that this is a high current state. The fix is below: find your servo's real end points.

Try it yourself

Drag the slider: stay between 1000 and 2000 µs first, then push to the ends. Then switch to 360° continuous servo; the same signal now means speed and direction.

This is a sandbox where you change the pulse width with a slider and see the 20 ms signal, the servo horn angle and the matching Arduino line. It needs JavaScript; if it did not load, the table and the picture above show the same relationship.

How do you connect a servo to an Arduino?

Wiring diagram: the servo brown wire goes to the breadboard minus rail, red to the plus rail, and the orange signal wire to Uno pin D9; the potentiometer outer legs go to the plus and minus rails and the middle leg to A0; the Uno 5V pin goes to the plus rail and GND to the minus rail

A servo has three wires: ground, power and signal. The signal wire goes to a digital pin; we use D9 in the examples.

Servo wire Uno pin
Brown or black GND
Red 5V (for one small servo)
Orange, yellow or white D9

The servo and the potentiometer share the single 5V pin, so we use the breadboard + and - rails (how to use a breadboard). New to Arduino? Start with what is Arduino?

Why does my servo reset the Arduino?

External power wiring: the plus of a 5-6 V supply goes to the servo red wire and the minus to the brown wire; Uno D9 goes to the signal wire and Uno GND also connects to the supply minus. Note: a stalled MG996R can draw 2.5 A, and the Uno USB fuse trips at 500 mA

A loaded servo can draw more current than the Uno can supply: the voltage sags, the Uno resets and the servo jitters. One unloaded SG90 can run from the Uno; the Arduino docs suggest a separate supply for more than one or two servos.

Arduino servo code

1. Sweep from 0 to 180 and back

#include <Servo.h>

Servo servo;              // the servo object

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

void loop() {
  for (int angle = 0; angle <= 180; angle++) {   // 0 to 180
    servo.write(angle);
    delay(15);            // 15 ms per degree: a bigger number = slower sweep
  }
  for (int angle = 180; angle >= 0; angle--) {   // and back
    servo.write(angle);
    delay(15);
  }
}

One direction takes about 2.7 seconds (181 steps × 15 ms).

Controlling servo speed: servo.write() on its own moves at full speed. To slow it down, change the angle in small steps with a delay in between, as above.

2. Control a servo with a potentiometer

#include <Servo.h>

Servo servo;

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

void loop() {
  int reading = analogRead(A0);          // potentiometer: 0-1023
  int angle = map(reading, 0, 1023, 0, 180);  // scale to 0-180 degrees
  servo.write(angle);
  delay(15);                             // give the servo time to get there
}

Outer legs to 5V and GND, middle leg to A0. Turn the knob and the servo follows it.

3. Find your servo's real end points

#include <Servo.h>

Servo servo;

void setup() {
  Serial.begin(9600);
  servo.attach(9, 500, 2500);          // widen the limits to 500-2500 µs
  servo.writeMicroseconds(1500);       // start in the middle
  Serial.println("Type a number from 500 to 2500 in the Serial Monitor");
}

void loop() {
  if (Serial.available()) {
    int us = Serial.parseInt();        // read the number you typed
    if (us >= 500 && us <= 2500) {
      servo.writeMicroseconds(us);
      Serial.println(us);
    }
  }
}

Type 1000 in the Serial Monitor, then go down 50 at a time; just inside the point where the servo stops moving or starts to buzz is its real end. Go up from 2000 for the other end. Then use servo.attach(9, min, max): write(0) and write(180) now land exactly on those ends.

What is a 360 degree (continuous rotation) servo?

A continuous rotation servo reads the same signal as speed and direction instead of angle: around 1.5 ms it stops, a shorter pulse spins it one way, a longer pulse the other way.

Servo vs stepper vs DC motor

DC motor Stepper motor Servo motor
What it does Spins continuously Turns in steps Goes to the angle you set
Knows its position? No (needs an encoder) Counts steps, does not measure Measures it with its potentiometer
Rotation Unlimited Unlimited Usually about half a turn
How you drive it Driver board (L298N) Driver board (ULN2003) A signal pin, no driver needed
Typical job Wheels, fans 3D printers, CNC Arms, flaps, steering

A "regular motor" usually means a DC motor: it spins but has no idea where it stopped. More on steppers in how stepper motors work.

Is a servo motor AC or DC? Hobby servos run on DC, around 5 V. Factory CNC machines and industrial robots also use AC servo motors that run from mains power; do not wire those yourself, that is a job for a licensed electrician.

SG90 or MG996R?

Per the datasheet SG90 MG996R
Weight 9 g 55 g
Stall torque 1.8 kgf·cm (4.8 V) 9.4 kgf·cm (4.8 V), 11 kgf·cm (6 V)
Speed 0.1 s / 60° 0.17 s / 60° (4.8 V)
Operating voltage 4.8 V (~5 V) 4.8-7.2 V
Rotation about 180° about 120°

kgf·cm: 1.8 kgf·cm means holding back about 1.8 kg at 1 cm from the shaft; on a 3 cm horn, a third of that. This is the stall value, so do not run a servo at that load all the time. Different copies of the SG90 sheet list 1.2 to 1.8 kgf·cm.

Common mistakes

Symptom Cause Fix
Servo jitters, Uno resets Not enough power External 5-6 V supply, shared GND
Buzzes and gets warm at one end Pulse goes past the servo's end Find the ends, use attach(9, min, max)
Does not move at all Signal on another pin, or no shared GND Check the attach pin and GND
analogWrite stops working on D9 or D10 On the Uno the Servo library disables PWM on those two pins Move the LED to 3, 5, 6 or 11
360 servo will not stop Its stop point is not exactly 1500 µs Trim screw, or fine-tune with writeMicroseconds
Horn sits at the wrong angle Horn was pushed onto the spline off-center Send write(90) and refit the horn centered

Sources

Accessed: 17 October 2026