PWM Servo Control with Raspberry Pi
Pulse-Width Modulation (PWM) is a highly efficient technique used to
control the precise position of servo motors by varying the width of
electrical pulses. This article provides a comprehensive guide on how to
utilize a Raspberry Pi to generate PWM signals, wire the hardware
safely, and write Python code using libraries like gpiozero
to command a servo motor to specific angles.
Understanding PWM and Servo Motors
Servo motors rely on a specific PWM frequency, typically 50Hz (which translates to a 20ms period), to determine their rotational position. The duration of the “on” time—known as the pulse width—tells the servo where to move.
- 1.0 ms pulse: Moves the servo to its minimum angle (usually 0°).
- 1.5 ms pulse: Centers the servo (usually 90°).
- 2.0 ms pulse: Moves the servo to its maximum angle (usually 180°).
The ratio of the pulse width to the total period is called the Duty Cycle. For a 50Hz signal, a 1.5ms pulse translates to a 7.5% duty cycle.
Hardware Wiring and Power Requirements
Standard servo motors can draw more current than the Raspberry Pi’s 5V pins can safely supply, especially under load. It is crucial to use an external 5V power supply to prevent your Raspberry Pi from crashing or suffering permanent damage.
| Servo Wire Color | Connection Target | Notes |
|---|---|---|
| Ground (Brown/Black) | External Power Supply (-) AND Raspberry Pi GND | Must share a common ground |
| Power (Red) | External Power Supply (+) | Typically 5V to 6V |
| Signal (Yellow/Orange) | Raspberry Pi GPIO Pin (e.g., GPIO 18) | Delivers the PWM command |
Important Note: Always connect the ground (GND) pin of the Raspberry Pi to the negative terminal of the external power supply. Without a common ground, the PWM signal will lack a stable reference point, causing the servo to jitter violently or fail to move.
Python Implementation using GPIO Zero
The gpiozero library is the most modern and
straightforward tool for controlling servos on a Raspberry Pi. It
automatically handles the underlying duty cycle calculations behind the
scenes.
First, ensure your system is updated and the library is installed:
sudo apt update
sudo apt install python3-gpiozeroYou can then use the following Python script to sweep the servo back and forth:
from gpiozero import Servo
from time import sleep
# Class default uses a standard pulse width range (1ms to 2ms)
# Connected to Raspberry Pi GPIO pin 18
servo = Servo(18)
try:
while True:
print("Setting servo to minimum position")
servo.min()
sleep(2)
print("Setting servo to mid position")
servo.mid()
sleep(2)
print("Setting servo to maximum position")
servo.max()
sleep(2)
except KeyboardInterrupt:
print("Program stopped by user")Fine-Tuning the Pulse Width
Not all servo motors are calibrated identically. If your servo is
hitting its physical limits or not rotating a full 180 degrees, you can
fine-tune the minimum and maximum pulse widths by using the
Servo class parameters.
from gpiozero import Servo
# Fine-tuning for a servo that expects 0.5ms to 2.5ms pulses
my_factory_target = Servo(18, min_pulse_width=0.5/1000, max_pulse_width=2.5/1000)By adjusting these thresholds and utilizing the gpiozero
library, the Raspberry Pi can achieve reliable, hardware-timed PWM
control over any standard hobby servo.