BysMax

Arduino Servo Motor Control — Wiring, Code & Angles Explained

14 min

A servo motor is a motor that moves to a specific angle on command. Unlike DC motors that spin continuously, servos rotate to 0°, 90°, 180° — or any position in between. The SG90 is the standard starter servo; the MG996R is the metal-gear version for heavier loads.

Time to complete: 10 minutes
Skill level: Beginner

How Servos Work

Servos use PWM (Pulse Width Modulation) to set position:

  • 1 ms pulse → 0° (full counterclockwise)
  • 1.5 ms pulse → 90° (center)
  • 2 ms pulse → 180° (full clockwise)

The Arduino Servo library handles all the PWM timing. You just call servo.write(angle) with a value from 0 to 180.

SG90 vs MG996R Comparison

SpecificationSG90MG996R
TypePlastic gearMetal gear
Torque1.8 kg·cm9.4 kg·cm
Speed0.12 sec/60°0.15 sec/60°
Operating voltage4.8–6V4.8–7.2V
Current (no load)100 mA150 mA
Current (stall)360 mA2,500 mA
Weight9 g55 g
Size22 × 12 × 29 mm40 × 20 × 43 mm
Price~$1~$4

Choose SG90 for: small robots, 3D printer parts, RC planes, lightweight arms
Choose MG996R for: robot arms, pan/tilt camera mounts, heavy steering applications

Servo Pinout (Universal)

Servo connectors have 3 wires. Color varies by brand:

SignalJR/Futaba colorHiTec color
GroundBlack or BrownBlack
Power (VCC)RedRed
Signal (PWM)Orange or YellowWhite

Wiring — Arduino Uno/Nano

For SG90 (low current, fine from Arduino 5V pin):

Servo WireArduino
Brown/Black (GND)GND
Red (VCC)5V
Orange/Yellow (Signal)Digital pin 9

For MG996R (high current — use external power):

Servo WireConnection
Brown/Black (GND)GND (Arduino GND AND external supply GND — share ground)
Red (VCC)External 5V supply (1A+), NOT Arduino 5V pin
Orange/Yellow (Signal)Arduino digital pin 9

The MG996R can draw up to 2.5A at stall — far more than an Arduino's 5V pin can provide (500 mA from USB). Using the Arduino's 5V for MG996R risks damaging the Arduino.

Install the Servo Library

The Servo library is included with Arduino IDE. No installation needed.

In Arduino IDE, just add #include <Servo.h> at the top of your sketch.

Code — Set a Specific Angle

#include <Servo.h>

Servo myServo;

void setup() {
  myServo.attach(9);  // Signal wire connected to digital pin 9
  
  myServo.write(0);   // Move to 0°
  delay(1000);
  
  myServo.write(90);  // Move to 90° (center)
  delay(1000);
  
  myServo.write(180); // Move to 180°
  delay(1000);
  
  myServo.write(90);  // Return to center
}

void loop() {
  // Nothing — servo holds position
}

Code — Sweep (Back and Forth)

#include <Servo.h>

Servo myServo;

void setup() {
  myServo.attach(9);
}

void loop() {
  // Sweep from 0° to 180°
  for (int angle = 0; angle <= 180; angle++) {
    myServo.write(angle);
    delay(15);  // 15 ms per degree = ~2.7 sec for full sweep
  }

  // Sweep from 180° back to 0°
  for (int angle = 180; angle >= 0; angle--) {
    myServo.write(angle);
    delay(15);
  }
}

Code — Control with Potentiometer

Turn a potentiometer to control servo angle in real time:

#include <Servo.h>

Servo myServo;
const int POT_PIN = A0;

void setup() {
  myServo.attach(9);
  Serial.begin(9600);
}

void loop() {
  int potValue = analogRead(POT_PIN);              // 0–1023
  int angle = map(potValue, 0, 1023, 0, 180);      // Map to 0–180°
  
  myServo.write(angle);

  Serial.print("Pot: ");
  Serial.print(potValue);
  Serial.print("  Angle: ");
  Serial.println(angle);

  delay(15);
}

map() converts the potentiometer range (0–1023) to servo angle range (0–180°). This is the most common servo control pattern in robotics.

Code — Control with Serial Commands

Type angles into Serial Monitor to position the servo:

#include <Servo.h>

Servo myServo;

void setup() {
  myServo.attach(9);
  myServo.write(90);  // Start at center
  Serial.begin(9600);
  Serial.println("Enter angle (0-180):");
}

