To successfully code an Arduino servo, you must first match the servo's stall torque to your mechanical load, power it via an external 5V/6V supply rather than the Arduino's onboard regulator, and use the Servo.h library to send 50Hz PWM pulses (typically 1000-2000µs). Skipping the mechanical sizing or power delivery steps will result in jitter, brownouts, and burnt-out driver boards before you ever debug a single line of code.
Sizing and Selecting the Right Servo for Your Load
Servos and steppers are fundamentally different architectures. A stepper motor holds position via magnetic detents and open-loop step counting, making it ideal for high-precision CNC or 3D printer axes. A hobby servo uses a closed-loop feedback system—an internal potentiometer reads the output shaft angle, and an internal H-bridge drives a DC motor to correct any error. You cannot treat them as interchangeable in code or hardware.
| Motor Type | Torque Curve | Control Needs | Approx. Cost (USD) | Best Load Profile |
|---|---|---|---|---|
| Hobby Servo (e.g., MG996R) | High stall torque, drops at speed | 50Hz PWM (1000-2000µs) | $5 - $15 | Robotic arms, pan/tilt, RC steering |
| Stepper (NEMA 17) | High holding torque, drops sharply at high RPM | Step/Dir pulses via driver (A4988/TMC2209) | $12 - $25 | 3D printers, linear actuators, CNC |
| DC Gearmotor | Linear torque/speed curve, max torque at stall | H-Bridge (L298N/TB6612) + Encoder for position | $8 - $20 | Drive wheels, conveyors, winches |
Sizing Rule of Thumb and Worked Example
When sizing a servo, calculate the static load torque, then apply a 2.0x safety factor to account for dynamic acceleration, friction, and gear backlash. Hobby servo torque is universally rated in kilogram-centimeters (kg·cm) or ounce-inches (oz·in).
Worked Load Example: You are building a robotic arm that must lift a 200g (0.2 kg) payload. The servo is mounted at the shoulder, and the center of mass of the payload is 15 cm away from the servo's output shaft.
- Static Torque: Mass × Distance = 0.2 kg × 15 cm = 3.0 kg·cm
- Required Torque (2.0x Safety Factor): 3.0 × 2.0 = 6.0 kg·cm
Selection: A micro SG90 (1.8 kg·cm) will instantly stall and overheat. An MG90S (2.2 kg·cm) will also fail. The standard MG996R (10-13 kg·cm) is the correct choice, providing enough headroom for smooth acceleration without drawing continuous stall current.
Wiring, Terminals, and Power Delivery
The physical layer is where most embedded projects fail. A standard hobby servo uses a 3-pin JR/Futaba connector. Terminal identification is strictly standardized across almost all manufacturers:
- Brown or Black: Ground (GND). Must be tied to the Arduino GND and the power supply GND.
- Red: VCC. Requires 4.8V to 6.0V DC. Never connect this to the Arduino's 5V pin if the servo is under mechanical load.
- Orange, Yellow, or White: Signal (PWM). Connects to an Arduino digital pin capable of hardware PWM (e.g., pins 3, 5, 6, 9, 10, 11 on the Uno).
Driver and Controller Demands
An Arduino Uno's ATmega328P can generate the 50Hz PWM signal natively via the Servo.h library, but its onboard 5V linear regulator maxes out around 500mA-800mA. A single MG996R under load can pull 2.5A of stall current. If you power a loaded servo from the Arduino 5V pin, the voltage will sag, triggering the ATmega's brownout detector and causing the microcontroller to reset continuously.
The Solution: For 1-2 standard servos, use a standalone 5V/6V UBEC (Universal Battery Elimination Circuit) or a 5V 3A buck converter. For projects requiring 3 or more servos, or high-precision multi-axis control, use a PCA9685 16-Channel I2C PWM Driver. The PCA9685 offloads the 50Hz timing from the Arduino's hardware timers, freeing up your code for other interrupts, and provides dedicated screw terminals for high-current servo power rails.
Failure Signatures to Watch For
- Hum or Jitter: Usually caused by 'ground bounce' (failing to share a common ground between the Arduino and the external servo supply) or excessive ripple on a cheap switching power supply.
- Overheat: The servo is physically blocked from reaching its target angle. The internal H-bridge continues to dump stall current into the motor windings to correct the error, melting the plastic gears or burning out the potentiometer wiper.
- Stall/Brownout: The Arduino resets or I2C buses crash when the servo moves. This is a voltage sag on the shared power rail due to inadequate wire gauge or an undersized power supply.
Coding Arduino Servo Logic: Core Commands and Edge Cases
When coding an Arduino servo, you are not sending an angle directly to the motor; you are sending a timed pulse width. The standard Arduino Servo library abstracts this, mapping 0-180 degrees to roughly 544µs to 2400µs. However, relying on the default write() mapping can cause mechanical binding at the extreme ends of the potentiometer's travel.
For production-grade code, use writeMicroseconds() to define exact physical limits, and use detach() to cut the PWM signal when the servo is stationary. This eliminates idle jitter and stops the servo from drawing continuous holding current, which drains batteries and generates heat.
#include <Servo.h>
Servo shoulderServo;
const int SERVO_PIN = 9;
// Define exact physical limits to prevent potentiometer over-travel
const int MIN_PULSE = 600; // Microseconds for 0 degrees
const int MAX_PULSE = 2300; // Microseconds for 180 degrees
void setup() {
shoulderServo.attach(SERVO_PIN, MIN_PULSE, MAX_PULSE);
}
void loop() {
// Move to 90 degrees (approx 1450us)
shoulderServo.writeMicroseconds(1450);
delay(2000); // Wait for mechanical movement to settle
// Detach to stop holding current and eliminate idle jitter
shoulderServo.detach();
delay(3000);
// Re-attach before next movement
shoulderServo.attach(SERVO_PIN, MIN_PULSE, MAX_PULSE);
shoulderServo.writeMicroseconds(900); // Move to ~30 degrees
delay(2000);
shoulderServo.detach();
delay(3000);
}
Frequently Asked Questions (FAQ)
Why is my Arduino resetting when coding a servo under load?
This is a classic brownout. When a servo starts moving against a load, it draws a massive inrush current (often 1.5A to 2.5A for standard metal-gear servos). If the servo is powered from the Arduino's 5V pin, this current spike drops the voltage below the ATmega328P's brownout threshold (typically ~4.3V), forcing a hardware reset. Always use an external 5V/6V power supply rated for at least 2A per servo, and ensure the external supply's ground is wired directly to the Arduino's GND pin.
How do I stop a servo from jittering in my Arduino code?
Jitter is rarely a code logic error; it is almost always a hardware or timing issue. First, ensure your power supply has adequate decoupling capacitors (a 470µF electrolytic capacitor across the servo's VCC and GND wires near the connector works wonders). Second, avoid using delay() in complex sketches where other interrupts might interfere with the hardware timer driving the PWM. If using a software-driven pin on a busy board, switch to a hardware I2C driver like the PCA9685, which generates the 50Hz pulse independently of the Arduino's main loop.
Can I code an Arduino servo to rotate a full 360 degrees?
Standard hobby servos are mechanically limited to roughly 180 to 270 degrees by the physical sweep of their internal potentiometer and hard stops on the output gear. If you need continuous 360-degree rotation, you must purchase a 'Continuous Rotation Servo' (like the Parallax Continuous Rotation Servo). In these models, the potentiometer is disconnected from the output shaft. When coding a continuous rotation servo, the write() value no longer represents an angle; instead, 90 means 'stop', 0 means 'full speed reverse', and 180 means 'full speed forward'.
What is the difference between coding a servo and a stepper on Arduino?
Coding a servo relies on the Servo.h library to generate a 50Hz PWM signal where the pulse width dictates the absolute target angle. The servo's internal circuitry handles the closed-loop PID control to reach that angle. Coding a stepper requires a dedicated driver (like an A4988 or TMC2209) and involves sending discrete digital 'Step' pulses and setting a 'Direction' pin. The Arduino must track the stepper's position in software (open-loop), counting every pulse sent, whereas a servo inherently knows its position via its internal feedback loop.






