How to Control Servo Motors Using Raspberry Pi and the RPi.GPIO Library for Beginners
If you’ve ever watched a robotic arm snap to a precise angle or a tiny pan-tilt camera follow a face, you’ve seen a micro servo motor doing the heavy lifting. These little yellow-and-blue motors (think SG90 or MG90S) are the absolute sweet spot for hobbyists: cheap, lightweight, and surprisingly powerful for their size. But getting one to spin exactly where you want it—not just spin endlessly—requires a specific type of signal. And that’s where your Raspberry Pi comes in.
In this guide, I’m going to walk you through the entire journey of controlling a micro servo with a Raspberry Pi using the classic RPi.GPIO library. No fancy add-on boards, no pigpio daemons, no I2C PWM chips. Just a breadboard, three jumper wires, and a few lines of Python. By the end, you’ll have a servo that sweeps, holds position, and responds to your commands like a well-trained puppy.
Why Micro Servos Are Different From DC Motors (And Why You Should Care)
Before we touch a single wire, let’s talk about what makes a micro servo tick. A regular DC motor spins continuously when you apply voltage. A micro servo, on the other hand, is a closed-loop positioning system. Inside that tiny plastic case, you have:
- A DC motor (the spinning part)
- A gear train (to reduce speed and increase torque)
- A feedback potentiometer (a variable resistor that tracks the output shaft’s angle)
- A small control board that reads the potentiometer and drives the motor to match your commanded angle
The control board doesn’t understand “go to 90 degrees” as a voltage level. Instead, it expects a Pulse Width Modulation (PWM) signal. Specifically, a 50 Hz signal (20 ms period) where the width of the high pulse tells the servo where to go:
- 1 ms pulse → 0 degrees (full counterclockwise)
- 1.5 ms pulse → 90 degrees (center)
- 2 ms pulse → 180 degrees (full clockwise)
Most micro servos (like the SG90) can only sweep about 180 degrees. Some “360-degree continuous rotation” servos exist, but they’re a different beast—they use the same PWM signal to control speed and direction, not position. For this tutorial, we’re sticking with the classic positional micro servo.
The Raspberry Pi’s PWM Problem (And RPi.GPIO’s Solution)
Here’s the catch: the Raspberry Pi’s GPIO pins operate at 3.3V logic, and they’re not natively great at generating precise, glitch-free PWM. The RPi.GPIO library provides a software-based PWM implementation, which is perfectly fine for a single micro servo. It works by toggling the GPIO pin in software with a timer. For one or two servos, this is rock solid. For a dozen servos or high-precision robotics, you’d want a dedicated PWM driver like the PCA9685. But for beginners? RPi.GPIO is the perfect starting point.
Important warning: Micro servos draw a surprising amount of current—especially when they start moving or hold position under load. The Raspberry Pi’s 5V pin can’t supply that current safely. You must power the servo from an external 5V supply (or a battery pack), and connect the Pi’s ground to the servo’s ground. Otherwise, you risk brownouts, resets, or even damaging your Pi.
What You’ll Need (The Shopping List)
Let’s keep this minimal. Here’s everything you need:
- Raspberry Pi (any model with GPIO pins—Zero, 3B+, 4B, 5—all work)
- Micro servo motor (SG90 or MG90S recommended; MG90S has metal gears and a bit more torque)
- Breadboard (optional but helps with wiring)
- Jumper wires (female-to-female for connecting to the servo’s pre-crimped wires, plus male-to-female for GPIO)
- External 5V power source (a USB power bank, a 4xAA battery pack, or a bench supply—just make sure it can deliver at least 500 mA)
- A common ground (critical!)
A note on servo wire colors: Most micro servos use three wires: - Brown (or black) → Ground (GND) - Red → 5V power - Orange (or yellow) → Signal (PWM)
Don’t mix up red and orange. I’ve seen people fry servos by plugging the signal wire into 5V. Double-check every time.
Wiring It Up (Step-by-Step, With Safety in Mind)
Let’s wire the servo to your Pi. We’ll use GPIO 18 for the signal, because it’s a common PWM-capable pin and easy to remember. But honestly, any GPIO pin works with RPi.GPIO software PWM.
Step 1: Connect the Servo to External Power
Take your external 5V supply and connect its positive terminal to the servo’s red wire. Connect the supply’s negative terminal to the servo’s brown wire. This powers the motor directly. If you’re using a battery pack, this is straightforward. If you’re using a USB power bank, you’ll need a USB-to-breadboard adapter or just clip leads.
Step 2: Connect the Signal Wire
Connect the servo’s orange wire to GPIO 18 on your Raspberry Pi. That’s physical pin 12 on the 40-pin header. Use a female-to-female jumper wire to go from the servo’s connector directly to the GPIO pin.
Step 3: Connect the Grounds (This Is Non-Negotiable)
The Raspberry Pi and the servo must share a common ground. If they don’t, the signal voltage will float, and the servo will twitch erratically or not move at all. Take a jumper wire from the negative terminal of your external power supply to any GND pin on the Pi (e.g., physical pin 6). This completes the circuit.
Step 4: Double-Check Everything
Before you power anything on, verify: - Red wire → external 5V positive - Brown wire → external 5V negative AND Pi GND - Orange wire → GPIO 18 (physical pin 12)
If you’re using a breadboard, it’s easy to accidentally bridge the 5V rail to the 3.3V rail. Take a breath and inspect your wiring. A wrong connection here can kill your servo, your Pi, or both.
Writing Your First Python Script (With RPi.GPIO)
Now the fun part. We’ll write a Python script that sweeps the servo from 0 to 180 degrees and back. But first, let’s understand the RPi.GPIO PWM API.
The Core API: GPIO.PWM(pin, frequency)
You create a PWM object on a pin, set the frequency (we’ll use 50 Hz), and then call start(duty_cycle). The duty cycle is a percentage of the 20 ms period that the signal is HIGH. For a 1 ms pulse, that’s 5% (1/20). For a 1.5 ms pulse, that’s 7.5%. For a 2 ms pulse, that’s 10%.
So to set the servo to 90 degrees, you’d set the duty cycle to 7.5%. But wait—different servos have slightly different ranges. Some SG90s might only respond between 2.5% and 12.5% duty. That’s why we’ll define a helper function to convert angles to duty cycles, with a safe range.
The Angle-to-Duty-Cycle Conversion
Here’s a linear mapping that works for most micro servos:
python def angle_to_duty_cycle(angle, min_angle=0, max_angle=180, min_duty=2.5, max_duty=12.5): # Clamp the angle to the valid range angle = max(min_angle, min(max_angle, angle)) # Linear interpolation duty = min_duty + (angle - min_angle) * (max_duty - min_duty) / (max_angle - min_angle) return duty
For a 0-degree angle, this gives 2.5% duty (0.5 ms pulse). For 180 degrees, it gives 12.5% (2.5 ms pulse). This is a bit wider than the theoretical 1-2 ms, but it compensates for the real-world quirks of cheap micro servos.
The Full Sweep Script
Here’s a complete script that sweeps the servo smoothly. I’ll add comments so you can follow along.
python import RPi.GPIO as GPIO import time
Set up GPIO using BCM numbering
GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)
Use GPIO 18 for the servo signal
SERVOPIN = 18 GPIO.setup(SERVOPIN, GPIO.OUT)
Create PWM object at 50 Hz
pwm = GPIO.PWM(SERVO_PIN, 50) pwm.start(0) # Start with 0% duty cycle (no signal)
def angletoduty_cycle(angle): """Convert an angle (0-180) to a duty cycle percentage.""" angle = max(0, min(180, angle)) # Clamp # Map 0-180 to 2.5-12.5 duty cycle return 2.5 + (angle / 180.0) * 10.0
try: # Sweep from 0 to 180 in 5-degree steps for angle in range(0, 181, 5): duty = angletoduty_cycle(angle) pwm.ChangeDutyCycle(duty) print(f"Angle: {angle}° Duty cycle: {duty:.2f}%") time.sleep(0.1) # Wait 100 ms so the servo can catch up
# Sweep back down for angle in range(180, -1, -5): duty = angle_to_duty_cycle(angle) pwm.ChangeDutyCycle(duty) print(f"Angle: {angle}° Duty cycle: {duty:.2f}%") time.sleep(0.1) # Hold at 90 degrees for 2 seconds pwm.ChangeDutyCycle(angle_to_duty_cycle(90)) time.sleep(2) except KeyboardInterrupt: pass
finally: pwm.stop() GPIO.cleanup()
Run this script with sudo python3 servo_sweep.py. You should see the servo sweep back and forth. If it twitches or buzzes but doesn’t move, your duty cycle range might be off. Try adjusting min_duty and max_duty in the conversion function.
Why sudo? (A Quick Note)
RPi.GPIO requires root permissions to access the hardware registers. So you’ll need to run your script with sudo. This is a common gotcha for beginners. If you forget, you’ll get a permission error. If you’re using a virtual environment, make sure you run sudo with the correct Python path.
Fine-Tuning Your Micro Servo (The Calibration Dance)
Every micro servo is a little different. The SG90 from one manufacturer might have a slightly different pulse range than the same model from another. Here’s how to calibrate yours:
Step 1: Find the Center (90 Degrees)
Set the duty cycle to 7.5% and observe the servo. It should be roughly centered. If it’s not, adjust the duty cycle slowly (in 0.1% increments) until the shaft is exactly perpendicular to the case.
Step 2: Find the Minimum and Maximum
Manually set the duty cycle to 2.5% and see if the servo stops at 0 degrees without buzzing. If it buzzes, it’s trying to go further—reduce the minimum duty cycle slightly (e.g., 2.0%). Do the same for 12.5% at 180 degrees. The goal is to find the widest range that doesn’t cause buzzing or stalling.
Step 3: Update Your Conversion Function
Once you’ve found the actual min and max duty cycles, update your angle_to_duty_cycle function accordingly. This ensures smooth, accurate positioning across the full range.
Common Beginner Mistakes (And How to Avoid Them)
Let me save you some frustration. Here are the top five mistakes I see with micro servos and Raspberry Pi:
Mistake #1: Powering the Servo From the Pi’s 5V Pin
The Pi’s 5V pin can only supply a few hundred milliamps before the voltage drops. When the servo starts moving, it can draw 250-500 mA. That voltage drop can reboot your Pi. Always use an external supply.
Mistake #2: Forgetting the Common Ground
This is the most common cause of “my servo twitches but doesn’t move.” The signal from the Pi needs a reference voltage, and that reference is ground. If the grounds aren’t connected, the signal is floating. Connect them.
Mistake #3: Using Too High a Frequency
Some beginners set the PWM frequency to 1000 Hz or higher, thinking it’ll be smoother. That’s wrong. Micro servos expect 50 Hz. A higher frequency will cause the servo to overheat and buzz loudly.
Mistake #4: Not Calling pwm.start(0)
If you call pwm.start(7.5) directly, the servo will jump to that position immediately, which is fine. But if you call pwm.start(0) and then ChangeDutyCycle(), you have a cleaner starting point. Also, always stop the PWM and clean up in a finally block to avoid leaving the GPIO in a weird state.
Mistake #5: Using a 3.3V Logic Level on a 5V Servo
The servo’s signal line expects a 3.3V or 5V logic high. The Pi outputs 3.3V, which is perfectly fine for most micro servos. But if you have an old or industrial servo that requires 5V logic, you’ll need a level shifter. For SG90/MG90S, 3.3V is safe and works.
Beyond the Sweep: Interactive Control With a Keyboard
Now that you have the basics down, let’s make it interactive. Here’s a script that lets you control the servo with your keyboard using input(). You can type an angle (0-180) and press Enter, and the servo will move there.
python import RPi.GPIO as GPIO import time
GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)
SERVOPIN = 18 GPIO.setup(SERVOPIN, GPIO.OUT)
pwm = GPIO.PWM(SERVO_PIN, 50) pwm.start(0)
def angletoduty(angle): angle = max(0, min(180, angle)) return 2.5 + (angle / 180.0) * 10.0
try: while True: userinput = input("Enter angle (0-180) or 'q' to quit: ") if userinput.lower() == 'q': break try: angle = float(userinput) duty = angleto_duty(angle) pwm.ChangeDutyCycle(duty) print(f"Moving to {angle}° (duty {duty:.2f}%)") except ValueError: print("Invalid input. Please enter a number.")
except KeyboardInterrupt: pass
finally: pwm.stop() GPIO.cleanup()
This is a great starting point for a pan-tilt camera mount or a robotic arm. You can easily extend it to read from a gamepad, a web interface, or a sensor.
Controlling Multiple Micro Servos (Without Losing Your Mind)
You can control multiple servos using the same RPi.GPIO library, but there’s a catch. Software PWM uses a single thread to toggle all pins, so if you have several servos, they might experience slight timing jitter. For two or three servos, it’s fine. For more, you’ll want a dedicated PWM controller.
Here’s how to control two servos: just create two PWM objects on different pins.
python servo1pin = 18 servo2pin = 23
GPIO.setup(servo1pin, GPIO.OUT) GPIO.setup(servo2pin, GPIO.OUT)
pwm1 = GPIO.PWM(servo1pin, 50) pwm2 = GPIO.PWM(servo2pin, 50)
pwm1.start(0) pwm2.start(0)
Move servo 1 to 90 degrees, servo 2 to 45 degrees
pwm1.ChangeDutyCycle(angletoduty(90)) pwm2.ChangeDutyCycle(angletoduty(45))
Remember: each servo still needs its own external power supply (or a shared one with enough current). A 5V 2A supply can easily drive two SG90s.
What About RPi.GPIO vs. pigpio vs. gpiozero?
You might see other libraries mentioned online. Here’s a quick comparison:
RPi.GPIO: The classic. Simple, widely documented, but software PWM is not super precise. Perfect for beginners.pigpio: Uses the Pi’s DMA hardware for very accurate PWM. Great for multiple servos or high-frequency signals. But it requires a daemon to be running.gpiozero: Built on top ofRPi.GPIOandpigpio. It has a high-levelServoclass that handles the angle conversion for you. It’s worth checking out after you understand the low-level details.
For this tutorial, stick with RPi.GPIO because it teaches you the underlying mechanics. Once you’ve mastered it, you can graduate to gpiozero and appreciate the abstraction.
A Practical Project: Pan-Tilt Camera Mount
Let’s put everything together into a mini project. You’ll need two micro servos:
- Servo 1 (horizontal) on GPIO 18
- Servo 2 (vertical) on GPIO 23
You can mount them in a cheap plastic pan-tilt bracket (about $10 on Amazon). Here’s a script that sweeps both servos in a pattern, simulating a security camera.
python import RPi.GPIO as GPIO import time
GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)
panpin = 18 tiltpin = 23
GPIO.setup(panpin, GPIO.OUT) GPIO.setup(tiltpin, GPIO.OUT)
pan = GPIO.PWM(panpin, 50) tilt = GPIO.PWM(tiltpin, 50)
pan.start(0) tilt.start(0)
def angletoduty(angle): angle = max(0, min(180, angle)) return 2.5 + (angle / 180.0) * 10.0
try: # Pan left to right, tilt up and down for panangle in range(0, 181, 10): pan.ChangeDutyCycle(angletoduty(panangle)) # Tilt based on sine wave for smooth motion tiltangle = 90 + int(30 * import('math').sin(panangle * 3.14159 / 180)) tilt.ChangeDutyCycle(angletoduty(tilt_angle)) time.sleep(0.1)
for pan_angle in range(180, -1, -10): pan.ChangeDutyCycle(angle_to_duty(pan_angle)) tilt_angle = 90 + int(30 * __import__('math').sin(pan_angle * 3.14159 / 180)) tilt.ChangeDutyCycle(angle_to_duty(tilt_angle)) time.sleep(0.1) except KeyboardInterrupt: pass
finally: pan.stop() tilt.stop() GPIO.cleanup()
This is a fun, tactile way to see your servos working together. It also demonstrates how to synchronize multiple axes.
Troubleshooting Cheat Sheet (When Things Go Wrong)
- Servo doesn’t move at all → Check power. Is the red wire getting 5V? Is the ground connected? Is the signal wire on the right GPIO pin?
- Servo buzzes but doesn’t move → The duty cycle is likely out of range. It’s trying to go beyond its physical limit. Adjust your min/max duty values.
- Servo moves erratically or jitters → Common ground issue. Also, try adding a 100 µF capacitor across the servo’s power pins to smooth out voltage spikes.
- Pi reboots when the servo moves → Your power supply is too weak. Use a dedicated 5V 2A supply for the servo, not the Pi’s 5V pin.
RPi.GPIOpermission errors → Run withsudo. Or, if you want to avoidsudo, add your user to thegpiogroup (but that’s a more advanced setup).
Final Thoughts on Micro Servos and Raspberry Pi
The combination of a Raspberry Pi and a micro servo is the gateway drug to physical computing. With just a few lines of Python, you can make something move in the real world. The RPi.GPIO library might not be the fanciest tool, but it’s reliable, well-documented, and perfect for learning the fundamentals of PWM.
Once you’re comfortable with this, try adding a potentiometer to manually control the servo, or hook up a distance sensor to create a servo-driven radar. The possibilities are endless. Just remember: respect the power supply, share the ground, and always start with a low duty cycle to avoid slamming your servo into its mechanical stops.
Now go grab an SG90, wire it up, and make something move. Your Raspberry Pi is waiting.
Copyright Statement:
Author: Micro Servo Motor
Source: Micro Servo Motor
The copyright of this article belongs to the author. Reproduction is not allowed without permission.
Recommended Blog
- Advanced Servo Control Techniques Using Raspberry Pi
- How to Connect a Servo Motor to Raspberry Pi Using Jumper Wires
- Using Raspberry Pi to Control Servo Motors in Automated Inspection and Sorting Systems
- Creating a Servo-Controlled Automated Blinds System with Raspberry Pi
- How to Use Raspberry Pi to Control Servo Motors in CNC Machines
- Getting Started with Micro Servo Motors and Raspberry Pi
- Building a Servo-Powered Automated Sorting Robot with Raspberry Pi and Sensors
- Creating a Servo-Controlled Automated Sorting Machine with Raspberry Pi and Sensors
- Using Raspberry Pi to Control Servo Motors in IoT Applications
- Using Raspberry Pi to Control Servo Motors in Automated Sorting Systems
About Us
- Lucas Bennett
- Welcome to my blog!
Hot Blog
- Diagnosing and Fixing RC Car ESC Throttle Limiting Issues
- What Is Inside a Micro Servo Motor? Components and Functions
- The Relationship Between Motor Torque and Efficiency
- How to Use Raspberry Pi to Control Servo Motors in CNC Machines
- How Micro Servo Motors Prevent Overshooting Position
- Getting Started with Micro Servo Motors and Raspberry Pi
- Building a Servo-Powered Automated Sorting Robot with Raspberry Pi and Sensors
- Smart Shelf Displays using Servo-Controlled Tilt Mechanics
- Effects of Shock & Impact on Micro Servo Gimbals after Hard Landings
- How to Calibrate Micro Servo Motors for Accurate Movement
Latest Blog
- The Best Micro Servo Motors for Educational Robotics Kits
- How to Control Servo Motors Using Raspberry Pi and the RPi.GPIO Library for Beginners
- How to Find Quality Micro Servo Motors on a Budget
- The Importance of Thermal Modeling in Motor Design
- The Role of PWM in Signal Modulation: Applications and Techniques
- Micro Servo Motors in Environmental Monitoring: Applications and Benefits
- Best Practices for Securing Micro Servos in RC Boats to Prevent Water Ingress
- Advanced Servo Control Techniques Using Raspberry Pi
- How to Connect a Servo Motor to Raspberry Pi Using Jumper Wires
- Wire Length & Connector Type: Micro Servo Wiring in RC Boats
- Which Servo Offers Better Resolution: Micro or Standard?
- How PWM Shapes Define Micro Servo Motor Behavior
- Micro Servo Motors in Smart Financial Systems: Applications and Benefits
- The Evolution of Micro Servo Motors: Top Brands Over the Years
- The Importance of Gear Ratio in Servo Motor Performance
- The Impact of Gear Materials on Servo Motor Performance Under Varying Signal Serviceability
- Micro Servo vs Standard Servo for RC Airplanes
- How Advanced Communication Protocols are Enhancing Micro Servo Motors
- The Future of Micro Servo Motors in Artificial Intelligence Applications
- How to Connect a Micro Servo Motor to Arduino MKR IoT Bundle