--- ---

Servo Control

26 Jul 2020 - Courtney McBeth

Raspberry Pis support software PWM, so any GPIO pin can be used to control a servo. Import the GPIO library and set the pin you’ve chosen for the servo as an output:


import RPi.GPIO as GPIO

GPIO.setup(pin, GPIO.OUT)


You’ll need to know the pulse frequency that your servo expects and the range of pulse durations that it supports. For example, an SG90 microservo expects a pulse frequency of 50 Hz and has a range of motion of 180 degrees with a 0.5 ms pulse corresponding to 0 degrees and a 2.5 ms pulse corresponding to 180 degrees. To setup PWM on your pin, use this command, which returns a PWM instance that you’ll use later:


pwm = GPIO.PWM(pin, frequency) # frequency is in Hz


Now, let’s convert our pulse durations into duty cycles. Remember that the duty cycle is the percentage of the pulse cycle time (20 ms for a 50 Hz pulse) during which the pin is high. For example, pulse duration of 1 ms corresponds to a duty cycle of 5 when the frequency is 50 Hz (0.001 s * 50 Hz * 100 = 5%). To start PWM output with some initial duty cycle, use this command:


pwm.start(dutyCycle)   # 0.0 <= dutyCycle <= 100.0


To change the duty cycle / set a new angle, use this command:


pwm.ChangeDutyCycle(dutyCycle)  # 0.0 <= dutyCycle <= 100.0


When you are done with your servo, stop the PWM output and release the pin(s) you used:


pwm.stop()
GPIO.cleanup()


Here’s a script you can use to test servo functionality. This is configured for an SG90 servo on pin 11 (GPIO 17), but you can change the frequency and/or duty cycles for compatibility with any servo. Run this via terminal and stop it using control+C.


import RPi.GPIO as GPIO
import time

servoPIN = 11
GPIO.setmode(GPIO.BOARD)
GPIO.setup(servoPIN, GPIO.OUT)

p = GPIO.PWM(servoPIN, 50) # GPIO 17 for PWM with 50Hz
p.start(2.5) # Initialization
try:
  while True:
    p.ChangeDutyCycle(5)
    time.sleep(0.5)
    p.ChangeDutyCycle(7.5)
    time.sleep(0.5)
    p.ChangeDutyCycle(10)
    time.sleep(0.5)
    p.ChangeDutyCycle(12.5)
    time.sleep(0.5)
    p.ChangeDutyCycle(10)
    time.sleep(0.5)
    p.ChangeDutyCycle(7.5)
    time.sleep(0.5)
    p.ChangeDutyCycle(5)
    time.sleep(0.5)
    p.ChangeDutyCycle(2.5)
    time.sleep(0.5)
except KeyboardInterrupt:
  p.stop()
  GPIO.cleanup()