Motors and Servos for Robotics Explained Simply

Robot BuildingBy November 9, 2026Fact-checked by Hugo Lindgren
Motors and Servos for Robotics Explained Simply

By Fact-checked by Hugo Lindgren Published

A $5 micro servo works on the same idea as the axis motor of an industrial milling machine: a motor, a position sensor and a circuit that keeps correcting until the shaft is exactly where it was told to be. In short, a DC motor spins when you power it, a stepper moves in fixed steps, and a servo measures its own position and holds the angle you ask for. This guide covers how each one works, which to pick, which driver it needs and how to power it from an Arduino, ESP32 or Raspberry Pi without jitter or resets.

BoardsArduino Uno, ESP32, Pi
LevelBeginner
Key partsSG90, MG996R, TB6612FNG
Servo signal50 Hz, 1-2 ms
Last checkedNovember 9, 2026

Key takeaways

  • A servo is a motor, gearbox, position sensor and control circuit in a negative-feedback loop.
  • Hobby servos sense position with a potentiometer. Industrial servos use an encoder and a separate drive.
  • Servos read a 50 Hz signal, and a pulse of about 1.5 ms puts the horn in the center.
  • An MG996R can pull about 2.5 A when stalled, roughly five times what an Arduino 5V pin can supply.
  • Use a separate 5-6 V supply for servos, with its ground tied to the board ground.

Fact-checked

We checked these key facts against the sources named, on November 09, 2026:

  • The board should then show up at address 0x40 when you run i2cdetect -y 1 (source: espboards.dev)
  • The TowerPro MG996R datasheet lists roughly 500-900 mA running and about 2.5 A at stall at 6 V (source: people.ece.cornell.edu)
  • An Arduino’s 5V pin can realistically supply only about 500 mA, especially when the board runs from USB (source: industrialmonitordirect.com)
  • An MG996R rated at 11 kg·cm can hold 11 kg at 1 cm from the center, but only about 1.1 kg at the end of a 10 cm arm (source: towerpro.com.tw)
  • A standard positional servo can’t, because its potentiometer and end stops limit it to about 180° (or 270° on wide-range models) (source: makezine.com)

Motors and servos in one minute

All three are electric motors. They differ in how much the motor knows about its own position. A DC motor knows nothing, a stepper assumes it moved the steps it was told to, and a servo checks its actual position and corrects any error.

  • DC motor: apply voltage and it spins. Reverse the polarity and it spins the other way. Speed depends on voltage and load. Rule of thumb: use it when you need continuous rotation, such as wheels, fans or pumps.
  • Stepper motor: the driver energises its coils in sequence and the shaft moves a fixed angle per pulse, commonly 1.8°, which is 200 steps per revolution. Rule of thumb: use it when you need repeatable positions with no sensor, such as 3D-printer axes.
  • Servo: a motor with a gearbox, a sensor and a control circuit in one case. You send a position command and it holds that position against load. Rule of thumb: use it when you need to reach an angle and stay there, such as robot arm joints, steering or pan-tilt heads.

People searching “DC motor and servo motor” are usually asking about this split. A servo usually contains a small DC motor. What makes it a servo is the feedback loop around that motor. The decision table in the comparison section below sets out the choice for each common robotics job.

How a servo works: the closed loop

A servo compares where its output shaft is with where you told it to be, and drives the motor to shrink the difference. This is negative feedback: the correction always works against the error. Some explainers call it positive feedback. That is wrong, because positive feedback would push the shaft further away until it hit the end stop.

Here is the signal path inside a typical hobby servo:

 Control signal (PWM)                       Output horn
 from Arduino/ESP32/Pi                           ^
        |                                        |
        v                                        |
 +----------------+    motor drive    +-------+  |  +-------------+
 | Control board  | ----------------> | DC    |--+--| Gear train  |
 | (compares      |                   | motor |     | (reduction) |
 |  target vs     |                   +-------+     +------+------+
 |  actual)       |                                        |
 +----------------+                                        v
        ^                                        +------------------+
        |        actual position (voltage)       | Potentiometer on |
        +--------------------------------------- | the output shaft |
                                                 +------------------+

The loop runs continuously:

  1. Command: the control board reads the pulse width on the signal wire and turns it into a target position.
  2. Measure: the potentiometer, which is mechanically linked to the output shaft, gives a voltage that represents the actual position.
  3. Error: the board subtracts actual from target. The sign of the result gives the direction and its size shows how far off the shaft is.
  4. Correct: the board drives the motor in the direction that reduces the error, harder when the error is large.
  5. Repeat: once the error is close to zero (inside a small “deadband”), the motor stops.

That is also why a servo pushes back when you twist the horn by hand. As soon as you move it, the sensor reports an error and the board powers the motor against your hand. The holding force you feel is the loop at work, and it costs current the whole time the load is pushing.

Inside a hobby servo (potentiometer)

Hobby servos such as the TowerPro SG90 and TowerPro MG996R sense position with a potentiometer, not an encoder. The pot sits on the final output gear, so it turns through the same angle as the horn. Some descriptions of the SG90 say it has an encoder. It doesn’t. A cheap pot plus a small comparator or microcontroller is what keeps hobby servos so inexpensive.

