Servo motor

How an SG90 servo knows its angle: a pulse every 20 ms, three wires, its own power supply, the Arduino Servo library and how long it takes to turn.

PWM Servo
Three blue servo motors with white arms and three-wire cables, with arms of different shapes and tiny screws next to them

What is a servo motor?

An ordinary motor spins as long as it has current. A servo motor turns to the angle we give it and stays there. The program tells it turn to 90°, and the servo turns and holds that position, even when something pushes it. The most common servos turn from 0° to 180°, half a circle.

You find servos in model planes and boats, where they move the rudders, in robot arms and in toys that wave. In our pinball machine a servo raises the post between the flippers to save the ball.

An SG90 servo from the side: a blue case with two mounting tabs, the shaft on top with a white arm, and three wires on the side, brown, red and orange, ending in a plug. Next to the plug: GND, 5V and D9

At the workshops we use the small SG90 servo. It weighs about 9 grams and has three wires:

  • brown is GND (minus),
  • red is the supply of about 5 V (plus),
  • orange is the signal, which tells the servo which angle to turn to.

Some servos have wires of other colours: black for GND, red for plus and white or yellow for the signal.

Arms of different shapes (horns) push onto the shaft.

What is inside a servo?

A servo cut through from the side. Numbers: 1 the motor standing under the gears, with its own small gear on top of its shaft, 2 a row of gears seen edge-on, each a large and a small wheel on the same upright axle, each driving the next, 3 the shaft coming out at the top, 4 the potentiometer under the large gear, on the same shaft, 5 the green circuit board at the bottom, with the three wires leaving it
  1. The motor: small and fast, but weak.
  2. The gears lower the speed and raise the force. The motor turns many times while the shaft turns once.
  3. The shaft comes out of the case. The arm goes on it.
  4. The potentiometer is joined to the shaft and turns with it, so its resistance tells which angle the shaft is at.
  5. The circuit compares the angle the program asks for with the angle the potentiometer shows. If they differ, it turns the motor until they are the same. If someone moves the arm, the circuit notices and moves it back.

It is like reaching for a cup: your eyes keep telling you how far your hand is, so your hand slows down as it gets close and stops right at the cup.

Don't turn a servo by hand

The gears slow the motor down many times, so the motor turns many times while the arm turns once. When you turn the arm by hand, you drive the whole row of gears backwards, and the small motor at the end of it has to spin much faster than the arm. That takes a lot of force, and the tiny teeth of the plastic gears have to carry it. A tooth cracks or breaks off, and afterwards the servo skips, sticks or doesn't turn at all.

If the servo is switched on, it is even worse: the circuit notices the arm has moved and pushes it back with all its strength. You and the motor are fighting, and the motor draws its highest current and gets hot. So set the arm's position with the program. If you really must move it by hand, for example to push an arm on, switch the power off first and turn it slowly, without force.

How does the servo know which angle we want?

Every 20 milliseconds the orange wire gets a short pulse: the voltage jumps to 5 V and back to 0 V. The angle depends on how long the pulse lasts:

Three graphs of the voltage on the signal wire over 25 ms, each with two pulses 20 ms apart. Top: the pulse lasts 1 ms and the arm points to 0 degrees; middle: 1.5 ms and 90 degrees; bottom: 2 ms and 180 degrees. Dashed lines through all three graphs show where each of the three pulses ends

  • a 1 ms pulse means 0°,
  • a 1.5 ms pulse means 90°,
  • a 2 ms pulse means 180°.

A longer pulse means a bigger angle. The exact limits differ a little from servo to servo, but the middle is almost always 1.5 ms.

Positional and continuous servos

Servos come in two kinds:

  • A positional servo turns to the angle it is given and stops there, usually somewhere from 0° to 180°. The SG90 is one, and the rest of this page is about it. The pulse tells it where to stop.
  • A continuous rotation servo, for example the FS90R, spins round and round like an ordinary motor. The pulse tells it which way and how fast to spin: about 1.5 ms means stop, 1 ms full speed one way, and 2 ms full speed the other way. Pulses in between make it turn more slowly.

