Learn

Controlling an SG90 Micro Servo with a Raspberry Pi 4B

Wire an SG90 micro servo to a Raspberry Pi 4B GPIO pin and sweep it through a range of angles with real PWM in Python — no hardware required.

Try this directly in the free Raspberry Pi 4B simulator — no hardware or signup required. New to the GPIO header? Start with the interactive pinout guide.

What you’ll need

Step by step

  1. Drag Raspberry Pi 4B onto the Canvas.
  2. Drag the SG90 Micro Servo onto the Canvas (it won't mount into a breadboard — that's expected, real servos connect via loose wires, not legs).
  3. Hover over the servo's 3 pins to confirm their labels: Signal, V+, GND.
  4. Wire it up: Servo V+ → Pi's 5V pin. Servo GND → Pi's GND pin. Servo Signal → a GPIO pin (e.g. pin 37).
  5. Go to the Code tab and write a test script that sweeps through a few angles:
import RPi.GPIO as GPIO
import asyncio
 
signalPin = 37
 
GPIO.setmode(GPIO.BOARD)
GPIO.setup(signalPin, GPIO.OUT)
 
pwm = GPIO.PWM(signalPin, 50) # 50Hz, standard for servos
pwm.start(0)
 
def angle_to_duty(angle):
# Converts a 0-180 degree angle into the duty cycle percentage the servo expects
return 2.5 + (angle / 180) * 10 # roughly 2.5% (0°) to 12.5% (180°)
 
async def move_to(angle):
print(f"Moving to {angle} degrees")
pwm.ChangeDutyCycle(angle_to_duty(angle))
await asyncio.sleep(1)
 
await move_to(0)
await move_to(90)
await move_to(180)
await move_to(90)
 
pwm.stop()
GPIO.cleanup()
  1. Click Start. You should see the servo horn visually rotate: starting near one end, sweeping to center, continuing to the other end, then returning to center — each position held for about a second before moving to the next.

What you'll see in the Console:

Console
Moving to 0 degrees
Moving to 90 degrees
Moving to 180 degrees
Moving to 90 degrees

Each line should print right as the servo visually starts moving toward that position — that's your confirmation the script's intent and the servo's actual motion are in sync, not just coincidentally similar.

One extra check worth doing: if the print appears but the servo doesn't move (or moves to a clearly wrong position), that tells you the script → PWM channel path is working correctly, but the PWM channel → visual rotation path is where the problem actually is. Worth mentioning that distinction if you ever need to report a bug, since it narrows down which half of the pipeline to look at first.

What “working correctly” looks like

More component tutorials are in Learn.