The pot is also what limits travel to around 180°. A potentiometer has a physical end, and the gear train usually has a stop to protect it. The pot is the part that wears out first, which shows up as twitching or drift on old servos.

The gear train trades speed for torque. The small DC motor spins fast with little force, and the reduction gears turn that into a slow output with enough torque to lift an arm. For a closer look at the coils, magnets, brushes and commutator inside that tiny motor, see the separate guide to electric motor parts.

Inside an industrial servo (encoder and drive)

An industrial servo is a motor with an encoder on the shaft, wired to a separate box called a servo drive. The encoder reports position as digital counts. Incremental encoders count pulses from a reference point, and absolute encoders report a unique position at every angle. Neither has the end stop a potentiometer has, so the motor can turn any number of revolutions and still know where it is.

The drive usually runs several nested loops. A fast current loop sits inside a velocity loop, which sits inside a position loop, and each is commonly tuned with PID controller gains (proportional, integral, derivative). This is how CNC milling machines and industrial robot arms move heavy loads fast and stop within tiny fractions of a millimetre. Manufacturers such as Yaskawa, Siemens and Mitsubishi Electric sell the motor and drive as a matched pair.

The principle is the same as in a $5 hobby servo: command, measure, error, correct. The sensor resolution, the power and the sophistication of the control maths are what scale up.

The three wires and their colours

Every standard hobby servo has three wires: power, ground and signal. The colours vary by brand, but the order on the plug is almost always the same, with power in the middle. That means a reversed plug usually doesn’t put voltage on the signal pin.

Wire Common colours Connects to Notes
Ground Brown or black Supply negative and board GND Must be shared with the controller
Power (V+) Red 4.8-6 V supply (check your servo) Middle wire on most plugs
Signal Orange, yellow or white A GPIO pin or PCA9685 channel Carries pulses, almost no current

The control signal: 50 Hz and 1-2 ms pulses

Hobby servos expect one pulse every 20 ms, which is 50 pulses per second (50 Hz). The width of each pulse sets the position, not the frequency. A pulse of about 1.5 ms means center, about 1 ms means one end and about 2 ms means the other in the textbook version. Real servos often accept a wider range.

|<------------------- 20 ms frame (50 Hz) ------------------->|
 _____
|     |_______________________________________________________|  1.0 ms  -> one end
 _______
|       |_____________________________________________________|  1.5 ms  -> center
 _________
|         |___________________________________________________|  2.0 ms  -> other end

The servo only cares about the high time. The SG90 datasheet copies list the 50 Hz (20 ms) frame, and most servos tolerate some variation in frame length. What they don’t tolerate is noise on the pulse edges, because a few microseconds of wobble in width becomes visible twitching at the horn.

Pulse width to angle

The table below shows how a typical positional servo and a continuous-rotation servo read the same pulses. Treat the end values as starting points to calibrate from, not guarantees.

Pulse width Positional servo Continuous-rotation servo
~500 µs Far end (about 0°) on servos that accept wide pulses Full speed, one direction
1000 µs Textbook 0° end (about 45° on wide-range servos) Fast, one direction
1500 µs Center (90°) Stop (if the trim is set correctly)
2000 µs Textbook 180° end (about 135° on wide-range servos) Fast, other direction
~2400 µs Far end (about 180°) on servos that accept wide pulses Full speed, other direction

Did you know?

According to Make: magazine’s walkthrough of the Arduino Servo library, the default “0 to 180°” mapping actually sends pulses from 544 µs to 2400 µs. That is much wider than the textbook 1-2 ms.

Analog vs digital servos

Both types read the same 50 Hz signal. The difference is inside. An analog servo’s control board drives the motor in bursts tied to the incoming pulses. A digital servo has a microcontroller that re-checks the error and updates the motor drive many times faster than the input frame.

Analog servo Digital servo
Holding stiffness Softer, small deadband Stiffer, corrects tiny errors
Response Slightly slower to start Faster, more torque at small errors
Current at rest Lower Higher, because it keeps correcting
Noise Quiet at rest Often an audible whine or buzz when holding
Best for Battery projects, light loads Arms and steering under load

That buzzing is normal for a digital servo holding a load. If an analog servo buzzes at rest, look first for an overload or a pulse that drives it into its end stop.

Calibrating min and max pulses

SG90 datasheet copies don’t agree. One lists a 500-2400 µs range and another gives 0.9-2.1 ms with a 1.5 ms neutral. On top of that, individual units from the same batch differ. The only reliable numbers are the ones you measure on your own servo, with no load on the horn.

Build steps

  1. Power the servo from a separate 5 V supply and tie its ground to the board ground.
  2. Attach with wide limits, for example attach(9, 400, 2600), and send writeMicroseconds(1500).
  3. Lower the pulse in 50 µs steps, then 10 µs steps, watching the horn.
  4. Stop at the point where the horn stops moving or the servo starts to buzz. Add 20-30 µs back and note the value as your min.
  5. Repeat upward from 1500 µs to find max.
  6. Pass both values to attach(pin, min, max) in your real sketch.

Maker tip

Write the min and max on a piece of masking tape stuck to each servo. When it ends up in a different project, the calibration goes with it.

Servo types

There are four main types of servo motor: positional (the usual hobby servo), continuous rotation, linear, and industrial AC or DC servos. They all take a target as input, but only some of them really close the loop on position.

