Tutorial

Lesson 5 β€” Servo Motor Control (SG90) πŸ”§

Lesson 5 β€” Servo Motor Control (SG90) πŸ”§

🧠 Concept

Use PWM to set the servo angle (0–180Β°). We’ll sweep, then control with a potentiometer.

πŸ”Œ What is PWM?

PWM is a rapid ON/OFF signal. For hobby servos, a pulse every 20 ms (50 Hz), width β‰ˆ 1–2 ms maps to 0–180Β°.

🧭 Wiring

SG90 Servo Wiring Diagram

  • Servo Brown/Black β†’ GND
  • Servo Red β†’ 5V (use external 5V if possible)
  • Servo Orange/Yellow (signal) β†’ PWM pin
  • Potentiometer (optional): center to A0 (Arduino) / ADC pin (ESP32), sides to 5V & GND
⚠️ Power: Many USB ports can’t power servos well. Use an external 5V supply and common ground.

πŸ’» Code (Arduino C/C++) β€” Sweep

#include <Servo.h>
Servo s; const int SERVO_PIN = 9;

void setup(){ s.attach(SERVO_PIN); }
void loop(){
  for(int a=0; a<=180; a+=3){ s.write(a); delay(15); }
  for(int a=180; a>=0; a-=3){ s.write(a); delay(15); }
}

πŸ’» Code (Arduino) β€” Pot control

#include <Servo.h>
Servo s; const int SERVO_PIN=9, POT=A0;

void setup(){ s.attach(SERVO_PIN); }
void loop(){
  int val = analogRead(POT);             // 0..1023
  int angle = map(val, 0, 1023, 0, 180);
  s.write(angle);
  delay(10);
}

🐍 Code (Raspberry Pi – Python)

# SG90 with RPi.GPIO (software PWM)
import RPi.GPIO as GPIO, time
SERVO = 18  # BCM 18 supports hardware PWM on some hats; software PWM also ok

GPIO.setmode(GPIO.BCM)
GPIO.setup(SERVO, GPIO.OUT)
p = GPIO.PWM(SERVO, 50)  # 50 Hz
p.start(0)

def angle_to_dc(angle):
    return 2.5 + (angle/180.0)*10.0  # ~2.5-12.5% duty

try:
    for a in list(range(0,181,5))+list(range(180,-1,-5)):
        p.ChangeDutyCycle(angle_to_dc(a))
        time.sleep(0.03)
finally:
    p.stop(); GPIO.cleanup()
πŸ’‘ For smoother control, use pigpio library (hardware-timed PWM).

⚑ Code (ESP32 – MicroPython)

# SG90 on ESP32 (MicroPython)
from machine import Pin, PWM
from time import sleep

servo = PWM(Pin(15), freq=50)

def write_angle(angle):
    # duty_u16 for 1ms..2ms pulse @50Hz (range β‰ˆ 1638..3277 for 0..180)
    duty = int(1638 + (angle/180)*1639)
    servo.duty_u16(duty)

while True:
    for a in range(0,181,5):
        write_angle(a); sleep(0.03)
    for a in range(180,-1,-5):
        write_angle(a); sleep(0.03)

🎯 Challenge: Potentiometer β†’ Servo

Map ADC reading (0–4095 on ESP32) to 0–180Β° and drive the servo live.

πŸ–¨οΈ Worksheet β€” Servo Angle Log

  • [ ] Record duty cycles for 0Β°, 90Β°, 180Β°
  • [ ] Note jitter and how power affects it
  • [ ] Bonus: limit motion between 30Β° and 150Β°
RoboRider Labs β€’ Classroom Lesson 5