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.

Note: the SG90 Micro Servo is a Premium-tier component in the simulator — you’ll need a Premium or VIP plan to use it there.

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

  • Raspberry Pi 4B
  • SG90 Micro Servo

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

  • The servo horn visually rotates: 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.
  • Each Console line (“Moving to N degrees”) prints right as the servo visually starts moving toward that position, not noticeably before or after.

If something’s wrong

  • The servo stays at the center (about 90°) and never moves → its Signal pin is not wired to a Pi GPIO pin, or the script has not called GPIO.PWM(...) and pwm.start(...). A stopped PWM channel also sends the servo back to center, so a servo that returns to center after pwm.stop() is normal.
  • The servo goes to the wrong angle → the simulator maps duty cycle to angle in a straight line: 2.5% is 0°, 7.5% is 90° and 12.5% is 180°. A duty cycle outside 2.5% to 12.5% stops at 0° or 180°.
  • The Console prints "Moving to…" but the servo does not move → check the Signal wire first. The script is running, so the problem is between the Signal pin and the servo.
  • The servo will not snap into the breadboard → that is expected. The SG90 connects with drawn wires, like a real servo with its loose cable.
  • In the simulator the servo moves from the Signal wire's PWM alone. Wire V+ and GND anyway, because a real servo needs them.