A continuous servo has no potentiometer following the shaft, and no end stop that holds the shaft at the end of its travel. So it doesn’t know which angle it is at and can’t stop at a given angle, but it can spin without end. From the outside both kinds look almost the same, so check the kind on the label or in the product description.

A positional servo moves an arm, a rudder or the post in the pinball machine. A continuous one drives the wheels of a small robot, which then needs no separate motor driver.

Where we use it

  • At the micro:bit workshop we connect a servo to the Maqueen robot. In MakeCode the servo write pin block, in the Pins category, turns it.
  • At the Arduino workshop SG90 servos are part of the pinball machine: they raise the post, and they can move other mechanisms too.

The servo at the Arduino workshop

From here on, this page is for the Arduino workshop.

Power

While it turns, an SG90 uses a few hundred mA, and when it starts or gets stuck, up to 0.7 A. That is far more than a pin may give, and more than USB gives without trouble. When the servo starts, the voltage on the Arduino drops and the Arduino may reset itself. So the servo has its own supply:

Schematic: the servo's orange signal wire on the Arduino's D9. The red wire to the plus of a separate 5 V supply, the brown one to its minus. A 470 µF electrolytic capacitor is across the supply. The supply's minus is joined to the Arduino's GND

  • The signal comes from pin D9, and the servo takes its current from a separate 5 V supply, for example an adapter.
  • A 470 µF capacitor next to the servo gives current at the moment the servo starts, so the voltage doesn’t drop. In the pinball machine, with three servos, we use 1000 µF.
  • The supply’s GND and the Arduino’s GND must be joined. The servo measures the pulse against its own GND, so without a common ground it can’t tell when the pulse starts (misconception 8).

The Servo library

We don’t have to send the pulses ourselves. The Servo library, which comes with the Arduino IDE, does it:

// C++
#include <Servo.h>                     // the Servo library, comes with the Arduino IDE

Servo servo;                           // our servo
const int servoPin = 9;                // the orange wire

void setup() {
  servo.attach(servoPin);              // from now on D9 sends a pulse every 20 ms
}

void loop() {
  servo.write(0);                      // quickly to 0°
  delay(1000);
  servo.write(90);                     // quickly to 90°
  delay(1000);
  servo.write(180);                    // quickly to 180°
  delay(1000);
  for (int angle = 180; angle >= 0; angle--) {
    servo.write(angle);                // slowly back, one degree at a time
    delay(15);
  }
  delay(1000);
}

What is new in the program?

  • Servo servo; – Creates an object for one servo. For two servos we would make two objects with different names.
  • servo.attach(servoPin); – From this moment the library sends the pulses to D9 by itself, in the background, while the program does something else.
  • servo.write(90); – Sets the angle in degrees, from 0 to 180. The library turns it into a pulse length: 0° is 544 µs and 180° is 2400 µs. That is a little wider than 1 to 2 ms, so that servos with wider limits also reach the end.
  • Turning slowly comes from changing the angle by one degree and waiting a little. The whole way from 180° to 0° then takes 181 · 15 ms ≈ 2.7 s.

On the Uno the Servo library uses the timer Timer1, so while any servo is attached, analogWrite() doesn’t work on pins 9 and 10. That is why the servos and the flippers of the pinball machine are not on the same Uno. An Uno can drive up to 12 servos.

Which Uno pins can do PWM?

The Arduino Uno has PWM on six pins: D3, D5, D6, D9, D10 and D11. On the board they are marked with a wavy line (~). Each pair of these pins is driven by one timer, so a command or library that takes a timer takes its two pins as well:

PinsTimerPWMWhat else uses it
D5 and D6Timer0about 980 Hzmillis() and delay(), but PWM still works
D9 and D10Timer1about 490 Hzthe Servo library
D3 and D11Timer2about 490 Hztone() and the IRremote library

