Servo motors are one of the most satisfying components to work with on Arduino. Whether you are building a robotic arm, a pan-tilt camera mount, a RC car steering system, or a simple door lock, the Arduino Servo library gives you precise control over angle and position with just a few lines of code. In this tutorial, you will learn everything about using the Servo library — from basic sweeping to buttery-smooth motion and advanced position control techniques.
Table of Contents
- What Is the Arduino Servo Library?
- Wiring a Servo to Arduino
- Basic Sweep Example
- Smooth Sweep with Easing
- Precise Position Control
- Controlling Multiple Servos
- Advanced Tips and Common Mistakes
- Frequently Asked Questions
What Is the Arduino Servo Library?
The Servo library is a built-in Arduino library that makes controlling hobby servo motors straightforward. It generates the PWM (Pulse Width Modulation) signal that servo motors need — typically a pulse between 1ms and 2ms repeated every 20ms. Instead of manually calculating timer registers and duty cycles, you simply call servo.write(angle) and the library handles everything.
Key facts about the Arduino Servo library:
- Supports up to 12 servos on most Arduino boards (Uno, Nano, Mega)
- On Arduino Mega, up to 48 servos can be controlled
- Uses Timer 1 on Uno/Nano (disables PWM on pins 9 and 10)
- Angle range: 0° to 180° by default
- Microsecond-level precision available via
writeMicroseconds() - No external library installation needed — it ships with Arduino IDE
Standard hobby servos have three wires: power (red), ground (black/brown), and signal (orange/yellow/white). The signal wire receives the PWM pulse from any Arduino digital pin connected through the Servo library.
Wiring a Servo to Arduino
Before writing any code, you need to wire the servo correctly. Incorrect wiring is the most common cause of erratic servo behaviour or burnt components.
Basic Wiring for a Single Servo
- Red wire (VCC): Connect to 5V on Arduino (for small servos under 1A) or to an external 5V supply
- Brown/Black wire (GND): Connect to GND on Arduino and external supply GND if used
- Orange/Yellow wire (Signal): Connect to any digital pin (pin 9 used in examples below)
Important: Most servo motors draw 200–600mA when moving under load. Arduino’s 5V pin can supply about 500mA in total (shared with everything else). For more than one servo or any servo under significant load, use an external 5V power supply with a shared ground connection to Arduino. Failing to do this causes voltage brownouts, random resets, and inconsistent servo behaviour.
For SG90 micro servos and similar lightweight servos in no-load test situations, powering directly from Arduino 5V is acceptable for quick prototyping.
Basic Sweep Example
The classic servo sweep is the “Hello World” of servo programming. The servo rotates from 0° to 180° and back continuously.
#include <Servo.h>
Servo myServo; // Create a Servo object
void setup() {
myServo.attach(9); // Attach servo to pin 9
}
void loop() {
// Sweep from 0 to 180 degrees
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle);
delay(15); // Wait 15ms for servo to reach position
}
// Sweep back from 180 to 0 degrees
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
delay(15);
}
}
This works, but delay(15) blocks everything else in your loop. Additionally, the motion is linear — it starts and stops abruptly, which looks mechanical and causes jerky motion in physical mechanisms. Let us improve on both of these issues.
Smooth Sweep with Easing
Professional servo projects use easing functions — mathematical curves that make motion accelerate at the start and decelerate at the end. This is called “ease-in-out” motion and it looks much more natural.
Non-Blocking Sweep with millis()
First, let’s replace delay() with millis() so your Arduino can do other things while the servo moves:
#include <Servo.h>
Servo myServo;
unsigned long lastMoveTime = 0;
int currentAngle = 0;
int targetAngle = 180;
const int STEP_DELAY = 15; // milliseconds between steps
void setup() {
myServo.attach(9);
myServo.write(0);
}
void loop() {
unsigned long now = millis();
if (now - lastMoveTime >= STEP_DELAY) {
lastMoveTime = now;
if (currentAngle < targetAngle) {
currentAngle++;
} else if (currentAngle > targetAngle) {
currentAngle--;
} else {
// Reached target — reverse direction
targetAngle = (targetAngle == 180) ? 0 : 180;
}
myServo.write(currentAngle);
}
// Other code can run here without being blocked
}
Sinusoidal Easing for Natural Motion
For truly smooth motion, apply a sine wave easing function. The servo accelerates gently at start and decelerates smoothly at end:
#include <Servo.h>
#include <math.h>
Servo myServo;
// Move servo from startAngle to endAngle over durationMs milliseconds
void smoothMove(int startAngle, int endAngle, int durationMs) {
unsigned long startTime = millis();
while (true) {
unsigned long elapsed = millis() - startTime;
if (elapsed >= durationMs) break;
// t goes from 0.0 to 1.0
float t = (float)elapsed / durationMs;
// Ease-in-out using cosine
float easedT = (1.0 - cos(t * M_PI)) / 2.0;
int angle = startAngle + (int)((endAngle - startAngle) * easedT);
myServo.write(angle);
delay(10);
}
myServo.write(endAngle); // Ensure final position is exact
}
void setup() {
myServo.attach(9);
myServo.write(0);
delay(500);
}
void loop() {
smoothMove(0, 180, 1500); // Move to 180° over 1.5 seconds
delay(500);
smoothMove(180, 0, 1500); // Move back over 1.5 seconds
delay(500);
}
The cosine easing produces motion that feels organic — ideal for animatronic characters, camera gimbals, or any project where smooth motion matters aesthetically.
Precise Position Control
Sometimes you need to move to an exact angle rather than sweep continuously. The write() function accepts integers (0–180), but you can get finer control using writeMicroseconds().
Using writeMicroseconds() for Precision
Standard servos use pulse widths from approximately 500µs to 2500µs:
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9, 500, 2500); // Min 500µs, max 2500µs
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
int microseconds = Serial.parseInt();
if (microseconds >= 500 && microseconds <= 2500) {
myServo.writeMicroseconds(microseconds);
Serial.print("Moved to: ");
Serial.print(microseconds);
Serial.println(" µs");
}
}
}
Potentiometer-Controlled Position
One of the most practical servo setups is using a potentiometer to manually set servo angle in real time — perfect for calibration jigs, manual overrides in automated systems, or just learning how servo control works:
#include <Servo.h>
Servo myServo;
const int POT_PIN = A0;
const int SERVO_PIN = 9;
void setup() {
myServo.attach(SERVO_PIN);
Serial.begin(9600);
}
void loop() {
int potValue = analogRead(POT_PIN); // 0–1023
int angle = map(potValue, 0, 1023, 0, 180);
myServo.write(angle);
Serial.print("Pot: ");
Serial.print(potValue);
Serial.print(" -> Angle: ");
Serial.println(angle);
delay(15);
}
Controlling Multiple Servos
The Servo library can control up to 12 servos on Arduino Uno and Nano without any additional hardware. Simply create multiple Servo objects and attach each to a different pin:
#include <Servo.h>
Servo servo1;
Servo servo2;
Servo servo3;
void setup() {
servo1.attach(6);
servo2.attach(7);
servo3.attach(8);
// Set all to neutral (90 degrees)
servo1.write(90);
servo2.write(90);
servo3.write(90);
delay(1000);
}
void loop() {
// Move all servos simultaneously
for (int angle = 90; angle <= 180; angle++) {
servo1.write(angle);
servo2.write(180 - angle); // Opposite direction
servo3.write(angle / 2 + 45); // Half speed
delay(10);
}
delay(500);
for (int angle = 180; angle >= 90; angle--) {
servo1.write(angle);
servo2.write(180 - angle);
servo3.write(angle / 2 + 45);
delay(10);
}
delay(500);
}
Note about Timer conflicts: On Arduino Uno and Nano, using the Servo library disables analogWrite() on pins 9 and 10 because the library takes over Timer 1. On Arduino Mega, servos use Timers 1, 3, 4, and 5, so the affected pins differ. If you need PWM on pins 9/10 alongside servos on Uno, consider using the VarSpeedServo library which has better timer management.
Advanced Tips and Common Mistakes
1. Always Calibrate Your Servo’s Pulse Range
Not all servos respond to the exact same pulse width range. Use myServo.attach(pin, minPulse, maxPulse) to specify your servo’s actual range. Typical values are 544–2400µs for standard servos, but cheap hobby servos can vary widely. Test with writeMicroseconds() to find your servo’s actual 0° and 180° positions before building anything mechanical.
2. Use detach() to Stop PWM Signal
When a servo reaches its final position and you do not need it to hold actively (for servos with physical stops), call myServo.detach(). This stops the PWM signal and frees the timer. The servo will hold position mechanically via its gearbox. This reduces current draw and eliminates the buzzing sound some servos make while holding position.
3. Add a Capacitor Across Servo Power
Place a 100µF to 470µF electrolytic capacitor across the servo’s power and ground leads (as close to the servo connector as possible). Servo motors create voltage spikes when they stall or change direction. The capacitor absorbs these spikes and prevents them from resetting your Arduino.
4. Servo Buzzing at Rest
If your servo buzzes or vibrates while stationary, it means the PWM signal is slightly off from the servo’s neutral point. Fine-tune with writeMicroseconds(1500) (standard neutral) or adjust until it stops. Also check your power supply — underpowered servos buzz continuously.
5. Jerky Motion at Low Speeds
The Servo library’s write() function takes integer angles. At very slow sweeps, you will see stepping because it can only move in 1° increments. Use writeMicroseconds() for sub-degree resolution, which gives you approximately 2000 steps over the full range instead of 180.
Frequently Asked Questions
How many servos can I control with Arduino Uno?
The Arduino Servo library supports up to 12 servos on Arduino Uno and Nano. However, powering more than 2–3 servos from the Arduino’s onboard 5V regulator will cause brownouts. Use an external 5V supply for the servo power rails and share only the ground with Arduino.
Why does my servo jitter when I run other code?
Jitter is caused by interruptions in the PWM signal timing. Long delay() calls or lengthy code in loop() can interrupt the servo library’s timer. Restructure your code to avoid delays longer than a few milliseconds, or use the millis()-based non-blocking approach shown above. Also check for electrical noise from other components — add decoupling capacitors.
What is the difference between write() and writeMicroseconds()?
write(angle) accepts an integer from 0 to 180 and maps it to a pulse width internally (typically 544–2400µs). writeMicroseconds(us) lets you specify the exact pulse width in microseconds (typically 500–2500) for finer control. For most projects, write() is sufficient. For precision applications like camera gimbals or robot joints, use writeMicroseconds().
Does the Servo library work with continuous rotation servos?
Yes, but differently. Continuous rotation servos do not have position stops — instead, write(90) stops the servo, write(0) runs it full speed one direction, and write(180) runs it full speed the other direction. Values between 0–90 and 90–180 control speed in each direction. The exact neutral point may need tuning with a small screwdriver on the servo’s potentiometer.
Can I use the Servo library on Arduino Nano?
Yes, the Servo library works identically on Arduino Nano as on Uno — they use the same ATmega328P microcontroller. All 12 servo capability is available. Note the same Timer 1 limitation applies: analogWrite() on pins 9 and 10 will not work while the Servo library is active.
Conclusion
The Arduino Servo library makes servo control accessible to beginners while offering enough depth — through writeMicroseconds(), easing functions, and multi-servo coordination — for advanced robotics and automation projects. Start with the basic sweep to understand how servo attachment and angle commands work, then layer in millis()-based non-blocking code and sinusoidal easing for production-quality motion.
Whether you are building your first robotic arm or designing an automated camera rig, smooth and precise servo control starts with understanding these fundamentals.
Ready to start your servo project? Browse our full range of Arduino boards and accessories at Zbotic.in — all sourced from trusted manufacturers and delivered fast across India.
Add comment