Overview

Servo motors are precision actuators that can rotate to specific angular positions. Unlike regular motors that just spin, servos provide position feedback and exact angular control - making them perfect for robotics, camera gimbals, robotic arms, and any application requiring precise movement.

In this lesson, you'll learn how to control servo motors using PWM signals from the ATmega328P microcontroller, with the servo connected to Digital Pin D9 on your Vumbua Synapse Kit.

Real-World Applications

Servo motors are used in:

  • Robotics: Robot arms, walking robots
  • RC Models: Steering in cars, control surfaces in planes
  • Automation: Automatic doors, valve control
  • Camera Systems: Pan-tilt camera mounts
  • Industrial: CNC machines, 3D printers
  • Home Automation: Smart blinds, pet feeders

Prerequisites

Before starting, make sure you have completed:

Completed Lessons
  • Lesson 1: Blinking LED (PWM basics)
  • Lesson 4: Potentiometer - Analog Input
  • Lesson 8: LCD Display
  • Understanding of PWM and analogWrite()
Hardware Requirements
  • Vumbua Synapse Kit with SG90 Servo
  • USB Type-C cable
  • Computer with Arduino IDE
  • Potentiometer (for advanced control)
On Vumbua Synapse Kit

The servo motor connects to the Servo Header on D9 of the Vumbua board. The header provides 5V power, GND, and signal connection - no external power supply needed for small servos like the SG90!

Learning Objectives

By the end of this lesson, you will be able to:

  • Understand how servo motors work internally
  • Connect and power servo motors correctly
  • Use the Servo library for precise control
  • Control servo angle with write() function
  • Create smooth sweeping motions
  • Control multiple servos simultaneously
  • Use potentiometer for analog position control
  • Understand continuous rotation servos
  • Build robotics and automation projects

What is a Servo Motor?

Components of a Servo

A standard hobby servo contains:

  • DC Motor: Provides rotation power
  • Gear Reduction: Increases torque
  • Potentiometer: Provides position feedback
  • Control Circuit: Compares position with command
  • Output Shaft: Connects to servo horn
How Servos Work

The servo control system works in a closed loop:

  1. MCU sends PWM pulse (1-2ms duration)
  2. Servo's internal circuit reads pulse width
  3. Potentiometer measures current position
  4. Circuit compares desired vs. actual position
  5. Motor turns until positions match
  6. Servo holds position against resistance
Types of Servos
Type Rotation Torque Application
Standard 0-180° 1-20 kg·cm Robotics, RC models
Continuous 360° continuous Low to medium Wheels, conveyors
Digital 0-180° High Industrial, robotics
Micro 0-180° 0.5-2 kg·cm Small projects, drones

Servo Pin Connections

The SG90 servo has 3 wires with standard colors:

Brown Wire
Ground (0V) - Connect to GND
GND
Red Wire
Power (4.8-6V) - Connect to 5V
5V
Orange/Yellow Wire
Signal - PWM control input
Digital Pin 9
Important Power Considerations

Never power servos directly from Arduino pins! Arduino pins can only supply 20-40mA, but servos can draw 100-500mA during movement. Always use:

  1. External power supply for multiple or large servos
  2. Capacitor across power lines to prevent voltage drops
  3. Separate power source for motors and MCU

For SG90 with Vumbua: Single servo is safe with board's 5V regulator.

PWM Servo Control Theory

Servos use a special form of PWM with precise timing requirements:

Servo PWM Signal Timing
20ms Cycle
1ms Pulse = 0°
20ms Cycle
1.5ms Pulse = 90°
20ms Cycle
2ms Pulse = 180°
Key Timing Parameters
Parameter Value Description
Pulse Cycle 20ms (50Hz) Repeat rate of PWM signal
Min Pulse Width 1.0ms Corresponds to 0° position
Neutral Pulse 1.5ms Corresponds to 90° position
Max Pulse Width 2.0ms Corresponds to 180° position
Calculating Position

The relationship between pulse width and angle is linear:

Angle (°) = (Pulse Width - 1000) × (180 / 1000)

Where pulse width is in microseconds (1000-2000µs)

Using the Servo Library

Arduino provides a built-in Servo library that handles the complex PWM timing:

servo_library_basics.ino
/*
  Vumbua Synapse Kit - Lesson 9: Servo Library Basics
  Basic servo control using Arduino Servo library
*/

// Include the Servo library
#include <Servo.h>

// Create a servo object to control a servo
Servo myServo;

// Pin where servo is connected (D9 on Vumbua)
const int servoPin = 9;