Positional servos

Positional servos rotate through a limited arc and hold an angle. That arc is usually about 180°, and 270° versions exist for joints that need more travel. The SG90 and MG996R are the standard maker examples. They’re the right choice for robot arm joints, grippers, steering linkages, pan-tilt camera heads and animatronic eyes and jaws.

Their specs differ by roughly an order of magnitude, which matters when you budget power:

Servo Voltage Stall torque Speed (s/60°) Current to budget Gears Good for
TowerPro SG90 4.8 V nominal ~1.8 kg·cm at 4.8 V (one TowerPro copy says 1.2) ~0.1 at 4.8 V Allow ~0.75 A each Plastic Pan-tilt, grippers, light linkages
TowerPro MG996R 4.8-7.2 V 9.4 kg·cm at 4.8 V, 11 kg·cm at 6 V ~0.17 at 4.8 V, ~0.14 at 6 V ~2.5 A stall at 6 V, 0.5-0.9 A running Metal Arm shoulders, steering, heavier joints

Torque in kg·cm means the force at a distance from the shaft. An MG996R rated at 11 kg·cm can hold 11 kg at 1 cm from the center, but only about 1.1 kg at the end of a 10 cm arm. Robot arm designs fail on this all the time, because the shoulder servo carries the whole arm and whatever it is holding at full length.

Continuous-rotation servos

A continuous-rotation servo looks the same but spins freely in either direction. Here the pulse width sets speed and direction, not angle. Around 1500 µs it stops, pulses further below it spin one way faster, and pulses further above spin the other way.

Did you know?

Adafruit’s Motor Selection Guide notes that a continuous-rotation hobby servo has its position feedback disabled. Strictly speaking, that means it is no longer a servo. It is a geared DC motor with a built-in speed controller.

That has real consequences. The servo can’t hold a position or tell you how far it has turned. Two “identical” continuous servos on a two-wheeled robot will run at slightly different speeds, so the robot drifts in a curve. The stop point also sits slightly off 1500 µs on many units, which is why some have a small trim pot to set the stop. If you need distance or heading, add wheel encoders or use DC gearmotors with encoders instead.

On the plus side, a continuous servo needs no separate motor driver. You can drive it straight from a signal pin with the same Servo library, which makes it a common choice for first wheeled robots.

Linear servos

A linear servo is a linear actuator with feedback. A small motor turns a lead screw or a gear rack, and a sensor (often a linear potentiometer) reports the extension. You command a position along a stroke instead of an angle. Typical uses are RC model mechanisms, small valves, camera sliders and animatronic movements where a straight push is cleaner than a horn and linkage.

AC vs DC servo motors

AC and DC servos differ in the motor inside. DC servos use a DC motor, often brushed, and suit low-voltage, low-cost and smaller-power jobs. AC servos use a brushless permanent-magnet motor powered through a servo drive. They dominate industrial work because they deliver more power for their size, need little maintenance and run smoothly at high speed.

Some guides say a DC servo’s speed is “set by the frequency of the applied voltage and the number of magnetic poles”. That describes AC synchronous motors. In a DC servo, speed follows the applied voltage (or PWM duty cycle) and the load. For a maker, the practical split is simple. Hobby servos are small DC servos with potentiometers. AC servos are what you meet on CNC milling machines, packaging lines and industrial robot arms, where they always come with an encoder and a matched drive.

DC motors, steppers and servos compared

Choose by the motion you need. Use DC motors for continuous spinning, steppers for repeatable positions without a sensor, and servos for holding an angle against load. The table puts every option side by side.

Motor Motion Feedback Driver needed Typical maker use Watch out for
Brushed DC (gearmotor) Continuous rotation, speed by PWM None (unless you add an encoder) H-bridge (TB6612FNG, L298N) Robot wheels, pumps, fans Speed varies with load and battery
Brushless DC Fast continuous rotation Hall sensors or back-EMF in the ESC ESC or BLDC driver Drones, high-speed spindles Needs a matched controller, high currents
Stepper Fixed steps (often 1.8°) None (open loop) Stepper driver (A4988) 3D-printer and CNC axes, camera sliders Missed steps go undetected, draws current at rest
Positional hobby servo ~180° (or 270°), holds angle Potentiometer None (direct PWM) or PCA9685 Arms, grippers, steering, pan-tilt Stall current, limited travel
Continuous-rotation servo Continuous, speed by pulse width None (removed) None (direct PWM) Small wheeled robots No position control, uneven speeds
Industrial AC/DC servo Any rotation, precise position Encoder Dedicated servo drive CNC, industrial robot arms Cost, setup and tuning

Which to use for common robotics jobs:

  • Robot wheels: DC gearmotors on a TB6612FNG. Add encoders if you need to drive a set distance. Continuous servos are fine for a first desk-sized robot.
  • Arm joints: positional servos. Use an MG996R or similar metal-gear servo at the shoulder and elbow, and micro servos at the wrist and gripper.
  • Pan-tilt camera heads: two SG90-class servos are enough for a small camera module.
  • 3D-printer and CNC axes: steppers with A4988-class drivers. Larger machines move to closed-loop steppers or AC servos.
  • Valves and latches: a positional servo for quarter-turn valves and locks. Use a linear servo for push-pull motion.

