Tutorial
π‘ Tip: Disable headers/footers in your print dialog for a clean PDF.
RoboRider Labs β Classroom Lesson
RoboRider Labs β 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

- 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Β°