How to Control SG90 Servo Motors Using Raspberry Pi

Micro Servo Motor with Raspberry Pi / Visits:10

If you’ve ever wanted to add precise, programmable movement to your Raspberry Pi projects, the SG90 micro servo motor is one of the easiest and most rewarding components to start with. These tiny motors pack a surprising amount of torque and accuracy into a package smaller than a matchbox, making them ideal for robotics arms, camera gimbals, animatronics, and even small-scale automation.

In this guide, we’ll walk through everything you need to know: from wiring and power considerations to Python code that gives you full control over position, speed, and multi-servo coordination. By the end, you’ll be able to command your SG90 servos like a pro.


Why the SG90 Micro Servo Is So Popular

Before diving into the wiring and code, it’s worth understanding what makes the SG90 a favorite among makers and hobbyists.

Key Specs That Matter

  • Operating Voltage: 4.8V to 6.0V (5V is the sweet spot)
  • Stall Torque: 1.8 kg·cm at 4.8V (enough to lift small objects or rotate a lightweight camera)
  • Operating Speed: 0.12 seconds per 60° at 4.8V (fast enough for most motion projects)
  • Weight: Just 9 grams (barely adds any load to your robot)
  • Rotation Range: 0° to 180° (standard servo) or 360° continuous rotation (modified versions)

What sets the SG90 apart from larger servos is its low power consumption and direct 5V compatibility with the Raspberry Pi’s GPIO pins (as long as you don’t draw too much current from the 5V rail). The plastic gears are lightweight and quiet, and the price is low enough that you can buy a handful for multi-axis projects.

Common Use Cases

  • Pan-and-tilt camera mounts
  • Small robotic arms (2–3 DOF)
  • RC car steering
  • Automatic door locks
  • Model train switch controls
  • Interactive art installations

Understanding PWM: The Language of Servos

The SG90, like all standard hobby servos, is controlled using Pulse Width Modulation (PWM) . The Raspberry Pi doesn’t output true analog voltages, but it can generate precise digital pulses that the servo interprets as position commands.

How PWM Controls Position

A servo expects a 50 Hz signal (20 ms period). Within each period, a pulse of a specific width tells the servo where to go:

  • 1 ms pulse (0.5–1 ms typical): 0° position (full left)
  • 1.5 ms pulse: 90° position (center)
  • 2 ms pulse (2–2.5 ms typical): 180° position (full right)

The exact pulse widths vary slightly between servos, so you’ll often need to calibrate your SG90 by testing the minimum and maximum values that actually move the horn to the mechanical stops.

20 ms period (50 Hz) |--------|--------|--------|--------| ↑ 1 ms → 0° ↑ 1.5 ms → 90° ↑ 2 ms → 180°

Why Raspberry Pi’s Software PWM Works Well

The Raspberry Pi has built-in hardware PWM on GPIO12, GPIO13, GPIO18, and GPIO19, but you can also use software PWM on any GPIO pin. For most SG90 projects, software PWM is perfectly fine because the servo doesn’t require microsecond-level precision—the mechanical gears smooth out small timing jitter.


Wiring the SG90 to Your Raspberry Pi

The SG90 has three wires, usually color-coded as:

  • Orange (or Yellow): Signal (PWM input)
  • Red: Power (5V)
  • Brown (or Black): Ground

The Critical Power Consideration

Never power the servo directly from the Raspberry Pi’s 3.3V pin. The SG90 needs 5V, and even more importantly, it can draw up to 500 mA under load. The Pi’s 5V rail can supply around 1.2A total (depending on the model), so one or two servos might be okay if you’re not also powering USB devices. But for anything beyond that, or if you want reliable operation, use an external 5V power supply.

Recommended Wiring Diagram

Raspberry Pi GPIO SG90 Servo ----------------- ---------- GPIO18 (Pin 12) ────── Orange (Signal) 5V Pin (Pin 2 or 4) ──── Red (Power) GND Pin (Pin 6) ────── Brown (Ground)

External 5V Supply (optional for multiple servos) +5V ──────────────── Red (Power) GND ──────────────── Brown (Ground)

If using an external supply, connect the ground of the external supply to the Raspberry Pi’s ground to create a common reference. Otherwise, the signal voltage won’t be interpreted correctly.

Adding a Capacitor for Smooth Operation

A 470 µF electrolytic capacitor across the servo’s power and ground (close to the servo) helps absorb current spikes and prevents voltage drops that could reset your Pi. This is especially important when the servo starts moving under load.


Software Setup: Installing Required Libraries

We’ll use Python with the RPi.GPIO library, which comes pre-installed on most Raspberry Pi OS images. If you’re using a fresh install, it’s already there.

