Raspberry Pi Program to Control Servo Motor with Python
RPi.GPIO library to control a servo motor on Raspberry Pi by setting up PWM on a GPIO pin and changing the duty cycle with code like pwm.ChangeDutyCycle(duty) to move the servo.Examples
How to Think About It
Algorithm
Code
import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) servo_pin = 18 GPIO.setup(servo_pin, GPIO.OUT) pwm = GPIO.PWM(servo_pin, 50) # 50Hz frequency pwm.start(0) def set_angle(angle): duty = 2 + (angle / 18) pwm.ChangeDutyCycle(duty) time.sleep(0.5) pwm.ChangeDutyCycle(0) try: for angle in [0, 90, 180]: print(f"Moving servo to {angle} degrees") set_angle(angle) time.sleep(1) finally: pwm.stop() GPIO.cleanup() print("Servo control finished")
Dry Run
Let's trace moving the servo to 90 degrees through the code
Calculate duty cycle
angle = 90; duty = 2 + (90 / 18) = 7.0
Change PWM duty cycle
pwm.ChangeDutyCycle(7.0)
Wait for servo to move
time.sleep(0.5)
Stop PWM signal
pwm.ChangeDutyCycle(0)
| Step | Angle | Duty Cycle | PWM Duty Cycle |
|---|---|---|---|
| 1 | 90 | 7.0 | N/A |
| 2 | 90 | 7.0 | 7.0 |
| 3 | 90 | 7.0 | 7.0 |
| 4 | 90 | 7.0 | 0 |
Why This Works
Step 1: Setup GPIO and PWM
We use GPIO.setmode(GPIO.BCM) to select pin numbering and set the servo pin as output. Then we start PWM at 50Hz because servos expect 50 pulses per second.
Step 2: Convert angle to duty cycle
The servo angle is converted to a PWM duty cycle between 2 and 12 percent using duty = 2 + (angle / 18). This matches the servo's expected pulse width range.
Step 3: Send PWM signal to servo
We change the PWM duty cycle to move the servo, wait 0.5 seconds for the servo to reach the position, then stop the signal to avoid jitter.
Step 4: Cleanup
After moving the servo, we stop PWM and clean up GPIO to free resources and avoid warnings on next run.
Alternative Approaches
import pigpio import time pi = pigpio.pi() servo_pin = 18 try: for angle in [0, 90, 180]: pulse_width = 500 + (angle * 2000 // 180) # 500-2500 microseconds print(f"Moving servo to {angle} degrees") pi.set_servo_pulsewidth(servo_pin, pulse_width) time.sleep(1) finally: pi.set_servo_pulsewidth(servo_pin, 0) pi.stop() print("Servo control finished")
from gpiozero import Servo from time import sleep servo = Servo(18) for position in [-1, 0, 1]: # -1 is 0°, 0 is 90°, 1 is 180° print(f"Moving servo to position {position}") servo.value = position sleep(1) print("Servo control finished")
Complexity: O(n) time, O(1) space
Time Complexity
The program runs a loop over n angles to move the servo, so time complexity is O(n). Each movement waits a fixed time for the servo to reach position.
Space Complexity
The program uses a fixed amount of memory for variables and GPIO setup, so space complexity is O(1).
Which Approach is Fastest?
All approaches have similar time complexity; pigpio may offer smoother control but requires extra setup. gpiozero is easiest but less flexible.
| Approach | Time | Space | Best For |
|---|---|---|---|
| RPi.GPIO PWM | O(n) | O(1) | Basic servo control with standard library |
| pigpio library | O(n) | O(1) | Precise PWM control, better for complex projects |
| gpiozero library | O(n) | O(1) | Simple and quick servo control with abstraction |