A servo doesn't need a PWM pin: the Servo library sends its pulses on any digital pin. A servo's signal isn't the same as PWM from analogWrite(). analogWrite() switches the pin on and off about 490 times a second, while a servo expects one pulse every 20 ms, 50 a second. All the Uno's pins are described on the Pinouts page.

How long does it take to turn?

servo.write() doesn’t wait for the servo to turn. The program goes on at once, while the servo is still turning. The graph shows a calculation for an SG90, which turns 60° in 0.1 s at 4.8 V:

The arm's angle over 1.2 seconds. Dashed: at 0.2 s the program asks for 180°, and at 0.8 s for 90°. Orange: the arm turns at a steady speed and slows down just before the target. It reaches 180° about 0.37 s after the command, and 90° about 0.22 s after the second command
The servo turns at full speed and slows down just before the target, because the circuit lowers the motor’s current as the difference gets smaller. From 0° to 180° it takes about 0.37 s. So after servo.write() the program needs a delay() or a check with millis() before it counts on the arm having arrived.

When a servo buzzes

If a servo buzzes and gets warm at the end of its travel, the arm or the mechanism doesn’t let it reach the angle asked for. The circuit then keeps pushing the motor, and the motor draws its highest current. Make the angle smaller then, for example 10° to 170°, or set the pulse limits yourself: servo.attach(servoPin, 1000, 2000); sends 1000 µs for 0° and 2000 µs for 180°.

A continuous servo in the program

A continuous servo is driven with the same Servo library, but servo.write() now sets a speed, not an angle: servo.write(90) stops it, servo.write(0) spins it at full speed one way, and servo.write(180) the other way. Values in between, for example 70 or 110, make it turn more slowly. If the servo still creeps at 90, try 88 or 92: the point where it stands still differs a little from servo to servo.

Moving slowly: a servo without jerks

servo.write() gives the servo a new angle, and the servo rushes there at full speed. A sudden start and a sudden stop knock the gears inside the servo and the mechanism it moves: an arm, a post or the joint of a robot arm. The heavier the mechanism, the harder the knock. So we don’t give a big move all at once, but lead the servo to its target slowly, in small steps:

Plan before you program:
remember the angle the servo is at and the angle it should reach (the target)
repeat:
if the servo is at the target:
do nothing
otherwise, if 15 ms have passed since the last step:
move the angle 1° towards the target
send the new angle to the servo
// C++
#include <Servo.h>

Servo servo;
const int servoPin = 9;
const int START_ANGLE = 90;            // where the servo stands when the program starts
const unsigned long STEP_MS = 15;      // one degree every 15 ms: 60° in 0.9 s

int servoAngle = START_ANGLE;          // the angle the servo was last given
int servoTarget = START_ANGLE;         // the angle the servo moves to, slowly
unsigned long servoLastStep = 0;       // when the servo last moved
unsigned long lastChange = 0;          // when we last changed the target

void setup() {
  servo.write(START_ANGLE);            // the first pulse already carries the start angle, not 90°
  servo.attach(servoPin);
}

void loop() {
  // an example: a new target every 4 seconds, 160° and 20° in turn
  if (millis() - lastChange >= 4000) {
    lastChange = millis();
    if (servoTarget == 160) {
      servoTarget = 20;
    } else {
      servoTarget = 160;
    }
  }

  moveTowardsTarget(servo, servoAngle, servoTarget, servoLastStep, STEP_MS);
}

// Moves the servo one degree towards the target, if stepMs have passed since the last step.
// Parameters with & are references: the function changes the very variables it was called with.
void moveTowardsTarget(Servo &s, int &angle, int target, unsigned long &lastStep, unsigned long stepMs) {
  if (angle == target) {
    return;                            // already there
  }
  if (millis() - lastStep < stepMs) {
    return;                            // not yet time for the next step
  }
  lastStep = millis();
  if (target > angle) {
    angle = angle + 1;
  } else {
    angle = angle - 1;
  }
  s.write(angle);
}