Step 1: Enable PWM on Your Chosen Pin

You don’t need to enable anything special for software PWM. Just make sure your user has permission to access the GPIO pins (usually gpio group membership).

bash sudo usermod -a -G gpio pi

Log out and back in for the change to take effect.

Step 2: Test Your Wiring with a Simple Script

Create a file called servo_test.py:

python import RPi.GPIO as GPIO import time

SERVO_PIN = 18

GPIO.setmode(GPIO.BCM) GPIO.setup(SERVO_PIN, GPIO.OUT)

Create PWM instance with 50 Hz frequency

pwm = GPIO.PWM(SERVO_PIN, 50) pwm.start(0) # Start with duty cycle 0 (no signal)

def set_angle(angle): # Convert angle (0-180) to duty cycle (2.5-12.5 typical) duty = 2.5 + (angle / 180.0) * 10.0 pwm.ChangeDutyCycle(duty) time.sleep(0.5) # Give servo time to move pwm.ChangeDutyCycle(0) # Stop sending signal to reduce jitter

try: while True: setangle(0) time.sleep(1) setangle(90) time.sleep(1) set_angle(180) time.sleep(1) except KeyboardInterrupt: pwm.stop() GPIO.cleanup()

Run it with:

bash python3 servo_test.py

You should see the servo sweep from 0° to 180° and back. If it doesn’t move to the full range, adjust the duty calculation—some SG90s need 2.0–12.0 instead of 2.5–12.5.


Fine-Tuning the Pulse Width Range

Every SG90 is slightly different due to manufacturing tolerances. The duty cycle values I gave above are a good starting point, but you may need to calibrate.

Finding the True Min and Max

Write a script that lets you manually adjust the duty cycle:

python import RPi.GPIO as GPIO import time

SERVOPIN = 18 GPIO.setmode(GPIO.BCM) GPIO.setup(SERVOPIN, GPIO.OUT) pwm = GPIO.PWM(SERVO_PIN, 50) pwm.start(0)

try: while True: duty = float(input("Enter duty cycle (2.0 to 12.0): ")) pwm.ChangeDutyCycle(duty) time.sleep(0.5) pwm.ChangeDutyCycle(0) except KeyboardInterrupt: pwm.stop() GPIO.cleanup()

Start at 2.5 and increase by 0.1 until you hear the servo click against its mechanical stop. That’s your 0° position. Then do the same from the high end (12.5 downward) to find 180°. Record these values and use them in your code.

Why You Should Stop the PWM Signal After Moving

Notice in the code above we set duty cycle to 0 after each move. This is important: if you leave a constant PWM signal on the servo, it will continue to draw power trying to hold that position, causing jitter and overheating. Sending a 0% duty cycle effectively disables the signal, and the servo’s internal controller will hold the last position with less power.


Controlling Multiple SG90 Servos Simultaneously

One Raspberry Pi can control many servos, but you need to be careful about power and GPIO pin allocation.

Power Budget for Multiple Servos

  • 1 servo: ~200 mA idle, up to 500 mA under load
  • 4 servos: ~2A peak (external 5V supply strongly recommended)
  • 8 servos: ~4A peak (dedicated servo controller like PCA9685 recommended)

If you’re using more than 2 servos, do not power them from the Pi’s 5V rail. Use a separate 5V supply and connect its ground to the Pi’s ground.

Multi-Servo Code Example

Here’s how to control 4 servos on GPIO18, 19, 20, and 21:

python import RPi.GPIO as GPIO import time

SERVOPINS = [18, 19, 20, 21] NUMSERVOS = len(SERVO_PINS)

GPIO.setmode(GPIO.BCM) for pin in SERVO_PINS: GPIO.setup(pin, GPIO.OUT)

pwms = [] for pin in SERVO_PINS: pwm = GPIO.PWM(pin, 50) pwm.start(0) pwms.append(pwm)

def set_angles(angles): for i, angle in enumerate(angles): duty = 2.5 + (angle / 180.0) * 10.0 pwms[i].ChangeDutyCycle(duty) time.sleep(0.5) for pwm in pwms: pwm.ChangeDutyCycle(0)

try: while True: setangles([0, 0, 0, 0]) time.sleep(1) setangles([90, 90, 90, 90]) time.sleep(1) set_angles([180, 180, 180, 180]) time.sleep(1) except KeyboardInterrupt: for pwm in pwms: pwm.stop() GPIO.cleanup()

Using a Servo Driver Board (PCA9685)

If you need 8+ servos or want to offload PWM generation from the Pi’s CPU, use an I2C-based PCA9685 servo driver. It can control 16 servos with just two I2C pins (SDA/SCL) and has its own clock for jitter-free PWM.

Wiring for PCA9685:

PCA9685 VCC → Raspberry Pi 5V PCA9685 GND → Raspberry Pi GND PCA9685 SDA → Raspberry Pi GPIO2 (Pin 3) PCA9685 SCL → Raspberry Pi GPIO3 (Pin 5)

Install the library:

bash pip3 install adafruit-circuitpython-servokit

Code example:

python from adafruit_servokit import ServoKit kit = ServoKit(channels=16)

Set servo 0 to 90 degrees

kit.servo[0].angle = 90

Set servo 1 to 45 degrees

kit.servo[1].angle = 45

The PCA9685 handles all the PWM timing, leaving your Pi free for other tasks.


Smooth Motion: Adding Acceleration and Deceleration

A servo that snaps instantly from 0° to 180° can be jarring and may cause mechanical stress. For more natural motion, increment the angle in small steps with a delay.

Simple Smooth Sweep Function

python import RPi.GPIO as GPIO import time

SERVOPIN = 18 GPIO.setmode(GPIO.BCM) GPIO.setup(SERVOPIN, GPIO.OUT) pwm = GPIO.PWM(SERVO_PIN, 50) pwm.start(0)

def smoothmove(startangle, endangle, steps=50, delay=0.02): anglerange = endangle - startangle for i in range(steps + 1): currentangle = startangle + (anglerange * i / steps) duty = 2.5 + (currentangle / 180.0) * 10.0 pwm.ChangeDutyCycle(duty) time.sleep(delay) pwm.ChangeDutyCycle(0)

try: smoothmove(0, 180, steps=100, delay=0.01) time.sleep(1) smoothmove(180, 0, steps=100, delay=0.01) finally: pwm.stop() GPIO.cleanup()

You can also implement easing functions (ease-in, ease-out) by varying the step size:

python import math

def easeinout(t): # t goes from 0 to 1, returns eased value return t * t * (3 - 2 * t) # smoothstep

def smoothmoveeased(startangle, endangle, duration=2.0, fps=50): totalsteps = int(duration * fps) for step in range(totalsteps + 1): t = step / totalsteps easedt = easeinout(t) currentangle = startangle + (endangle - startangle) * easedt duty = 2.5 + (currentangle / 180.0) * 10.0 pwm.ChangeDutyCycle(duty) time.sleep(1.0 / fps) pwm.ChangeDutyCycle(0)


Continuous Rotation Servos (360° Modification)

Standard SG90 servos are limited to 180°, but you can modify them for continuous rotation (useful for wheels or conveyor belts). Alternatively, you can buy pre-modified continuous rotation servos.

How Continuous Rotation Works

Instead of position, the PWM signal controls speed and direction:

  • 1 ms pulse: Full speed clockwise
  • 1.5 ms pulse: Stop
  • 2 ms pulse: Full speed counterclockwise

The duty cycle between these values gives proportional speed.

Code for Continuous Rotation

python import RPi.GPIO as GPIO import time

SERVOPIN = 18 GPIO.setmode(GPIO.BCM) GPIO.setup(SERVOPIN, GPIO.OUT) pwm = GPIO.PWM(SERVO_PIN, 50) pwm.start(0)

def set_speed(speed): # speed: -1 (full CW) to 1 (full CCW), 0 = stop duty = 7.5 + (speed * 5.0) # 7.5 is center (stop) pwm.ChangeDutyCycle(duty)

try: setspeed(0.5) # Half speed CCW time.sleep(2) setspeed(-0.3) # Slow CW time.sleep(2) set_speed(0) # Stop finally: pwm.stop() GPIO.cleanup()

Note: Continuous rotation servos often have a trim potentiometer to fine-tune the “stop” position. You may need to adjust it with a small screwdriver until the servo stops completely at 1.5 ms.


Advanced: Using Hardware PWM for Jitter-Free Control

Software PWM works well, but if you need ultra-smooth motion (e.g., for a camera gimbal), hardware PWM is better. The Raspberry Pi has hardware PWM on GPIO12 (PWM0) and GPIO18 (PWM0 on some models), GPIO13 (PWM1), and GPIO19 (PWM1).

Enabling Hardware PWM

You need to modify /boot/config.txt to enable the PWM overlays:

bash sudo nano /boot/config.txt

Add these lines:

dtoverlay=pwm-2chan

Reboot:

bash sudo reboot

Now you can use hardware PWM with the pigpio library, which is much more precise.

Using pigpio for Hardware PWM

Install pigpio:

bash sudo apt install pigpio sudo systemctl enable pigpiod sudo systemctl start pigpiod

Then in Python:

python import pigpio import time

SERVO_PIN = 18 pi = pigpio.pi()

