Lesson 3: Servo Motors
Table of Contents
- Materials
- Servo motors
- Servo PWM vs.
analogWrite()PWM - The Arduino Servo library
- Let’s make stuff!
- Exercises
- Lesson Summary
- Resources
- Next Lesson
This lesson is in draft form. The circuit diagrams and videos have not yet been inserted; however, the content is complete and can be followed.
In the previous two lessons, we controlled pixels—on an OLED screen and on an LED strip. Now let’s make things move! Servo motors let you precisely control angular position, making them essential components in robotics, RC vehicles, pan/tilt camera mounts, automated door locks, and countless other projects. Best of all, like the OLED and addressable LEDs, servos have a built-in control circuit—so the wiring is simple and a library handles the tricky signal timing.
In this lesson, you will learn:
- What servo motors are and how they differ from regular DC motors
- How the internal feedback loop (motor + gears + potentiometer + control circuit) enables precise position control
- The difference between servo PWM signals and
analogWrite()PWM—and why they’re not the same thing- How to use the Arduino Servo library to control servo position
- How to wire a servo to Arduino (no transistor needed!)
- Power considerations for servos and when to use an external supply
- How to create interactive servo projects driven by sensor input
Materials
You will need the following materials for this lesson:
| Arduino | Servo Motor | Breadboard | Potentiometer |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
| Arduino Uno, Leonardo, or similar | SG90 or SG92R micro servo (9g) | Breadboard | 10KΩ Potentiometer |
You will also need jumper wires and, for Activity 3, a couple of tactile buttons.
Our kits include a 9g micro servo—either the TowerPro SG92R (available from Adafruit) or the Miuzei SG90 (available from Amazon). Both are SG90-class servos with nearly identical specs and wiring. Any 9g micro servo with a standard 3-pin connector will work for this lesson.
Servo motors
What is a servo motor?
A servo motor is a motor that can rotate to a specific angle and hold that position. Unlike a regular DC motor (which just spins continuously when you apply voltage), a servo knows where its output shaft is pointing and actively works to maintain that position—even if you try to push it away.
How does it do this? A servo packs four components into one compact package:
- A small DC motor that provides rotational force.
- A gear reduction system that slows the motor down while increasing torque (turning force).
- A potentiometer mechanically coupled to the output shaft that measures the shaft’s current angle.
- A control circuit that continuously compares the desired position (from your Arduino’s signal) with the actual position (from the potentiometer) and drives the motor until they match.
This is called a closed-loop feedback system—the control circuit constantly monitors and corrects the position. You tell the servo “go to 90°” and it figures out how to get there and stay there.
Built-in smarts! Notice the pattern across this module: the OLED has a built-in SSD1306 display controller, addressable LEDs have built-in WS2812B driver chips, and servos have a built-in feedback control circuit. Each device handles the complex low-level work internally, and you communicate with it through a simple signal. In the next lesson, we’ll encounter a component that doesn’t have built-in intelligence—and you’ll appreciate the difference!
Standard vs. continuous rotation servos
There are two types of hobby servos:
- Standard (positional) servos rotate to a specific angle, typically between 0° and 180°, and hold that position. The angle is determined by the signal you send. This is what we’ll use in this lesson.
- Continuous rotation servos spin freely like a regular motor, but you control their speed and direction rather than their position. The same PWM signal that means “go to 90°” on a standard servo means “stop” on a continuous rotation servo, while “0°” means “full speed clockwise” and “180°” means “full speed counter-clockwise.”
For this lesson, we’ll focus on standard (positional) servos, specifically the popular SG90 micro servo.
The SG90 micro servo
The SG90 is a class of tiny, inexpensive servo motors that weigh only 9 grams. Despite their small size, they’re surprisingly capable for learning projects. You’ll find SG90-class servos from many manufacturers (TowerPro, Miuzei, and others)—they all share the same basic form factor, connector, and specs:
| Attribute | Rating |
|---|---|
| Weight | 9g |
| Operating voltage | 4.8V - 6.0V |
| Stall torque | 1.8 kg·cm (4.8V) |
| Operating speed | 0.09 sec/60° (4.8V) |
| Rotation range | ~180° |
| Idle current | ~6mA |
| Running current (no load) | ~200-500mA |
| Stall current | ~500-700mA |
The SG90 has a standard 3-pin connector with color-coded wires: orange/yellow (signal), red (power), and brown/black (ground).
Servo PWM vs. analogWrite() PWM
Before we start wiring, let’s clear up a common source of confusion. You’ve already used analogWrite() to control LED brightness. Servos are also controlled by a “PWM” signal. But these are fundamentally different kinds of PWM, and mixing them up is a common mistake.
analogWrite() PWM | Servo PWM | |
|---|---|---|
| What varies | The duty cycle (fraction of time HIGH) | The pulse width (duration of the HIGH pulse) |
| Frequency | Fixed at 490 Hz or 980 Hz (depending on pin) | Fixed at 50 Hz (one pulse every 20ms) |
| What it controls | Power delivery (brightness, motor speed) | Position (angle) |
| Signal meaning | 0% duty cycle = off, 100% = full power | ~1ms pulse = 0°, ~1.5ms = 90°, ~2ms = 180° |
| Arduino function | analogWrite(pin, 0-255) | servo.write(0-180) via the Servo library |
With analogWrite(), a 50% duty cycle delivers 50% of the available power—useful for dimming LEDs or slowing motors. With servo PWM, the duty cycle doesn’t matter for power delivery. Instead, the servo’s control circuit measures the width of each pulse to determine the target angle.
Do not use
analogWrite()to control servos! TheanalogWrite()function produces PWM at 490 Hz or 980 Hz—much too fast for servos, which expect 50 Hz. Sending the wrong signal can cause erratic behavior or damage. Always use the ArduinoServolibrary, which generates the correct 50 Hz signal for you.
The Arduino Servo library
The Arduino Servo library ships with the Arduino IDE—no installation needed. It handles all the precise signal timing so you can simply tell the servo which angle you want.
Figure. Wiring the SG90 servo requires just three connections. No transistor or external components needed—the servo has its own built-in driver circuit.
No transistor needed! In the vibromotor lesson, you’ll learn that raw DC motors need a transistor because they draw more current than a GPIO pin can supply. Servos are different—the signal wire carries only a control signal (a few milliamps), not the motor’s power. The servo’s internal driver circuit handles the heavy lifting. The motor power comes directly from the 5V pin, not through the Arduino’s GPIO.
Power considerations
A single SG90 servo under light load can usually be powered from the Arduino’s 5V pin (via USB). However, servos can draw significant current, especially during rapid movements or when holding position against a load:
| State | Typical current |
|---|---|
| Idle (holding position, no load) | ~6mA |
| Moving (no load) | ~200-500mA |
| Stall (load exceeds torque) | ~500-700mA |
The Arduino’s USB power supply provides about 500mA total. A single SG90 moving under light load is usually fine, but if your servo jitters, stalls, or your Arduino resets, you may be hitting the current limit.
If your Arduino resets when the servo moves, the servo is drawing too much current from USB. Power the servo from an external 5V supply (like a USB phone charger rated 1A+). Connect the supply’s 5V directly to the servo’s red wire and the supply’s GND to both the servo’s brown wire and the Arduino’s GND (shared ground). Do not connect the external 5V to the Arduino’s 5V pin.
For projects with multiple servos, you will almost certainly need an external power supply. Two or more servos moving simultaneously can easily exceed 1A. For larger builds, consider a dedicated servo driver board like the PCA9685, which provides its own power bus and can control up to 16 servos via I2C.
Let’s make stuff!
Now that we understand how servos work and have one wired up, let’s build some projects! As with the previous lessons, we’ll start simple and progressively add interactivity.
Activity 1: Servo sweep
Just as we started with blinking an LED and lighting up NeoPixels, let’s start with the simplest possible servo program: sweeping back and forth between 0° and 180°. This confirms your wiring is correct and that the library is communicating with the servo.
#include <Servo.h>
const int SERVO_PIN = 3;
Servo myServo;
void setup() {
myServo.attach(SERVO_PIN);
}
void loop() {
// Sweep from 0° to 180°
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle);
delay(15); // Wait for the servo to reach the position
}
// Sweep back from 180° to 0°
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
delay(15);
}
}The delay(15) gives the servo time to reach each position before advancing to the next degree. Try changing the delay—a shorter delay means faster sweeping, but if it’s too short, the servo can’t keep up and will jitter. What happens if you change the range to for (int angle = 30; angle <= 150; ...)?
Avoid driving to the mechanical limits. If your servo makes a grinding or buzzing sound at 0° or 180°, it’s hitting its mechanical stops and stalling. This draws high current and can strip the plastic gears over time. Try reducing your range to 10-170° or experiment to find your servo’s actual safe limits.
Activity 2: Potentiometer-controlled servo
Now let’s add a potentiometer to directly control the servo’s position—turn the knob, and the servo follows. This is the same analogRead() → map() → output pattern from the OLED ball-size demo and the NeoPixel color wheel. You’ll see this pattern again in the vibromotor lesson too—it’s one of the most fundamental patterns in physical computing!
The circuit
Use the same servo wiring as before, and add a 10KΩ potentiometer with its wiper connected to A0.
The code
#include <Servo.h>
const int SERVO_PIN = 3;
const int POT_PIN = A0;
Servo myServo;
void setup() {
myServo.attach(SERVO_PIN);
Serial.begin(9600);
}
void loop() {
// Read the potentiometer (0-1023)
int potVal = analogRead(POT_PIN);
// Map to servo angle (0-180)
int angle = map(potVal, 0, 1023, 0, 180);
// Move the servo
myServo.write(angle);
// Debug output
Serial.print("Pot: ");
Serial.print(potVal);
Serial.print(" -> Angle: ");
Serial.println(angle);
delay(15);
}This is essentially the Arduino’s built-in “Knob” example, which you can also find in the Arduino IDE under File → Examples → Servo → Knob. Turn the potentiometer and watch the servo track your input in real time. Try replacing the potentiometer with a force-sensitive resistor or a photoresistor—squeeze to point, or let light control the angle!
Activity 3: Sensor-driven servo gauge
For our final activity, let’s build a physical gauge—a servo-powered pointer that displays sensor data in the real world, like an analog speedometer or a VU meter needle. This is the physical output equivalent of the OLED analog graph and the NeoPixel level meter. Where the OLED drew data on screen and the NeoPixels lit up LEDs proportionally, here we’ll sweep a physical pointer across a scale.
We’ll read an analog sensor on A0 and map it to the servo’s range. To make it more interesting, we’ll add two buttons: one to “freeze” the gauge at its current reading (like a max-hold feature on a multimeter), and one to reset it.
The circuit
Use the same servo + potentiometer wiring, and add two tactile buttons on Pins 8 and 9 using INPUT_PULLUP.
The code
#include <Servo.h>
const int SERVO_PIN = 3;
const int SENSOR_PIN = A0;
const int FREEZE_BTN = 8;
const int RESET_BTN = 9;
Servo gaugeServo;
bool isFrozen = false;
int frozenAngle = 0;
void setup() {
gaugeServo.attach(SERVO_PIN);
pinMode(FREEZE_BTN, INPUT_PULLUP);
pinMode(RESET_BTN, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
// Check freeze button (INPUT_PULLUP reads LOW when pressed)
if (digitalRead(FREEZE_BTN) == LOW) {
isFrozen = !isFrozen; // Toggle freeze state
if (isFrozen) {
frozenAngle = gaugeServo.read();
Serial.print("Frozen at: ");
Serial.println(frozenAngle);
} else {
Serial.println("Unfrozen");
}
delay(300); // Simple debounce
}
// Check reset button
if (digitalRead(RESET_BTN) == LOW) {
isFrozen = false;
gaugeServo.write(0);
Serial.println("Reset to 0");
delay(300);
}
// Update gauge if not frozen
if (!isFrozen) {
int sensorVal = analogRead(SENSOR_PIN);
int angle = map(sensorVal, 0, 1023, 0, 180);
gaugeServo.write(angle);
Serial.print("Sensor: ");
Serial.print(sensorVal);
Serial.print(" -> Angle: ");
Serial.println(angle);
}
delay(15);
}Try attaching a small pointer (a piece of cardboard, a toothpick, or a 3D-printed needle) to the servo horn to create a visual gauge. You could print or draw a scale on paper behind it to complete the analog meter look. This is a great example of physical data visualization—the same sensor data that we graphed on the OLED screen is now embodied as physical motion.
Connecting it all together: At this point, you could combine the servo gauge with an OLED display to show the numeric reading on screen while the servo shows it physically, or with NeoPixels to add color coding (green for low, red for high). Multimodal output—visual, spatial, and haptic—is a powerful tool in physical computing and HCI!
Exercises
Want to go further? Here are some challenges to reinforce what you’ve learned:
- Servo-powered door lock. Use a button to toggle the servo between “locked” (0°) and “unlocked” (90°) positions. Add an LED that turns green when unlocked and red when locked. You could even attach the servo to a small latch mechanism.
- Light tracker. Mount two photoresistors on either side of a servo. Read both sensors and turn the servo toward whichever side detects more light—a simple solar tracker!
- Servo + OLED dashboard. Display the current servo angle, sensor reading, and servo state (frozen/unfrozen) on the OLED display while the gauge moves. This combines two lessons into a multimodal output project.
- Animatronic face. If you have two servos, mount them to control the horizontal and vertical movement of a pair of eyes (drawn or 3D-printed). Use two potentiometers—or an accelerometer—as input for a fun animatronic project.
Lesson Summary
In this lesson, you learned how to control servo motors for precise angular positioning. The key concepts were:
- Servo motors contain a DC motor, gears, a position-sensing potentiometer, and a control circuit in one package. This closed-loop feedback system lets you command a specific angle and the servo figures out how to get there.
- Standard servos rotate to a specific angle (typically 0-180°) and hold position. Continuous rotation servos control speed and direction instead.
- Servo PWM is fundamentally different from
analogWrite()PWM. Servos expect a 50 Hz signal where the pulse width (1-2ms) encodes the target angle.analogWrite()produces 490-980 Hz PWM with varying duty cycles for power control. Never useanalogWrite()to drive a servo. - The Arduino Servo library generates the correct 50 Hz signal for you. Like the NeoPixel library, it works on any digital pin—no hardware PWM required.
- Unlike raw DC motors (covered in the next lesson), no transistor is needed because the signal wire carries only a low-current control signal. The servo’s internal circuit handles motor power.
- The Servo library uses Timer1, which disables
analogWrite()on Pins 9 and 10 (Uno) or Pins 9, 10, and 11 (Leonardo). Plan your pin assignments accordingly when combining servos with other PWM outputs. - For multiple servos or heavy loads, use an external 5V power supply with a shared ground connection to the Arduino—the same principle we’ll encounter again in the vibromotor lesson.
Resources
-
Arduino Servo Library Reference, Arduino.cc
-
Servo Motor Basics with Arduino, Arduino Docs
-
Adafruit Motor Selection Guide, Adafruit — helps you choose the right motor type for your project
-
PCA9685 16-Channel Servo Driver, Adafruit — for projects needing many servos
Next Lesson
In the next lesson, we will shift from components with built-in intelligence to a raw DC motor—the vibromotor. You’ll learn why transistors, flyback diodes, and resistor calculations become necessary when a component doesn’t have its own driver circuit.