void setup() {
  // Attach the servo on pin 9 to the servo object
  myServo.attach(servoPin);
  
  // Initialize Serial communication
  Serial.begin(9600);
  Serial.println("Servo Library Test");
  Serial.println("Servo connected to pin D9");
}

void loop() {
  // Nothing here yet - we'll add code in next sections
}

Servo Library Functions

1. attach() - Connect Servo
// Basic attach
servo.attach(pin);

// With custom pulse range
servo.attach(pin, minPulse, maxPulse);

Connects servo to specified pin. Optional min/max pulse in microseconds (default: 544-2400µs).

2. write() - Set Position
// Set angle in degrees (0-180)
servo.write(angle);

// Set pulse width in microseconds (500-2500)
servo.writeMicroseconds(pulseWidth);

Sets servo position. Most servos accept 0-180°, but some have different ranges.

3. read() - Read Position
// Get last written angle
int angle = servo.read();

Returns last position set with write(), not actual servo position.

4. attached() & detach()
// Check if servo is attached
if (servo.attached()) {
  // Servo is connected
}

// Disconnect servo (pulse stops)
servo.detach();

Useful for power saving or reconfiguring pins.

Basic Servo Control Program

Let's create a complete program to control the servo through different positions:

servo_basic_control.ino
/*
  Vumbua Synapse Kit - Lesson 9: Basic Servo Control
  Move servo to specific positions with delays
*/

#include <Servo.h>

Servo myServo;
const int servoPin = 9;

void setup() {
  myServo.attach(servoPin);
  Serial.begin(9600);
  Serial.println("Basic Servo Control Program");
  Serial.println("Servo will move through positions: 0° → 90° → 180° → 90°");
}

void loop() {
  // Move to 0 degrees (minimum position)
  Serial.println("Moving to 0°");
  myServo.write(0);
  delay(1000);  // Wait 1 second for movement
  
  // Move to 90 degrees (center position)
  Serial.println("Moving to 90°");
  myServo.write(90);
  delay(1000);
  
  // Move to 180 degrees (maximum position)
  Serial.println("Moving to 180°");
  myServo.write(180);
  delay(1000);
  
  // Return to center
  Serial.println("Returning to 90°");
  myServo.write(90);
  delay(1000);
  
  // Demonstrate microsecond control
  Serial.println("Using writeMicroseconds()");
  Serial.println("1000µs = 0°, 1500µs = 90°, 2000µs = 180°");
  
  myServo.writeMicroseconds(1000);  // 0 degrees
  delay(1000);
  
  myServo.writeMicroseconds(1500);  // 90 degrees
  delay(1000);
  
  myServo.writeMicroseconds(2000);  // 180 degrees
  delay(1000);
  
  myServo.writeMicroseconds(1500);  // Back to center
  delay(1000);
}

Testing the Program

1. Connect the Servo

Connect the SG90 servo to the Servo Header on your Vumbua Synapse Kit:

  • Brown wire → GND (outer pin)
  • Red wire → 5V (middle pin)
  • Orange wire → Signal (inner pin, D9)
2. Upload and Observe

Upload the code and watch the servo move through the sequence:

  1. 0° position (fully counter-clockwise)
  2. 90° position (center)
  3. 180° position (fully clockwise)
  4. Return to center
  5. Repeat with microsecond control
3. Monitor Serial Output

Open Serial Monitor (Tools → Serial Monitor) to see position messages:

Basic Servo Control Program
Servo will move through positions: 0° → 90° → 180° → 90°
Moving to 0°
Moving to 90°
...
90°
0° 90° 180°

Potentiometer Position Control

Combine servo control with potentiometer input from Lesson 4 for interactive control:

servo_pot_control.ino
/*
  Vumbua Synapse Kit - Lesson 9: Potentiometer Servo Control
  Control servo position with potentiometer
*/

#include <Servo.h>

Servo myServo;

const int servoPin = 9;      // Servo on pin D9
const int potPin = A0;        // Potentiometer on A0

int potValue;                 // Raw potentiometer reading
int servoAngle;               // Calculated servo angle
int lastAngle = -1;          // Last position to avoid redundant updates

void setup() {
  myServo.attach(servoPin);
  Serial.begin(9600);
  
  Serial.println("Potentiometer Servo Controller");
  Serial.println("Turn potentiometer to control servo position");
  Serial.println("==============================================");
}