Brushed and brushless DC motors

A brushed DC motor switches current through its coils mechanically, using brushes that rub on a commutator. It is cheap and easy to control, because two wires and a voltage make it spin. Brushes wear out and cause electrical noise, which is why a 0.1 µF ceramic capacitor across the motor terminals is a common fix for interference.

A brushless DC motor moves the switching into electronics. An ESC (electronic speed controller) energises the coils in sequence, and the motor runs faster, cooler and longer. The trade-off is that you can’t connect it straight to an H-bridge. It needs a controller that matches its design.

Stepper motors

A stepper has several coil phases and a toothed rotor. Energising the phases in order pulls the rotor from one position to the next. A common NEMA 17 stepper moves 1.8° per full step, and drivers can split each step into microsteps for smoother motion.

Steppers are open loop. The driver assumes every step happened. If the load is too heavy or the acceleration too aggressive, the motor skips steps and the controller has no idea. That’s the familiar layer shift on a 3D print.

Servo vs stepper

Neither is better. They solve different problems. A stepper gives you cheap, repeatable positioning over many revolutions, with full holding torque at standstill, as long as you never overload it. A servo gives you feedback: it notices disturbances and corrects them. Hobby servos are limited to roughly 180°, and industrial servos are fast and efficient at high speed.

For a beginner the honest rule is this. Choose a stepper when the motion is repetitive, the load is known and you need more than one turn, such as on a lead screw. Choose a hobby servo when you need a joint to reach an angle quickly and you don’t want to write motion-control code. Choose a closed-loop or AC servo only when skipped steps would cost real money.

Every motor needs the right driver

A microcontroller pin can’t power a motor directly. Each general purpose input output pin is built to send signals. An Arduino Uno pin is rated around 20 mA continuous with 40 mA as the absolute maximum, and ESP32 and Raspberry Pi pins run at 3.3 V with even tighter limits. A small gearmotor draws hundreds of milliamps and a stalled one draws more. Motors also send voltage spikes back into whatever is driving them.

A driver sits between the pin and the motor. The pin sends low-current logic signals, and the driver switches the real motor current from a separate supply.

Driver Type Max voltage Continuous current Voltage drop Best for
L298N Bipolar dual H-bridge 46 V 2 A per channel (4 A total) ~1.8-3 V, more near 2 A 12 V motors where efficiency matters less
TB6612FNG MOSFET dual H-bridge 13.5 V recommended (15 V absolute) ~1.2 A per channel, 3.2 A short peaks ~0.2-0.5 V Small gearmotors on battery robots
A4988 (Pololu carrier) Bipolar stepper driver, microstepping 8-35 V ~1 A per phase uncooled, up to 2 A with cooling Chopper-regulated current NEMA 17 steppers, printer axes
PCA9685 (Adafruit 16-Channel PWM/Servo Driver) 16-channel, 12-bit PWM generator over I2C 2.3-5.5 V logic, servo rail separate Signal only, servos draw from the V+ rail Signal only Many servos, Raspberry Pi projects

H-bridges for DC motors

An H-bridge is four switches arranged around the motor like the letter H. Closing one diagonal pair sends current one way, and closing the other pair reverses it. PWM on the enable or speed pin sets the speed, and switching the pairs sets the direction. Both the L298N and the TB6612FNG contain two H-bridges, so one board runs two motors.

They differ mostly in voltage drop. The L298N uses bipolar transistors, and ST’s datasheet shows the high-side and low-side saturation voltages adding up to roughly 1.8 V at 1 A and several volts near 2 A. Vendor comparisons put the typical loss at 1.8-3 V. A 6 V motor on a 7.4 V battery can end up seeing only about 4.5 V, and the rest becomes heat. The TB6612FNG uses MOSFETs and drops only about 0.2-0.5 V. In a bench test posted on the Makeblock forum, the L298N measured about 59% efficient at 9 V, while the TB6612FNG measured 80-90%.

The TB6612FNG’s limits are lower, though. Toshiba’s datasheet gives 1.2 A average and 3.2 A in short pulses per channel, with a recommended motor supply of 2.5-13.5 V. For motors above that, look at higher-current MOSFET drivers rather than falling back to the L298N.

Stepper drivers

A stepper driver takes two logic signals, STEP and DIR, and handles the coil sequencing and current limiting itself. The Pololu A4988 carrier runs motors from 8-35 V. It has full, 1/2, 1/4, 1/8 and 1/16 microstepping and a small potentiometer that sets the current limit. Set that limit before you connect the motor, and fit an electrolytic capacitor of at least 47 µF across the motor supply. Pololu warns that long power leads can cause voltage spikes that destroy the chip.

PCA9685 for 16 servos

The PCA9685 is a dedicated PWM chip. It generates 16 independent channels of 12-bit (4096-step) PWM and takes commands over I2C, so it uses only two signal pins on your board. Set it to about 50 Hz for servos. Its adjustable frequency range runs roughly from 24 Hz to 1526 Hz. The Adafruit 16-Channel PWM/Servo Driver board puts the chip on a breakout with three-pin servo headers and a separate V+ terminal for servo power.

It solves two problems at once. You can control many servos with two wires, and the pulses come from a hardware timer, so they stay steady even when your Raspberry Pi is busy running Python.

