Raspberry Pi Servo Motor
Hobby servo motors are positioned to a specific angle by the width of a repeating electrical pulse, and gpiozero's Servo class lets you set that angle directly with simple method calls or a value between -1 and 1.
Position, Not Speed: How a Servo Differs from a DC Motor
A plain DC motor just spins in whichever direction current flows through it, at a speed roughly proportional to voltage - it has no idea what angle it is at. A hobby servo is a small, self-contained unit: inside its case is a DC motor, a reduction gearbox, a potentiometer that reports the output shaft's current angle, and a tiny control circuit that compares the requested angle to the actual angle and drives the motor until they match. The result is a shaft that moves to, and holds, an absolute position rather than spinning continuously.
Position Is Encoded in Pulse Width
A servo's control wire expects a pulse roughly every 20 milliseconds (about 50 times a second). What matters is not whether the pulse is on or off overall, but exactly how long the high portion of each pulse lasts. By convention a pulse of about 1 millisecond drives the shaft to one extreme, about 1.5 milliseconds centres it, and about 2 milliseconds drives it to the other extreme - with everything in between mapping smoothly to an angle across the servo's usable range, commonly around 180 degrees.
- Signal wire (often orange or yellow) connects to a GPIO pin.
- Power wire (usually red) needs 4.5 to 6V - for anything beyond a single small servo, use an external supply rather than the Pi's own 5V pin.
- Ground wire (usually brown or black) must be connected to a Pi GND pin, even when the servo is powered externally, so both circuits share a reference voltage.
Example
from gpiozero import Servo
from time import sleep
servo = Servo(17)
servo.min() # rotate to one end (~1ms pulse)
sleep(1)
servo.mid() # move to centre (~1.5ms pulse)
sleep(1)
servo.max() # rotate to the other end (~2ms pulse)
sleep(1)Example
from gpiozero import Servo
from time import sleep
# Correct for a servo whose usable pulse range is narrower than gpiozero's default
servo = Servo(17, min_pulse_width=1/1000, max_pulse_width=2/1000)
for position in [-1, -0.5, 0, 0.5, 1]:
servo.value = position
sleep(0.8)Continuous-Rotation Servos Are a Different Beast
Some servos sold in the same style of case are modified internally to remove the position feedback entirely, turning them into a geared motor that spins continuously. With those, gpiozero's Servo class still works and still reads pulse widths, but the value now maps to spin speed and direction rather than an angle - value 0 stops it, positive values spin one way, negative values spin the other. Everything above about angles assumes a standard positional servo.
Exercise: Raspberry Pi PWM
What does PWM stand for and fundamentally do?