void loop() {
  // Read potentiometer value (0-1023)
  potValue = analogRead(potPin);
  
  // Map potentiometer value to servo angle (0-180)
  servoAngle = map(potValue, 0, 1023, 0, 180);
  
  // Only update servo if position changed
  if (servoAngle != lastAngle) {
    // Move servo to new position
    myServo.write(servoAngle);
    lastAngle = servoAngle;
    
    // Calculate percentage for display
    int potPercentage = map(potValue, 0, 1023, 0, 100);
    
    // Display status
    Serial.print("Potentiometer: ");
    Serial.print(potValue);
    Serial.print(" (");
    Serial.print(potPercentage);
    Serial.print("%) | Servo Angle: ");
    Serial.print(servoAngle);
    Serial.println("°");
  }
  
  // Small delay for stability
  delay(20);
}

Advanced Features to Add

servo_advanced_control.ino
/*
  Vumbua Synapse Kit - Lesson 9: Advanced Servo Control
  Added features: smoothing, constraints, LED feedback
*/

#include <Servo.h>

Servo myServo;

const int servoPin = 9;
const int potPin = A0;
const int ledPin = 13;  // Built-in LED

// Smoothing variables
const int numReadings = 10;
int readings[numReadings];
int readIndex = 0;
int total = 0;
int average = 0;

// Angle constraints
const int minAngle = 20;   // Minimum safe angle
const int maxAngle = 160;  // Maximum safe angle

void setup() {
  myServo.attach(servoPin);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  
  // Initialize smoothing array
  for (int i = 0; i < numReadings; i++) {
    readings[i] = 0;
  }
  
  Serial.println("Advanced Servo Control with Smoothing");
  Serial.println("Angle constrained to " + String(minAngle) + "° - " + String(maxAngle) + "°");
}

void loop() {
  // Read potentiometer with smoothing
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(potPin);
  total = total + readings[readIndex];
  readIndex = (readIndex + 1) % numReadings;
  average = total / numReadings;
  
  // Map to servo angle with constraints
  int servoAngle = map(average, 0, 1023, minAngle, maxAngle);
  
  // Constrain to safe limits
  servoAngle = constrain(servoAngle, minAngle, maxAngle);
  
  // Move servo
  myServo.write(servoAngle);
  
  // LED feedback based on position
  if (servoAngle < 90) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }
  
  // Display status every 100ms
  static unsigned long lastDisplay = 0;
  if (millis() - lastDisplay > 100) {
    lastDisplay = millis();
    
    Serial.print("Raw: ");
    Serial.print(average);
    Serial.print(" | Angle: ");
    Serial.print(servoAngle);
    Serial.print("° | Limits: [");
    Serial.print(minAngle);
    Serial.print("° - ");
    Serial.print(maxAngle);
    Serial.println("°]");
  }
  
  delay(10);  // Fast response for smooth control
}

Sweep Function - Automatic Scanning

Create smooth automatic sweeping motion for scanning applications:

servo_sweep.ino
/*
  Vumbua Synapse Kit - Lesson 9: Servo Sweep Function
  Create smooth back-and-forth sweeping motion
*/

#include <Servo.h>

Servo myServo;
const int servoPin = 9;

int pos = 0;     // Current position
int increment = 1;  // Degrees to move each step
int delayTime = 15; // Delay between steps (ms)

// Sweep range
const int minPos = 30;
const int maxPos = 150;

void setup() {
  myServo.attach(servoPin);
  Serial.begin(9600);
  
  Serial.println("Servo Sweep Function");
  Serial.println("Sweeping from " + String(minPos) + "° to " + String(maxPos) + "°");
}

void loop() {
  // Move servo one step
  myServo.write(pos);
  
  // Display position every 10 degrees
  if (pos % 10 == 0) {
    Serial.print("Position: ");
    Serial.print(pos);
    Serial.println("°");
  }
  
  // Wait for servo to reach position
  delay(delayTime);
  
  // Update position for next step
  pos = pos + increment;
  
  // Reverse direction at limits
  if (pos <= minPos || pos >= maxPos) {
    increment = -increment;  // Reverse direction
    
    // Optional: pause at ends
    delay(500);
    
    Serial.println("Direction reversed!");
  }
}

Variable Speed Sweep

servo_variable_sweep.ino
/*
  Vumbua Synapse Kit - Lesson 9: Variable Speed Sweep
  Control sweep speed with potentiometer
*/

#include <Servo.h>

Servo myServo;
const int servoPin = 9;
const int potPin = A0;

int pos = 0;
int increment = 1;
int delayTime;

// Speed settings
const int minSpeed = 5;    // Fastest (5ms delay)
const int maxSpeed = 50;   // Slowest (50ms delay)