Maker tip

For more than a few servos, or for any servo on a Raspberry Pi, use a PCA9685 board set to 50 Hz instead of GPIO PWM. It removes most timing jitter in one step.

Powering motors and servos without resets

Most motor and servo problems are power problems. A servo or motor that starts or stalls pulls a surge of current. If it shares a supply with your microcontroller, the voltage sags, the board browns out and resets, and the servo twitches. The fix is a separate supply sized for stall current, with its ground tied to the board ground.

Running vs stall current

Running current is what a motor draws while it moves freely. Stall current is what it draws when it is blocked or just starting, and it is many times higher. The TowerPro MG996R datasheet lists roughly 500-900 mA running and about 2.5 A at stall at 6 V. Every servo is briefly near stall at the moment it starts moving, and a joint holding a heavy arm can sit near stall for as long as it holds.

An Arduino’s 5V pin can realistically supply only about 500 mA, especially when the board runs from USB. One MG996R at stall pulls five times that. Even an SG90 can push the board over the edge when the servo jerks to a new position. That is the cause of the “servos sucking power from Arduino, Arduino freezing” threads.

Power check

An MG996R can draw about 2.5 A at stall (6 V). Never power one from the Arduino 5V pin, and size your supply for every servo stalling at once.

Wiring a separate supply

The pattern is the same on any board. Servo power comes from its own supply, the signal comes from the board, and the two grounds are joined.

From To Wire purpose
External 5-6 V supply (+) Servo red wire(s) Servo power
External supply (−) Servo brown/black wire(s) Servo ground
External supply (−) Arduino GND Common ground, the signal reference
Arduino D9 Servo signal (orange/yellow) Position pulses
470-1000 µF electrolytic capacitor Across servo + and − near the servos Absorbs startup current spikes

People often ask, “Do I need to connect the grounds if the servo has its own supply?” Yes. The signal is a voltage measured against ground. Without a shared ground the servo has no reference, and it will twitch, ignore commands or move unpredictably. Join only the grounds. Never connect the two positive rails.

Mind the polarity on the electrolytic capacitor and use one rated well above your supply voltage, such as 10 V or 16 V for a 6 V rail.

Worked example: 4-servo robot arm

Take a desktop arm with an MG996R at the base and shoulder, and SG90s at the wrist and gripper. Budget for the worst case, which happens at power-up when every servo jumps to its start position at once.

Joint Servo Stall budget
Base MG996R 2.5 A
Shoulder MG996R 2.5 A
Wrist SG90 0.75 A
Gripper SG90 0.75 A
Total 6.5 A

A 5 V supply rated for at least 7 A covers this, and a 10 A unit gives headroom for heat and aging. Running at 5 V instead of 6 V costs the MG996Rs some torque, but it keeps the SG90s inside every datasheet copy’s voltage rating. Feed the supply into a PCA9685 V+ terminal or a power rail, fit a 1000 µF capacitor across it, and run a ground wire to the controller.

Then check the shoulder torque. If the arm and payload weigh 300 g and their center of mass sits 12 cm from the shoulder, the shoulder needs 0.3 × 12 = 3.6 kg·cm just to hold. That fits within an MG996R’s rating, but it holds the servo well above running current. That is exactly why the supply has to be sized for stall current.

Maker tip

Size your supply for stall current, not running current. Budget about 2.5 A per MG996R at 6 V, and power the controller from its own USB or regulator.

A common question is whether you can share a USB power bank between the Arduino and the servo. It works for one or two micro servos if the bank can deliver 2 A. But the servo’s startup surge pulls the shared 5 V rail down and can reset the board. Use a bank with two outputs (one for the board, one for the servos, grounds joined) or put a bulk capacitor at the servo end. Some power banks also switch off when the current draw is low, which looks like a random shutdown when the robot sits idle.

Motors and servos with Arduino

On an Arduino Uno, the built-in Arduino Servo library handles the 50 Hz timing for you. You call attach() to pick a pin, write() to set an angle and writeMicroseconds() to set an exact pulse. The library supports up to 12 servos on most boards. It uses Timer1 on the Uno, which disables analogWrite() on pins 9 and 10, so plan your motor pins around that.

Servo sketch

The minimal sweep sketch moves a servo from 0° to 180° and back. It sets the start position before attach() so the servo doesn’t jump at power-up.

\#include <Servo.h>

Servo arm;                       // one Servo object per servo

void setup() {
  arm.write(90);                 // set the start position first
  arm.attach(9, 544, 2400);      // pin 9, min and max pulse in µs (library defaults)
}

void loop() {
  for (int angle = 0; angle <= 180; angle++) {
    arm.write(angle);
    delay(15);                   // gives the servo time to follow
  }
  for (int angle = 180; angle >= 0; angle--) {
    arm.write(angle);
    delay(15);
  }
}

attach(pin, min, max) stretches or narrows the 0-180° mapping to your servo’s real limits. If your servo stops short of a full 180°, widen min and max. If it buzzes at either end, narrow them.

To calibrate, use writeMicroseconds() and type pulse values into the Serial Monitor (set it to 115200 baud and “Newline”):

\#include <Servo.h>

Servo s;