What is new in the program?

  • servoAngle, servoTarget and servoLastStep – The program remembers the angle the servo was last given, the angle it should reach and when the last step was taken. The rest of the program only changes servoTarget.
  • moveTowardsTarget(servo, servoAngle, servoTarget, servoLastStep, STEP_MS); – The function gets everything it needs as parameters and touches no global variable. That is why you can use it for more than one servo. For a second servo, for example arm, you make its own variables and call the same function: moveTowardsTarget(arm, armAngle, armTarget, armLastStep, STEP_MS);. Both then move at the same time, each towards its own target.
  • int &angle – The & says that the parameter is a reference. The function doesn’t get a copy of the value, but changes the very variable it was called with: when it increases angle, servoAngle increases. The same goes for lastStep and for the servo, Servo &s. The function only reads target and stepMs, so it gets them as ordinary parameters, without &.
  • millis() - lastStep < stepMs – A step is taken only when 15 ms have passed since the last one, like debouncing in the lesson on buttons. The program doesn’t wait, so loop() can read buttons and sensors in the meantime. Turning slowly with delay(), as in the program above, would stop everything else until the servo has turned.
  • STEP_MS – Sets the speed: with 15 ms the servo covers 60° in 0.9 s, six times slower than at full speed (0.1 s for 60°). With 30 ms it goes half as fast.
  • servo.write(START_ANGLE); before servo.attach() – The program doesn’t know where the arm is when the Arduino starts. Without this, the library’s first pulse would ask for 90°, and the servo would rush there. This way the first pulse carries the start angle. The servo still jumps to the start angle, but only if someone moved it while it was off.

In a real program the target isn’t changed by a clock but by an event: a button press, a message from another Arduino or a sensor reading. For an even softer move, the step can be bigger while the servo is far from the target and smaller as it gets close.

What did we learn?

  • A servo turns to the angle it is given and holds it. Inside are a motor, gears, a potentiometer and a circuit that compares them.
  • The SG90 has three wires: brown (GND), red (5 V) and orange (signal).
  • The angle is set by the length of a pulse that comes every 20 ms: about 1 ms for 0°, 1.5 ms for 90° and 2 ms for 180°.
  • A servo has its own 5 V supply, with a common GND and a capacitor.
  • servo.write() doesn’t wait for the servo to turn. On the Uno the Servo library turns off PWM on pins 9 and 10.
  • A big move is given in small steps towards the target, with millis(), so that we don’t knock the gears and the mechanism.
  • A positional servo stops at the angle it is given. A continuous one has no potentiometer, so it spins round and round, and the pulse sets its direction and speed.

Quick quiz

1. How is a servo different from an ordinary motor?
An ordinary motor spins as long as it has current. A servo turns to the angle it is given and stays there.
2. How does a servo know which angle it is at?
A potentiometer is joined to the shaft, and its resistance depends on the angle. The circuit compares it with the angle the program asks for and turns the motor until they are the same.
3. How long is the pulse for 90°, and how often does it come?
About 1.5 ms, and it comes every 20 ms.
4. When the servo starts, the Arduino resets. What is most likely wrong?
The servo is powered from the Arduino or USB and draws too much current for a moment, so the voltage drops. The servo needs its own 5 V supply, a capacitor next to it and its GND joined to the Arduino’s GND.
5. A program calls servo.write(180) and straight after it reads a sensor at the arm. Why doesn't the sensor report yet that the arm has arrived?
servo.write() doesn’t wait. An SG90 needs about 0.37 s to turn from 0° to 180°, so the program needs a delay() or a check with millis().
6. On an Uno, a servo is on D9 and you want to dim an LED on D10 with analogWrite(). Why doesn't it work?
On the Uno the Servo library uses Timer1, the same timer that makes PWM on pins 9 and 10. Move the LED to pin 3, 5, 6 or 11.
7. How is a continuous servo different from a positional one?
A positional servo turns to the angle it is given and stops there. A continuous one has no potentiometer and no end stop, so it spins round and round like an ordinary motor, and the pulse sets its direction and speed: about 1.5 ms means stop.