def setangle(angle): # Convert angle to pulse width in microseconds pulsewidth = 500 + (angle / 180.0) * 2000 # 500 to 2500 µs pi.setservopulsewidth(SERVOPIN, pulsewidth)

try: setangle(0) time.sleep(1) setangle(90) time.sleep(1) setangle(180) time.sleep(1) finally: pi.setservopulsewidth(SERVOPIN, 0) # Stop signal pi.stop()

The pigpio library uses the Pi’s dedicated PWM hardware, resulting in jitter-free motion even under heavy CPU load.


Troubleshooting Common SG90 Issues

Even with correct wiring, you may run into problems. Here are the most common ones and how to fix them.

Servo Jitters or Vibrates

  • Cause: PWM signal is left on continuously.
  • Fix: Set duty cycle to 0 after moving, or use pi.set_servo_pulsewidth(pin, 0) in pigpio.

  • Cause: Power supply voltage drops under load.

  • Fix: Add a 470 µF capacitor across power and ground near the servo. Use a separate 5V supply for multiple servos.

Servo Doesn’t Move Full Range

  • Cause: Pulse width range is wrong for your specific servo.
  • Fix: Calibrate min and max duty cycles as described earlier. Some SG90s need 2.0–12.0 duty cycle, others need 2.5–12.5.

Servo Moves Erratically or Not at All

  • Cause: Ground not shared between Pi and external power supply.
  • Fix: Connect the GND of your external supply to a GND pin on the Pi.

  • Cause: PWM frequency is not 50 Hz.

  • Fix: Double-check that GPIO.PWM(pin, 50) uses 50 Hz.

Raspberry Pi Reboots When Servo Moves

  • Cause: Current spike exceeding the Pi’s power supply capacity.
  • Fix: Use a higher-rated power adapter (2.5A minimum for Pi + servos). Add a capacitor. Use external servo power.

Real-World Project: Pan-Tilt Camera Mount

Let’s put everything together into a practical project: a two-servo pan-tilt mount for a Raspberry Pi camera.

Hardware Needed

  • 2 × SG90 servos
  • Pan-tilt bracket (plastic 2-DOF mount)
  • Raspberry Pi Camera Module
  • External 5V power supply (2A minimum)
  • 470 µF capacitor

Wiring

  • Servo 1 (pan, horizontal): GPIO18
  • Servo 2 (tilt, vertical): GPIO19
  • Both servos powered from external 5V supply
  • Common ground

Python Code

python import RPi.GPIO as GPIO import time

PANPIN = 18 TILTPIN = 19

GPIO.setmode(GPIO.BCM) GPIO.setup(PANPIN, GPIO.OUT) GPIO.setup(TILTPIN, GPIO.OUT)

panpwm = GPIO.PWM(PANPIN, 50) tiltpwm = GPIO.PWM(TILTPIN, 50) panpwm.start(0) tiltpwm.start(0)

def move_servo(pwm, angle): duty = 2.5 + (angle / 180.0) * 10.0 pwm.ChangeDutyCycle(duty) time.sleep(0.3) pwm.ChangeDutyCycle(0)

def lookat(panangle, tiltangle): moveservo(panpwm, panangle) moveservo(tiltpwm, tilt_angle)

Example: scan left to right

try: for pan in range(0, 181, 10): lookat(pan, 90) time.sleep(0.5) for pan in range(180, -1, -10): lookat(pan, 90) time.sleep(0.5) finally: panpwm.stop() tiltpwm.stop() GPIO.cleanup()

You can extend this by adding keyboard control or integrating with OpenCV face tracking.


Final Tips for Reliable Servo Control

  • Always use a separate power supply for 3+ servos. The Pi’s 5V rail is not designed for high-current loads.
  • Add a heat sink to the servo driver chip if using PCA9685 with many servos.
  • Test with a multimeter to verify your external supply is outputting a stable 5V under load.
  • Use shielded cables for long runs (over 30 cm) to reduce noise on the signal line.
  • Store your calibration values in a config file so you can swap servos without re-tuning.

The SG90 micro servo is a fantastic component that bridges the gap between simple blinking LEDs and complex robotics. With the Raspberry Pi’s flexibility and the techniques covered here, you can add smooth, precise motion to almost any project. Whether you’re building a robot arm, a weather station with a moving sensor, or a tiny animatronic figure, the SG90 will serve you well.

Copyright Statement:

Author: Micro Servo Motor

Link: https://microservomotor.com/micro-servo-motor-with-raspberry-pi/control-sg90-servo-raspberry-pi.htm

Source: Micro Servo Motor

The copyright of this article belongs to the author. Reproduction is not allowed without permission.

About Us

Lucas Bennett avatar
Lucas Bennett
Welcome to my blog!

Tags