void setup() {
  Serial.begin(115200);
  s.attach(9, 400, 2600);        // wide limits so writeMicroseconds isn't clamped
  s.writeMicroseconds(1500);     // start at center
  Serial.println("Type a pulse width in microseconds (400-2600):");
}

void loop() {
  if (Serial.available()) {
    int value = Serial.parseInt();
    if (value >= 400 && value <= 2600) {
      s.writeMicroseconds(value);
      Serial.print("Pulse: ");
      Serial.println(value);
    }
  }
}

Move out from 1500 in small steps and stop the moment the servo buzzes against its end stop. Holding it there heats the motor and strips plastic gears. On a continuous-rotation servo, the same sketch finds the exact stop point.

Smooth movement without delay()

The sweep sketch uses delay(), which freezes everything else, including sensors, buttons and other motors. The fix is to step the servo toward a target one degree at a time using millis(). Each pass through loop() checks whether it is time for the next step.

\#include <Servo.h>

Servo arm;
int current = 90;                        // where the servo is now (degrees)
int target  = 90;                        // where it should go
unsigned long lastStep = 0;
const unsigned long STEP_MS = 10;        // 10 ms per degree: about 1.8 s for 180°

void setup() {
  arm.write(current);
  arm.attach(9);
}

void loop() {
  // Demo: choose a new target every 3 seconds
  static unsigned long lastChange = 0;
  if (millis() - lastChange >= 3000) {
    lastChange = millis();
    target = (target == 20) ? 160 : 20;
  }

  // Move one degree toward the target when the step time has passed
  if (current != target && millis() - lastStep >= STEP_MS) {
    lastStep = millis();
    current += (target > current) ? 1 : -1;
    arm.write(current);
  }

  // Other code keeps running here: read sensors, drive motors, check buttons
}

Slower movement also cuts the startup current spike, because the servo never sees a big error all at once. On a robot arm, that one change often cures resets on its own.

DC motor speed and direction

A DC gearmotor needs an H-bridge. Here is a TB6612FNG wired to an Arduino Uno, using pin 5 for PWM so it doesn’t clash with the Servo library.

From To Wire purpose
Battery + (6-9 V, max 13.5 V) TB6612FNG VM Motor power
Arduino 5V TB6612FNG VCC Logic power
Battery − and Arduino GND TB6612FNG GND Common ground
Arduino D5 PWMA Speed (PWM)
Arduino D7 AIN1 Direction bit 1
Arduino D6 AIN2 Direction bit 2
Arduino D8 STBY High = driver enabled
AO1, AO2 Motor terminals Motor output
const int PWMA = 5;    // speed: a PWM pin, not 9 or 10 if Servo is also used
const int AIN1 = 7;
const int AIN2 = 6;
const int STBY = 8;

void setup() {
  pinMode(PWMA, OUTPUT);
  pinMode(AIN1, OUTPUT);
  pinMode(AIN2, OUTPUT);
  pinMode(STBY, OUTPUT);
  digitalWrite(STBY, HIGH);      // take the driver out of standby
}

// speed from -255 (full reverse) to 255 (full forward)
void drive(int speed) {
  if (speed >= 0) {
    digitalWrite(AIN1, HIGH);
    digitalWrite(AIN2, LOW);
  } else {
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, HIGH);
    speed = -speed;
  }
  analogWrite(PWMA, constrain(speed, 0, 255));
}

void brake() {
  digitalWrite(AIN1, HIGH);      // both inputs high = short brake
  digitalWrite(AIN2, HIGH);
  analogWrite(PWMA, 0);
}

void loop() {
  for (int s = 0; s <= 200; s += 5) { drive(s); delay(30); }   // ramp up
  delay(1000);
  brake();
  delay(500);
  drive(-150);                                                 // reverse
  delay(1500);
  brake();
  delay(1000);
}

Ramping the speed up instead of jumping to full power does the same job as the smooth servo pattern: it keeps the startup surge from pulling the supply down.

Servos with ESP32 and Raspberry Pi

Both boards use 3.3 V logic, and neither should power a servo from its own pins. Most SG90 and MG996R units respond to a 3.3 V signal. If one ignores the pulses or behaves erratically, a simple level shifter to 5 V fixes it. The bigger difference is how each board makes the pulses.

ESP32

On an ESP32, install the ESP32Servo library from the Arduino Library Manager. It mirrors the Arduino Servo API but generates pulses with the ESP32’s LEDC hardware PWM peripheral, so timing stays stable. The library’s documentation lists 16 LEDC channels on the original ESP32 and 6 on the ESP32-C3, so check your chip variant before planning a many-servo build.

From To Wire purpose
ESP32 GPIO 18 Servo signal Position pulses (3.3 V)
External 5 V supply (+) Servo red Servo power
External supply (−) Servo brown and ESP32 GND Common ground
\#include <ESP32Servo.h>

Servo pan;
const int SERVO_PIN = 18;

void setup() {
  pan.setPeriodHertz(50);              // standard 50 Hz servo frame
  pan.attach(SERVO_PIN, 500, 2400);    // replace with your calibrated limits
}

void loop() {
  pan.write(0);
  delay(1000);
  pan.write(90);
  delay(1000);
  pan.write(180);
  delay(1000);
}

