You've got a robot arm that needs to wave, a camera gimbal that needs to pan smoothly, or a little animatronic puppet that needs to nod its head. The component that makes this precise, angular motion possible is the humble servo motor. But if you've ever plugged one in and watched it twitch erratically or refuse to move, you know there's a gap between buying a servo and actually controlling it reliably. I've been there, frying my share of cheap servos by misunderstanding their power needs. Let's bridge that gap.
This guide cuts through the noise. We'll start with the absolute fundamentals of what a servo is and how it interprets commands, then move straight into practical code for Arduino and Raspberry Pi. More importantly, we'll cover the setup mistakes that cause jitter, burnout, and frustrationāthings most tutorials gloss over.
What You'll Learn
What Exactly is a Servo Motor?
Forget the complex definitions. A servo motor is a packaged unit containing three things: a small DC motor, a set of gears to reduce speed and increase torque, and a control circuit with a feedback sensor (usually a potentiometer). This last part is key. The sensor tells the control circuit the motor's current position. When you send a command saying "go to 90 degrees," the circuit compares that target to the current position and powers the motor until they match. It's a closed-loop system.
This is fundamentally different from a standard DC motor, which just spins when you apply power. A servo gives you positional control. The most common type is the 180-degree rotary servo, like the ubiquitous SG90 or MG90S. It moves its output shaft to a specific angle between 0 and 180 degrees. There are also continuous rotation servos (which act like speed-controllable gearmotors) and high-torque or digital servos for more demanding jobs.
How Servo Motors Work: The PWM Signal Explained
You don't send a servo a number like "90". You send it a pulse. This is the core concept everyone needs to grasp. The language a servo understands is called Pulse Width Modulation (PWM).
Imagine you're rapidly flipping a light switch on and off. The servo expects a new "on" pulse every 20 milliseconds (50 times per second). The magic is in the duration of that "on" pulse, or the pulse width.
- A pulse width of 1.5 milliseconds typically tells the servo to move to its neutral position (90 degrees).
- A pulse width of 1.0 milliseconds commands it to go to 0 degrees.
- A pulse width of 2.0 milliseconds commands it to go to 180 degrees.
The control circuit inside the servo measures the length of each incoming pulse and drives the motor to the corresponding position. If the pulses stop, most servos will simply hold their last position (or go limp, depending on the model).
The Big Misconception About Voltage
Here's a subtle point that causes endless trouble. The PWM signal on the signal wire is about timing, not power. It's usually a 5V or 3.3V logic pulse from your microcontroller. However, the servo's motor needs a separate, more robust power source. A tiny micro-servo might run on 5V from your Arduino's USB port for testing, but the moment it meets any resistance, it will draw more current than the Arduino's voltage regulator can supply. This causes the Arduino to brown out, reset, or the servo to behave erratically.
Rule of thumb: Always power your servos from a dedicated power supply (like a 5V or 6V battery pack or bench supply) and connect its ground to your microcontroller's ground. The signal wire is the only connection needed from the MCU.
How to Control a Servo with Arduino
Arduino makes servo control almost trivial, which is why it's the perfect starting point. It has a dedicated Servo library that handles the precise timing of the PWM pulses for you.
Basic Wiring and Sweep Example
Let's control an SG90 servo. You'll need an external 5V power source (like a 4xAA battery holder or a USB power bank).
Wiring:
- Servo Red Wire -> 5V on your external supply.
- Servo Brown/Black Wire -> GND on your external supply and GND on Arduino.
- Servo Yellow/Orange Wire -> Pin 9 on Arduino.
- Connect the GND of your external supply to an Arduino GND pin. This creates a common ground.
Now, the code. This makes the servo sweep back and forth.
Servo myServo; // Create a servo object
int servoPin = 9;
void setup() {
myServo.attach(servoPin); // Attach the servo to pin 9
}
void loop() {
myServo.write(0); // Command to 0 degrees
delay(1000); // Wait 1 second
myServo.write(90); // Command to 90 degrees
delay(1000);
myServo.write(180); // Command to 180 degrees
delay(1000);
}
The myServo.write(angle) function is the magic. You give it an angle from 0 to 180, and the library converts it to the correct pulse width. Couldn't be simpler.
Controlling Multiple Servos
The standard Servo library can control up to 12 servos on most Arduino boards. Just create more Servo objects. However, there's a catch: using delay() in your code will freeze everything. For a robot with multiple moving parts, you need non-blocking code. This is where millis()-based timing or more advanced libraries like ESP32Servo (for ESP32 boards) come in.
Controlling Servos with a Raspberry Pi
On the Raspberry Pi, servo control is different. The Pi's hardware PWM pins are limited (only GPIO12, GPIO13, GPIO18, GPIO19 on a Pi 4). For reliable, jitter-free control, you should use a dedicated servo hat or an external PCA9685 PWM driver, which communicates via I2C. But for a single servo test, we can use software PWM with the GPIO Zero library, keeping in mind it may have slight jitter.
For any serious multi-servo project on a Pi, I strongly recommend the PCA9685 breakout board. It's cheap, handles 16 servos independently, and offloads the timing work from the Pi's CPU, giving you rock-solid performance.
How to Choose the Right Servo Motor for Your Project
Not all servos are created equal. Picking the wrong one leads to stripped gears or a mechanism that just can't move. Look at these three specs:
| Servo Type | Torque (kg-cm) | Speed (sec/60°) | Best For | Price Range |
|---|---|---|---|---|
| Micro Servo (SG90) | 1.2 - 2.5 | 0.10 - 0.15 | Small robot joints, lightweight flags, pan/tilt for tiny cameras. | $3 - $5 |
| Standard Servo (MG90S) | 2.0 - 3.0 | 0.10 - 0.14 | RC car steering, medium-duty robot arms, larger pan/tilt mechanisms. | $5 - $10 |
| High-Torque Servo (MG996R) | 10 - 13 | 0.17 - 0.20 | Heavy-duty robot arms, combat robot weapons, large animatronics. | $10 - $20 |
| Digital Servo | Varies (often high) | Very Fast (0.06-0.08) | Precision robotics, drones (gimbals), competition RC where holding strength and speed are critical. | $20+ |
Torque is the rotational force. If you're lifting an arm with a weight at the end, you need high torque. Speed is how fast it moves. A fast, weak servo is useless for lifting; a strong, slow servo is bad for quick movements.
My advice: For a first project, buy a 3-pack of MG90S servos. They're metal-geared (more durable than SG90's plastic gears), strong enough for most small to medium projects, and very affordable. Avoid the absolute cheapest no-name servosātheir calibration and consistency are terrible.
Advanced Control and Common Problems Solved
Fixing Servo Jitter and Buzzing
This is the #1 complaint. The servo buzzes or shakes when it should be still. 95% of the time, it's a power supply issue. The servo isn't getting clean, sufficient current. The fix: Use a dedicated regulator (like a 5V UBEC) or a high-current battery pack. Never power multiple servos from a microcontroller's 5V pin.
The other 5% is electrical noise or a poor signal connection. Keep signal wires away from power wires. Use a capacitor (100-470µF) across the servo's power and ground leads, right at the servo connector. This smooths out sudden current draws.
Achieving Smoother Movement
The write() function makes an immediate jump. For a graceful sweep, you need to move in small steps. Here's a better Arduino loop:
Controlling a Continuous Rotation Servo
These servos are rewired internally. A 1.5ms pulse means "stop." 1.0ms means "full speed clockwise," and 2.0ms means "full speed counter-clockwise." You control speed and direction, not position. They're great for simple wheeled robots. The Arduino Servo library still worksāyou use write() with 0 as full speed one way, 180 as full speed the other, and 90 to stop. The values in between control speed.
Your Servo Control Questions Answered
myServo.attach(pin, minPulse, maxPulse). In the Raspberry Pi GPIO Zero example above, you saw the min_pulse_width and max_pulse_width parameters. Tweak these values to get the full range of motion.