void setup() {
  myServo.attach(servoPin);
  Serial.begin(9600);
  
  Serial.println("Variable Speed Servo Sweep");
  Serial.println("Turn potentiometer to control sweep speed");
}

void loop() {
  // Read potentiometer for speed control
  int potValue = analogRead(potPin);
  delayTime = map(potValue, 0, 1023, minSpeed, maxSpeed);
  
  // Move servo
  myServo.write(pos);
  delay(delayTime);
  
  // Update position
  pos = pos + increment;
  
  // Reverse direction at limits
  if (pos <= 0 || pos >= 180) {
    increment = -increment;
  }
  
  // Display status every 50 cycles
  static int cycleCount = 0;
  cycleCount++;
  
  if (cycleCount % 50 == 0) {
    int speedPercentage = map(delayTime, minSpeed, maxSpeed, 100, 0);
    
    Serial.print("Position: ");
    Serial.print(pos);
    Serial.print("° | Delay: ");
    Serial.print(delayTime);
    Serial.print("ms | Speed: ");
    Serial.print(speedPercentage);
    Serial.println("%");
  }
}

Controlling Multiple Servos

Learn to control two or more servos simultaneously for robotic applications:

multiple_servos.ino
/*
  Vumbua Synapse Kit - Lesson 9: Multiple Servo Control
  Control two servos for robotic arm or pan-tilt mechanism
*/

#include <Servo.h>

// Create two servo objects
Servo servoBase;    // Base rotation (pan)
Servo servoArm;     // Arm elevation (tilt)

// Servo pins
const int basePin = 9;   // Base servo on D9
const int armPin = 10;    // Arm servo on D10

// Potentiometers for control
const int potBasePin = A0;   // Base control
const int potArmPin = A1;    // Arm control

void setup() {
  // Attach servos to pins
  servoBase.attach(basePin);
  servoArm.attach(armPin);
  
  Serial.begin(9600);
  Serial.println("Dual Servo Control System");
  Serial.println("Potentiometer 1 (A0) controls base");
  Serial.println("Potentiometer 2 (A1) controls arm");
}

void loop() {
  // Read both potentiometers
  int basePot = analogRead(potBasePin);
  int armPot = analogRead(potArmPin);
  
  // Map to servo angles with constraints
  int baseAngle = map(basePot, 0, 1023, 0, 180);
  int armAngle = map(armPot, 0, 1023, 30, 150);  // Limited range for arm
  
  // Apply constraints for safety
  baseAngle = constrain(baseAngle, 0, 180);
  armAngle = constrain(armAngle, 30, 150);
  
  // Move both servos
  servoBase.write(baseAngle);
  servoArm.write(armAngle);
  
  // Display status
  static unsigned long lastUpdate = 0;
  if (millis() - lastUpdate > 200) {
    lastUpdate = millis();
    
    Serial.print("Base: ");
    Serial.print(baseAngle);
    Serial.print("° | Arm: ");
    Serial.print(armAngle);
    Serial.println("°");
  }
  
  delay(20);
}
Power Considerations for Multiple Servos

Multiple servos can draw significant current! When controlling more than one servo:

  1. Use external power supply (5-6V, 2A minimum for 2-3 servos)
  2. Connect power directly to servo power pins, not through Arduino
  3. Keep Arduino ground connected to external supply ground
  4. Add large capacitor (470-1000µF) across power lines near servos
  5. Consider using a dedicated servo controller board for complex projects

Continuous Rotation Servos

Some servos can be modified for continuous rotation - acting like gear motors:

continuous_servo.ino
/*
  Vumbua Synapse Kit - Lesson 9: Continuous Rotation Servo
  Control speed and direction of continuous rotation servo
*/

#include <Servo.h>

Servo continuousServo;
const int servoPin = 9;
const int potPin = A0;

void setup() {
  continuousServo.attach(servoPin);
  Serial.begin(9600);
  
  Serial.println("Continuous Rotation Servo Control");
  Serial.println("Potentiometer controls speed and direction");
  Serial.println("Center = Stop, Left = Reverse, Right = Forward");
}