Don’t feed servos from the dev board’s 5V or VIN pin. On most boards that is just USB power passing through, and a servo surge resets the ESP32 or interrupts Wi-Fi. Keep to pins that are safe as outputs and avoid the strapping pins used at boot. The guide to GPIO pins for Arduino, Raspberry Pi and ESP32 covers which ones those are.

Raspberry Pi

On a Raspberry Pi, gpiozero’s AngularServo class is the easiest start, but its default software PWM makes servos jitter. Linux pauses your program at unpredictable moments, the pulse width wobbles by a few microseconds and the servo follows the wobble. For years gpiozero itself warned users to switch to the pigpio pin factory, which generates hardware-timed pulses.

That advice has changed on current systems. The pigpio pin factory is reported as not compatible with Raspberry Pi OS based on Debian Trixie, and the pigpio package is missing from Trixie images. Current Raspberry Pi OS ships gpiozero with the lgpio backend instead. That still leaves you with two solid routes to jitter-free servos:

  1. Hardware PWM pins: the Pi has hardware PWM on GPIO 12 (physical pin 32), GPIO 13 (pin 33), GPIO 18 (pin 12) and GPIO 19 (pin 35). These need the PWM overlay enabled in /boot/firmware/config.txt and a library that uses hardware PWM.
  2. A PCA9685 board over I2C: this is the robust option. The Pi only sends I2C commands, and the chip produces steady pulses for up to 16 servos.

For quick tests, AngularServo works fine. It also solves another forum puzzle, “AngularServo only moves half the angle it should”. gpiozero defaults to a 1-2 ms pulse range, while many hobby servos need about 0.5-2.4 ms for their full travel. Widen the range:

from gpiozero import AngularServo
from time import sleep


servo = AngularServo(18, min_angle=-90, max_angle=90,
                     min_pulse_width=0.0005, max_pulse_width=0.0024)

while True:
    for angle in (-90, 0, 90, 0):
        servo.angle = angle
        sleep(1)
    servo.detach()          # stop pulses so the servo stops twitching at rest
    sleep(2)

For the PCA9685 route, wire it like this and use Adafruit’s ServoKit library (installed with pip as adafruit-circuitpython-servokit, inside a Python virtual environment):

From To Wire purpose
Pi 3.3 V (physical pin 1) PCA9685 VCC Chip logic power
Pi GND (physical pin 6) PCA9685 GND Common ground
Pi GPIO 2 / SDA (physical pin 3) PCA9685 SDA I2C data
Pi GPIO 3 / SCL (physical pin 5) PCA9685 SCL I2C clock
External 5-6 V supply PCA9685 V+ terminal Servo power
from adafruit_servokit import ServoKit kit = ServoKit(channels=16)                    # address 0x40, 50 Hz by default
kit.servo[0].set_pulse_width_range(500, 2400)  # your calibrated limits
kit.servo[0].angle = 90                        # positional servo on channel 0
kit.continuous_servo[1].throttle = 0.5         # half speed on channel 1

Enable I2C first with raspi-config. The board should then show up at address 0x40 when you run i2cdetect -y 1.

Troubleshooting: jitter, buzzing, resets and short travel

Most faults trace back to three causes: a weak or shared supply, a missing common ground or noisy pulse timing. The table maps the symptoms people report most often to fixes.

Symptom Likely cause Fix
Arduino resets when the servo, motor or relay turns on Startup surge browns out the shared 5 V rail Separate supply for loads, common ground, 470-1000 µF capacitor, ramp motion
Servo jitters and twitches heavily while the DC motor is running Motor noise and voltage sag on a shared supply Separate motor and servo supplies, 0.1 µF capacitor across motor terminals, keep motor wires away from signal wires
Servos sucking power from Arduino, Arduino freezing Servos powered from the 5V pin (about 500 mA available) Move servo power to an external 5-6 V supply sized for stall current
Servo moves randomly or ignores commands on its own supply Grounds not connected Join the supply ground to the board ground
Servo jittering and not turning fully on Raspberry Pi with gpiozero Software PWM timing plus a narrow default pulse range Hardware PWM pins or a PCA9685, and widen min/max pulse width
AngularServo only moves half the angle it should Default 1-2 ms range too narrow for the servo Set min_pulse_width and max_pulse_width to calibrated values
Servo buzzes and vibrates when it’s holding still Load near its limit, digital servo correcting, or pulse past the end stop Reduce load or lever length, narrow attach() limits, detach when idle if the joint doesn’t need holding
Servo travels less than 180° Pulse limits narrower than the servo’s real range Calibrate with writeMicroseconds() and pass the limits to attach()
Servo jumps at power-up No valid pulse until attach(), or start position not set Call write() before attach() and power servos after the controller starts
Continuous servo creeps at “stop” Neutral point not exactly 1500 µs Find the real stop with writeMicroseconds() or adjust the trim pot
DC motor weak on an L298N 1.8-3 V lost across the driver Switch to a TB6612FNG, or raise the supply within the motor’s rating

When you can’t tell supply from signal, measure the servo rail with a multimeter while the servo starts. If it dips below about 4.5 V, the problem is power, whatever the code looks like.

Where servos are used

Servos are used wherever something must reach a position and hold it. On the hobby side that covers RC car steering, aircraft control surfaces, animatronic faces, pan-tilt camera mounts, robot arms, walking robots and small valve or latch mechanisms. In industry, the same closed loop moves the axes of CNC milling machines, the joints of industrial robot arms, packaging and pick-and-place machines and the focus motors in camera lenses.