void loop() {
  if (Serial.available() > 0) {
    int angle = Serial.parseInt();
    
    if (angle >= 0 && angle <= 180) {
      myServo.write(angle);
      Serial.print("Moved to: ");
      Serial.print(angle);
      Serial.println("°");
    } else {
      Serial.println("Invalid angle. Enter 0-180.");
    }

    // Clear remaining characters in buffer
    while (Serial.available()) Serial.read();
  }
}

Project — Pan/Tilt Camera Mount

Control two servos for horizontal (pan) and vertical (tilt) camera movement:

#include <Servo.h>

Servo panServo;   // Horizontal rotation
Servo tiltServo;  // Vertical rotation

const int PAN_PIN  = 9;
const int TILT_PIN = 10;

int panAngle  = 90;
int tiltAngle = 90;

void setup() {
  panServo.attach(PAN_PIN);
  tiltServo.attach(TILT_PIN);
  panServo.write(panAngle);
  tiltServo.write(tiltAngle);

  Serial.begin(9600);
  Serial.println("Commands: W/S = tilt up/down, A/D = pan left/right");
}

void loop() {
  if (Serial.available() > 0) {
    char cmd = Serial.read();

    switch (cmd) {
      case 'a': panAngle  = max(0,   panAngle  - 5); break;  // Pan left
      case 'd': panAngle  = min(180, panAngle  + 5); break;  // Pan right
      case 'w': tiltAngle = min(180, tiltAngle + 5); break;  // Tilt up
      case 's': tiltAngle = max(0,   tiltAngle - 5); break;  // Tilt down
    }

    panServo.write(panAngle);
    tiltServo.write(tiltAngle);
    Serial.print("Pan: ");
    Serial.print(panAngle);
    Serial.print("  Tilt: ");
    Serial.println(tiltAngle);
  }
}

Connect both servos to GND and 5V (external supply for MG996R). Pan servo signal to pin 9, tilt servo signal to pin 10.

Simulate on Wokwi

Wokwi supports servo motors. The servo shows its current angle in real time:

  1. Go to wokwi.com → New Project → Arduino Uno
  2. Add a Servo component
  3. Connect signal to pin 9, VCC to 5V, GND to GND
  4. Paste the sweep code and click Play — watch the servo rotate

See the Wokwi guide for setup instructions.

Troubleshooting

Servo jitters at target angle:

  • Add a 100 µF capacitor between 5V and GND near the servo
  • Underpowered: use external power supply instead of Arduino 5V
  • Other PWM devices on the same board can interfere

Servo moves to position then slowly drifts:

  • Usually a cheap servo with worn internal potentiometer
  • Try myServo.detach() after reaching position — releases PWM signal and stops fighting the position

Servo doesn't reach full 0° or 180°:

  • Some servos' range is 0–170° or 10–180°. Adjust the map() output range
  • Use myServo.writeMicroseconds(544) for true 0° and myServo.writeMicroseconds(2400) for true 180°

Servo buzzes loudly and draws high current:

  • Mechanical obstruction — don't force past mechanical limits
  • Voltage too low — servo stalls trying to reach position

Multiple servos stutter when one moves:

  • Power issue. Connect all servos to an external 5V supply. Share the GND with Arduino GND.

Frequently Asked Questions (FAQ)

What's the difference between a servo and a DC motor? A DC motor spins continuously at a set speed. A servo moves to a specific angle and holds that position. Servos have built-in position feedback (internal potentiometer) and control electronics.

Can Arduino control a servo without the Servo library? Yes, using analogWrite() on a PWM pin with the correct duty cycle. But the Servo library makes it trivial — use it.

How many servos can one Arduino Uno control? Up to 12 servos (pins that support Servo.attach()). Power is the limiting factor — use an external supply for more than 2–3 servos.

Can I control a 360° continuous rotation servo? Yes. Use the same Servo library. write(90) = stop, write(0) = full speed one direction, write(180) = full speed other direction.

What voltage does the SG90 servo need? 4.8V to 6V. At 5V it works fine from Arduino's 5V pin for low-torque applications. For heavy loads, use a dedicated 5V 2A power supply.

How do I make the servo move smoothly without jerking? Use small increments with delays — like the sweep code example. Alternatively, use easing functions or the SlowServo library for acceleration/deceleration curves.

Comentarios (0) /en/blog/arduino-servo-motor