Servo Motors: Precise Position Control for Robot Joints
Servo motors are the joints of a robot. Learn the difference between hobby servos and industrial servo systems, and how to control them with PWM.
A plain DC motor spins as fast as you let it and stops wherever momentum leaves it — useful for wheels, useless for an arm that needs to hold a precise angle. A servo motor solves that problem: tell it “go to 90 degrees” and it goes there and stays there, fighting back if something pushes it. That makes servos the natural choice for robot joints, steering linkages, grippers, and camera gimbals.
What Makes a Servo Different
A hobby servo is not just a motor. Inside one small plastic case you get four things working together:
- A small DC motor for the actual movement
- A gear train that trades speed for torque
- A position sensor (usually a potentiometer geared to the output shaft)
- A control circuit that constantly compares where the shaft is against where you commanded it to be
That last part is the key idea: closed-loop control. The servo measures its own position and corrects any error automatically. A bare DC motor is open-loop — you apply voltage and hope. A servo watches itself and adjusts, which is why it can hold an angle against a load.
The Three Types of Servo
| Type | Range of Motion | Typical Use |
|---|---|---|
| Standard hobby servo | Limited, usually ~180° | Robot joints, grippers, steering, pan/tilt |
| Continuous-rotation servo | Full 360°, no limit | Drive wheels, conveyors (you control speed, not angle) |
| Industrial / closed-loop servo | Multi-turn, very precise | CNC, industrial arms, high-torque automation |
A continuous-rotation servo is a clever modification: the position sensor is disconnected from the shaft, so the servo can never “reach” its target. Instead of moving to an angle, it spins continuously, and your command sets the direction and speed. Industrial servos are a different world — they use encoders (next week’s topic) instead of potentiometers, run on dedicated drives, and cost orders of magnitude more.
This tutorial focuses on the standard hobby servo, since it’s what you’ll actually wire to an Arduino.
How PWM Controls a Servo
Servos are commanded with a PWM (Pulse Width Modulation) signal, but not the kind you use to dim an LED. A servo cares about one thing: how long each pulse stays HIGH.
The signal is a repeating frame sent at 50 Hz, meaning one pulse every 20 ms. Within each frame, the width of the HIGH pulse encodes the target position:
| Pulse Width | Servo Angle |
|---|---|
| 1.0 ms | 0° |
| 1.5 ms | 90° (center) |
| 2.0 ms | 180° |
So the position information lives entirely in a window between roughly 1 ms and 2 ms inside each 20 ms frame. The servo’s internal circuit measures that pulse, compares it to the potentiometer reading, and drives the motor until they match. (Real servos vary — some respond to pulses as short as 0.5 ms or as long as 2.5 ms — which is why some servos slightly over- or under-shoot the textbook 0–180° range.)
The 3-Wire Interface
Every hobby servo has exactly three wires. Colors vary by brand, but the order is standardized:
| Wire | Color (common) | Connects To |
|---|---|---|
| Signal | Orange / white / yellow | A digital pin on the Arduino |
| V+ | Red | The servo’s power supply (+) |
| GND | Brown / black | Power supply ground and Arduino ground |
Arduino Code: Move to an Angle
The Arduino Servo library hides the PWM timing for you. You think in degrees; it generates the pulses.
#include <Servo.h>
Servo myServo; // create a servo object
const int SERVO_PIN = 9; // signal wire connects here
void setup() {
myServo.attach(SERVO_PIN); // tell the library which pin to drive
myServo.write(90); // move to center (90°)
}
void loop() {
myServo.write(0); // go to 0°
delay(1000); // wait for it to get there
myServo.write(90); // go to 90°
delay(1000);
myServo.write(180); // go to 180°
delay(1000);
}
servo.attach(9) claims pin 9 and starts the 50 Hz signal. servo.write(angle) sets the target in degrees from 0 to 180. Note the delay() calls: write() returns instantly, but the servo needs physical time to travel, so you give it a moment before commanding the next move.
Arduino Code: A Smooth Sweep
Jumping straight to a target is fine, but stepping the angle gradually gives smoother, slower motion — useful for a camera mount or a gentle gripper.
#include <Servo.h>
Servo myServo;
const int SERVO_PIN = 9;
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); // 15 ms per degree controls the speed
}
// Sweep back from 180° to 0°
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
delay(15);
}
}
The Most Important Wiring Rule: Separate Power
Beginners burn out more boards on this than anything else, so read this twice.
A servo draws far more current than the Arduino’s 5V pin can supply. A small servo idles at tens of milliamps but spikes to several hundred milliamps to over an amp the instant it starts moving or hits a load. The Arduino’s onboard regulator simply cannot deliver that.
The rule:
- Power the servo from a separate supply — a battery pack or a dedicated 5V/6V supply rated for at least 1A per servo.
- Connect the grounds together. The servo’s GND, the external supply’s GND, and the Arduino’s GND must all share a common ground. Without a common ground, the signal wire has no reference voltage and the servo behaves erratically or not at all.
- Only the tiniest micro servos (like a 9g SG90) doing light, occasional moves can sometimes run off the Arduino 5V pin — and even then, expect resets under load.
Arduino pin 9 ──────────────► Servo signal
External 5V (+) ────────────► Servo V+
External 5V GND ─┬──────────► Servo GND
└──────────► Arduino GND (common ground!)
Torque and Voltage Ratings
Two numbers decide whether a servo can do your job:
- Torque, given in kg·cm (kilogram-centimeters). A 10 kg·cm servo can hold 10 kg at 1 cm from the shaft, 5 kg at 2 cm, and so on — torque falls off as the load moves farther out on the arm. Size your servo for the worst-case lever arm, with margin.
- Voltage rating, usually a range like 4.8V–6V (or 6V–7.4V for high-power servos). Higher voltage within the rated range generally means more torque and faster motion. Exceeding the rating cooks the electronics; running below it leaves you weak and slow.
Troubleshooting
- Jitter (the servo twitches or hums at rest): Usually electrical noise on the signal line or a marginal power supply. Add a 100µF capacitor across the servo’s power leads, keep signal wires short, and confirm a solid common ground. Cheap servos also jitter simply from a low-resolution internal potentiometer.
- Brownouts / Arduino randomly resets: The classic symptom of powering the servo from the Arduino. The current spike drops the rail voltage and reboots the board. Move the servo to a separate supply with a common ground.
- Buzzing while holding position: The servo is fighting a load it can’t quite hold, so the motor keeps pulsing. Either the load exceeds its torque rating or it’s commanded to an angle past its mechanical limit. Reduce the load, pick a higher-torque servo, or back the command off the end stops.
Next week we move from commanding a joint to measuring one: wheel encoders, and how they let your robot know exactly how far it has actually moved.