void loop() {
  int potValue = analogRead(potPin);
  
  // Map potentiometer to continuous servo range
  // 0 = Full reverse, 90 = Stop, 180 = Full forward
  int servoValue = map(potValue, 0, 1023, 0, 180);
  
  // For finer control around center (stop position)
  if (servoValue > 85 && servoValue < 95) {
    servoValue = 90;  // Dead zone for precise stop
  }
  
  // Control continuous servo
  continuousServo.write(servoValue);
  
  // Calculate speed percentage (-100% to +100%)
  int speedPercent = map(servoValue, 0, 180, -100, 100);
  
  // Display status
  static int lastSpeed = 0;
  if (abs(speedPercent - lastSpeed) > 5) {
    lastSpeed = speedPercent;
    
    Serial.print("Servo Value: ");
    Serial.print(servoValue);
    Serial.print(" | Speed: ");
    Serial.print(speedPercent);
    
    if (speedPercent > 0) {
      Serial.println("% Forward");
    } else if (speedPercent < 0) {
      Serial.println("% Reverse");
    } else {
      Serial.println("% Stopped");
    }
  }
  
  delay(50);
}

Project Ideas

Robotic Arm

Build a simple 2-degree-of-freedom robotic arm:

  • Base servo for rotation
  • Arm servo for elevation
  • Potentiometers for manual control
  • Add gripper with third servo
  • Programmable positions
Pan-Tilt Camera Mount

Create a camera positioning system:

  • Servo for pan (horizontal)
  • Servo for tilt (vertical)
  • Joystick or dual potentiometer control
  • Preset positions for surveillance
  • Smooth scanning mode
Automatic Pet Feeder

Build an automated feeding system:

  • Servo controls food dispenser
  • Real-time clock for scheduling
  • LCD display for status
  • Button for manual feeding
  • Portion size control
Solar Tracker

Create a sun-following system:

  • Two servos for dual-axis tracking
  • Light sensors for position feedback
  • Maximum power point tracking
  • Manual override capability
  • Energy monitoring

ATmega328P Timers & PWM

Understanding how the ATmega328P generates PWM signals for servo control:

Timer1 - Servo Control Timer

The Servo library uses Timer1 (16-bit timer) to generate precise 50Hz PWM signals:

  • Clock Source: 16MHz system clock
  • Prescaler: Typically 8 or 64
  • Frequency: 50Hz (20ms period)
  • Resolution: 1µs (with 8 prescaler)
PWM Generation

Timer1 operates in Fast PWM Mode or Phase Correct PWM:

  1. Timer counts from 0 to TOP value
  2. Output pin set HIGH at BOTTOM
  3. Output pin cleared when counter matches OCR1A
  4. Cycle repeats at TOP value

For servos: TOP = 40000 (with prescaler 8), giving 20ms period

Servo Library Limitations

The Servo library can control up to 12 servos on most Arduino boards:

  • Uses Timer1 which interferes with PWM on pins 9 & 10
  • Each servo requires ~200 bytes of RAM
  • Servo updates occur in background (interrupt-driven)
  • Not all pins support servo control equally

Troubleshooting Common Issues

Common Servo Problems

  • Check Power: Servo needs 5V, 500mA+ during movement
  • Verify Connections: Brown=GND, Red=5V, Orange=Signal
  • Test Voltage: Measure at servo connector during movement
  • Add Capacitor: 470µF across servo power lines
  • Check Code: Ensure servo.attach(pin) is called

  • Mechanical Limits: Some servos don't reach full 180°
  • Adjust Pulse Range: servo.attach(pin, 1000, 2000)
  • Check for Obstructions: Servo horn hitting something
  • Test with writeMicroseconds(): Try 1000-2000µs directly
  • Servo Type: Some servos are 90° or 270° range

  • Power Issue: Servo draws too much current
  • Solution: Use external power supply for servo
  • Add Decoupling: 100µF capacitor on Arduino 5V line
  • Check USB Cable: Some cables can't deliver enough power
  • Limit Current: Move servos one at a time

Video Demonstration

Servo Control Video Tutorial

Watch our detailed video walkthrough showing servo control in action!

Learn about proper connections, power considerations, and advanced techniques.

Watch on OLSPACE YouTube

What's Next?

Congratulations! You've mastered servo motor control. Here's what you've accomplished:

  • ✓ Learned servo motor principles and PWM control
  • ✓ Controlled servo position with write() function
  • ✓ Created smooth sweeping motions
  • ✓ Used potentiometer for analog position control
  • ✓ Controlled multiple servos simultaneously
  • ✓ Understood continuous rotation servos
  • ✓ Learned about power requirements and safety

In the next lesson, you'll explore distance measurement:

Lesson 10: Ultrasonic Distance Sensor

Learn to measure distance using ultrasonic waves! Create parking sensors, object detection systems, and simple radar using the HC-SR04 ultrasonic sensor. Combine with servo motors to create scanning distance measurement systems.

Resources & Downloads