Hardware Atlas
Servo Motor
A servo motor is a closed-loop actuator that holds a precise angular position. Used in robotic joints, grippers, steering mechanisms, and any system where position — not just speed — must be controlled.
You will understand
- How a servo motor uses internal feedback to hold a commanded angle
- The PWM protocol that controls servo position
- SG90 specifications, wiring, and safe operating limits
- How to write smooth, controlled motion code that avoids mechanical shock
- How servos fit into a robotic manipulator or bipedal system
What is a servo motor?
A servo motor is an actuator that accepts a commanded position and uses internal feedback to hold that position against external forces. Unlike a DC motor — which spins freely at a speed proportional to voltage — a servo does not move continuously. It moves to a specific angle and stays there.
The word servo comes from the Latin servus (servant) and entered engineering through Norbert Wiener's cybernetics work in the 1940s. The feedback principle — compare actual state to desired state, correct the error — is the foundation of all closed-loop control systems, from thermostats to space telescopes.
Inside every servo is a three-component feedback loop: a motor that can drive the shaft, a potentiometer that reads the current angle, and a control circuit that compares the two. When you command 90°, the circuit drives the motor until the pot reads 90°, then cuts power. If something pushes the shaft away, the circuit detects the error and corrects it. This is the same principle used in every industrial robot arm joint — the servo just makes it visible at a scale you can touch.
Why it matters for AI builders
In robotic manipulation, every joint that must hold a position against gravity uses a servo or its industrial equivalent. The diffusion policy and other modern robot learning algorithms output joint angle targets — a servo is what executes those targets in the physical world.
Key roles in physical AI systems:
- Manipulator joints — each degree of freedom in a robot arm is one servo
- Gripper mechanism — open/close commands map directly to servo angle
- Camera pan/tilt — gaze direction control for visual systems
- Bipedal balance — ankle and hip servos respond to IMU feedback
- Soft robotics — servo-actuated tendons drive compliant finger structures
Working principle
Inside an SG90 (and all hobby servos):
- Motor + gearbox — a small brushed DC motor drives a plastic gear train that increases torque and reduces speed
- Potentiometer — mechanically coupled to the output shaft; its resistance encodes current angle (0°–180°)
- Control IC — compares the pot voltage (actual position) to the PWM pulse width (commanded position), drives the motor to minimise the error
Servo Control Loop
MCU
PWM signal
Control IC
Pulse → angle target
H-Bridge
Drive motor
Gearbox
Torque × speed
Output shaft
Physical angle
Potentiometer
Angle feedback
PWM encoding. The control IC reads the pulse width of the incoming PWM signal:
- 1.0 ms pulse → 0°
- 1.5 ms pulse → 90° (centre)
- 2.0 ms pulse → 180°
- Period: 20 ms (50 Hz repetition rate)
The pulse width, not the duty cycle percentage, encodes the angle.
Output shaft and control horn at top. Gear train visible through housing. Three-wire JST connector: red = VCC (4.8–6V), brown/black = GND, orange = PWM signal. PWM waveform shows 1–2 ms pulse width at 20 ms period.
Key parameters (SG90)
| Parameter | Value | Notes |
|---|---|---|
| Operating voltage | 4.8 – 6.0 V | Do NOT power from Arduino 5V pin at load |
| Stall torque | 1.8 kg·cm @ 4.8V | 2.2 kg·cm @ 6V |
| No-load speed | 0.1 s / 60° | At 4.8V — faster at 6V |
| PWM pulse width | 1.0 – 2.0 ms | Varies by manufacturer — may be 0.5–2.5 ms |
| PWM frequency | 50 Hz | 20 ms period — some servos accept 333 Hz |
| Angular range | 0° – 180° | Mechanical hard stops — do not command past limits |
| Gear material | Plastic (nylon) | Metal gear versions available — more reliable under load |
| Weight | 9 g | 14 g with metal gears |
| Stall current | ~650 mA | At stall — wire directly to power, not MCU pin |
Pinout
| Pin | Label | Type | Description |
|---|---|---|---|
| 1 | VCC | power | 4.8–6V supply — connect to external power rail, not Arduino 5V |
| 2 | GND | ground | Ground — must share ground with Arduino (common ground) |
| 3 | SIG | digital | PWM signal — connect to Arduino digital pin (any pin supporting digitalWrite) |
Wire colour conventions:
- Red or orange = VCC
- Brown or black = GND
- Yellow or orange = Signal (varies — check your specific servo's datasheet)
Wiring
Power note. A single SG90 at light load can run from the Arduino 5V pin. Two or more servos under load will brownout the Arduino. Always use an external power source (4× AA batteries or a bench supply) for multiple servos, and ensure a common ground between the Arduino and the power rail.
Code
Basic position control
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9); // attach servo to pin 9
myServo.write(90); // move to centre position at startup
delay(500); // allow servo to reach position
}
void loop() {
myServo.write(0); // go to 0 degrees
delay(1000);
myServo.write(90); // go to 90 degrees (centre)
delay(1000);
myServo.write(180); // go to 180 degrees
delay(1000);
}
Smooth sweep — avoiding mechanical shock
Commanding a servo from 0° to 180° in one step causes maximum mechanical stress and current spike. Ramp the angle instead:
#include <Servo.h>
Servo myServo;
void smoothMove(Servo &s, int from, int to, int stepDelay = 15) {
int step = (to > from) ? 1 : -1;
for (int pos = from; pos != to; pos += step) {
s.write(pos);
delay(stepDelay); // 15ms per degree = ~2.7s for 180°
}
s.write(to);
}
void setup() {
myServo.attach(9);
myServo.write(90);
delay(500);
}
void loop() {
smoothMove(myServo, 90, 0);
delay(500);
smoothMove(myServo, 0, 180);
delay(500);
smoothMove(myServo, 180, 90);
delay(500);
}
Joystick to servo mapping
#include <Servo.h>
Servo myServo;
const int JOY_PIN = A0;
void setup() {
myServo.attach(9);
}
void loop() {
int raw = analogRead(JOY_PIN); // 0 – 1023
int angle = map(raw, 0, 1023, 0, 180); // scale to servo range
myServo.write(angle);
delay(20);
}
Test procedure
Servo Verification
Wire servo per the wiring section. Power the servo from external 5V or 4× AA batteries, not the Arduino 5V pin.
Upload the basic position control sketch. Observe the servo sweep to 0°, 90°, and 180° with 1-second pauses. A healthy servo will reach each position cleanly without buzzing or hunting.
Manually resist the output shaft while it holds 90°. You should feel torque resisting your force. The motor will briefly spike current as it corrects — this is normal closed-loop behaviour.
Open Serial Monitor and add Serial.println(myServo.read()) to verify the commanded angle is what the library reports.
Test the full range: command 0° and check for mechanical hard-stop contact (buzzing at limit). If the servo buzzes continuously at 0° or 180°, your actual range is narrower than 0–180 — adjust your minimum and maximum pulse widths.
Common mistakes
- Powering multiple servos from Arduino 5V — each servo draws up to 650 mA stall current. Three servos can draw 2 A, which is 4× the Arduino's 5V regulator limit. Use external power.
- Missing common ground — if the servo and Arduino have separate power but no shared GND, the PWM signal has no reference and the servo behaves erratically or does not move.
- Commanding past mechanical limits — servos have internal hard stops. Commanding 0° when the mechanical limit is 5° causes the motor to stall against the stop, drawing maximum current and overheating.
- Using
delay()in the main loop — delay() blocks all other code. Usemillis()for non-blocking servo updates in multi-sensor systems. - Ignoring pulse width variation — cheap servos often respond to 0.5–2.5 ms rather than the standard 1–2 ms. Use
myServo.writeMicroseconds(1500)for precise control.
Failure Signs
- Continuous buzzing / humming at rest — the servo is hunting: PWM noise, imprecise pulse width, or mechanical binding is preventing it from reaching the target position
- Erratic random movement — missing common ground, or signal line length too long without shielding
- No response to commands — check VCC (must be 4.8–6V), check common ground, check that
myServo.attach()was called beforemyServo.write() - Servo moves then immediately returns — two devices fighting for control of the same pin; check for conflicting
Servoobjects - Arduino resets when servo moves — brownout: servo is drawing too much current from the Arduino power rail, dropping the voltage below the reset threshold
- Stripped gears — plastic gears fail under shock loads or when commanded against hard stops repeatedly; upgrade to metal gear version
Robotics and AI use cases
Servo Motors in Physical AI Systems
- Robot arm joints — each degree of freedom (DOF) in a robotic manipulator maps to one servo. A 6-DOF arm requires 6 servos, each receiving angle targets from the inverse kinematics solver.
- Diffusion policy execution — modern imitation learning algorithms (Chi et al. 2023) output joint angle trajectories that are executed directly as servo write commands at 10–50 Hz.
- Gripper control — finger opening width is commanded as a servo angle. Vision models predict grasp pose; the gripper servo executes it.
- Head/camera pan-tilt — visual attention control: a tracking algorithm computes where to look, servo commands orient the camera.
- Bipedal balance — ankle servos counteract IMU-measured tilt using a PD controller, implementing real-time balance.
- Tendon-driven fingers — servo reels a cable attached to a soft finger, enabling compliant grasping.
Beginner project — Potentiometer-controlled servo
Control servo angle by turning a knob. This is the most fundamental human-in-the-loop motor control circuit.
Components: Arduino Uno, SG90 servo, 10kΩ potentiometer, external 5V power, breadboard, jumper wires.
Goal: Turning the pot from 0 to full maps the servo from 0° to 180°. Smooth, proportional response with no jitter.
Key learning: analogRead() → map() → myServo.write() — the canonical sensor-to-actuator pipeline.
Advanced project — 2-DOF pan-tilt face tracker
Mount two servos in a pan-tilt bracket with a camera. Run a face detection model (OpenCV haarcascade_frontalface_default) on a computer, send the face centroid coordinates over USB serial to Arduino, and use PD control to minimise the offset between the face position and the image centre.
Components: Arduino Uno, 2× SG90 servos, pan-tilt bracket, USB camera, laptop running Python/OpenCV.
Key learning: Serial communication bridge, PD control loop, coordinate frame transformation, non-blocking servo updates.
# Python side — send servo commands over serial
import cv2, serial, time
ser = serial.Serial('/dev/ttyUSB0', 9600)
cap = cv2.VideoCapture(0)
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
if len(faces):
x, y, w, h = faces[0]
cx = x + w // 2 # face centre x
cy = y + h // 2 # face centre y
pan = int(cx / frame.shape[1] * 180)
tilt = int(cy / frame.shape[0] * 180)
ser.write(f"{pan},{tilt}\n".encode())
time.sleep(0.05)