From hobby to industrial, the hardware changes in stages:

Stage Sensor Controller Typical job
Micro hobby servo (SG90) Potentiometer Small onboard board Pan-tilt, grippers
Standard metal-gear servo (MG996R) Potentiometer Onboard, often digital Arm joints, steering
Smart serial servos Magnetic or other sensor, position readback Onboard microcontroller with a serial bus Humanoid and hexapod robots
Industrial DC or AC servo High-resolution encoder External servo drive with tuned loops CNC, industrial robot arms

The concept you learn on a $5 servo carries over. When you later tune a PID loop on an encoder-equipped gearmotor, you are building by hand what an SG90 does in its tiny case. A sensible next step is to calibrate one servo, power it properly from a separate supply and get the non-blocking sketch running. That one setup removes the most common failures in Arduino projects that move.

FAQ

What is the difference between a motor and a servo?

A motor converts electrical power into rotation and has no sense of position. A servo is a complete system: a motor, a gearbox, a position sensor and a control circuit that compares the actual position with the commanded one and corrects the error. Most hobby servos contain a small brushed DC motor.

How does a servo motor work?

It runs a negative-feedback loop. The control board reads the pulse width, sets a target, measures the shaft with a potentiometer (or an encoder in industrial servos), and drives the motor to cancel the difference. It keeps doing this as long as it receives pulses, which is why it resists being pushed off position.

What are the types of servo motors?

The main types are positional servos (about 180° or 270°), continuous-rotation servos, linear servos and industrial AC or DC servos. Hobby servos are also split into analog and digital by their control electronics. Positional hobby servos are the default for maker robotics.

Servo vs stepper motor: which is better?

Neither in general. A stepper is better for repeatable multi-turn positioning with a known load, such as 3D-printer axes. A servo is better for reaching and holding an angle quickly, such as an arm joint, and it corrects disturbances that would make a stepper skip steps without anyone noticing.

Can I power a servo from the Arduino 5V pin?

Only a single micro servo with no load, for a quick test. The 5V pin realistically gives about 500 mA, and one MG996R can pull about 2.5 A at stall. Anything more needs a separate 5-6 V supply with its ground connected to the Arduino ground.

Why does my servo jitter?

The usual causes are a sagging supply, a missing common ground, noisy pulse timing (software PWM on a Raspberry Pi) or pulses that drive the servo into its end stop. Fix the power first, then the ground, then the signal source, then the pulse limits.

What is the PWM frequency for a servo?

Standard hobby servos use 50 Hz, which is one pulse every 20 ms. The pulse width, about 1 ms to 2 ms with 1.5 ms at center, sets the position. Many servos accept roughly 0.5-2.4 ms for full travel, so calibrate yours.

What is the difference between AC and DC servo motors?

A DC servo uses a DC motor and suits lower power and lower cost, which covers all hobby servos. An AC servo uses a brushless permanent-magnet motor run by a servo drive with encoder feedback. It is the standard in CNC and industrial robots because it delivers more power, runs at higher speed and needs little maintenance.

How much does a servo motor cost?

Hobby servos are cheap. Kiwi Electronics lists a TowerPro-branded SG90 at €5.49 before VAT, and generic multi-packs cost less per unit. A single MG996R sells for around $9 at retailers such as PiShop.ca, and multi-packs bring the price per servo down further. Industrial AC servos and their drives are priced in a different class entirely.

Can a servo rotate 360 degrees?

A standard positional servo can’t, because its potentiometer and end stops limit it to about 180° (or 270° on wide-range models). A continuous-rotation servo spins all the way round, but it gives up position control in exchange. Multi-turn and industrial servos with encoders can rotate any number of turns and still hold an exact position.

Notes on this article

Written by

Rohan Easterbrook writes about coding and robots for Artoo Maker Lab, covering Arduino sketches, MicroPython, motor control and beginner robot kits. He checks code examples against official language references, board documentation and release notes, and he cares about explaining why each line works so readers can adapt projects instead of copying them blindly.

Covers: Robot Building, Coding for Makers

  • Fact-checked by Hugo Lindgren against the sources listed below before publication.
  • Published

Fact-checking

  • Researched from 8 sources, listed below.
  • Every claim is checked by Hugo Lindgren; anything we cannot confirm is corrected, labelled or removed.
Sources (8)
  1. Arduino's Servo Library: Angles, Microseconds, and Optional Command Parameters (Make:) (makezine.com)
  2. Arduino Servo library reference: writeMicroseconds() (ccrma.stanford.edu)
  3. SG90 micro servo datasheet (bit.nkust.edu.tw)
  4. SG90 datasheet copy (Universität Hamburg) (tams.informatik.uni-hamburg.de)
  5. TowerPro MG996R datasheet (courses.ece.cornell.edu)
  6. Servo jitter with SparkFun Servo Trigger (SparkFun Community) (community.sparkfun.com)
  7. Troubleshooting Arduino resets randomly (Universal-Solder) (universal-solder.ca)
  8. PCA9685 16-Channel 12-Bit I2C PWM Servo Driver Module User Guide (envistiamall.com)