Control servos with a Raspberry Pi

Use your Raspberry Pi to move parts of a robot or control anything that can rotate

The servo is used to rotate the volume control right to increase the volume, or left to decrease it

Servos are similar to motors, but can typically only move from 0 to 60/120/180 degrees, rather than rotate continuously. Unlike a motor, you send a servo a signal that makes it go to a specific position (eg 30 degrees), making them ideal for applications such as moving parts of robots, or controlling surfaces on an aircraft. That’s a little complicated to cover in this tutorial – a simpler use case is using a servo to turn an analogue potentiometer. Here we are going to create some simple software that will allow a Raspberry Pi to control the volume knob on a simple speaker amplifier, which could be used as part of a remote control project. This step- by-step tutorial assumes that you have already soldered the pin headers onto the Adafruit board.

The servo is used to rotate the volume control right to increase the volume, or left to decrease it
The servo is used to rotate the volume control right to increase the volume, or left to decrease it

What you’ll need

Latest Raspbian image
Adafruit PCA9685 servo controller
5V power supply
Female-to-female jumper cables
A servo suited to your needs


Step 01 Install software and configure I2C

We will start off with the usual ‘apt-get’ lines. Simply enter the following commands in order to download and install the required software:

$ sudo apt-get update

$ sudo apt-get install python-smbus i2c-tools git

$ git clone

By default, the I2C modules are blacklisted. To change this, run:

$ sudo nano /etc/modprobe.d/raspi-blacklist.conf

…and comment out the following lines by putting a # in front of each of them:

blacklist spi-bcm2708
blacklist i2c-bcm2708

Save changes with Ctrl+O followed by Enter, then exit with Ctrl+X. Then, you also need to add the following two lines to /etc/modules:


Finally, run sudo poweroff to shut down the Raspberry Pi.

Step 02 Wire the servo controller

Wire up the servo controller, as shown in the circuit diagram. It’s essential that all power is disconnected during the wiring process. You also need to make sure that your Raspberry Pi is oriented the correct way. The OE pin on the Adafruit board stands for Output Enable and is active low, which means the output is enabled when the signal is 0V. This is why we have connected it to ground. The VCC pin on the Adafruit board should be connected to 3.3V from the Raspberry Pi and the servo power in the middle of the board should be 5V. The Raspberry Pi’s power needs to be stable – and servos often cause a voltage drop, which is why a second power supply is necessary.

A handy wiring diagram for the projects
A handy wiring diagram for the projects

Step 03 Test the connection to the servo controller

We will use a program called i2cdetect to detect the servo controller. If you are using an older Raspberry Pi then the I2C bus is 0, otherwise the I2C bus is 1. Type sudo i2cdetect -y 1, where 1 is the I2C bus number. You should see an output similar to the one in the image. Try the other I2C bus and, if not, then it’s likely you’ve wired something wrong.


Step 04 Servo Hello World

Change directory into where you git-cloned the Adafruit Raspberry Pi code (it was probably /home/pi). Then run the following commands:

$ cd Adafruit-Raspberry-Pi-Python-Code

$ cd Adafruit_PWM_Servo_Driver

$ sudo python2

If your servo is connected to channel 0 of the Adafruit board, it should start moving between its min and max positions.

Step 05 How a servo works

If you open up the code in nano, you’ll see that there isn’t much to it. This is because the Adafruit board does all of the hard work and the Raspberry Pi just tells it what to do. The Adafruit board is required because a servo requires very accurate pulse-width modulation signals to set its position. This is very hard to do on a Pi because there are so many other things going on.

If you look at the two oscilloscope traces, you can see what the Adafruit board sends to the servo. The difference in the duty cycle (the percentage of time that a signal is high) between the minimum position and maximum position is roughly 10 per cent.

Step 06 Run the code

Place the code in the same directory as the Adafruit example code and run it with sudo python2 The servo should rotate to the right when you press the up arrow and rotate to the left when you press the down arrow.

Code listing

import curses
from Adafruit_PWM_Servo_Driver import PWM

# Initialise the PWM device using the default address
pwm = PWM(0x40, debug=False)

servoMin = 150  # Min pulse length out of 4096
servoMax = 600  # Max pulse length out of 4096
maxDegree = 60 # Degrees your servo can rotate
degIncrease = 2 # Number of degrees to increase by each time

pwm.setPWMFreq(60) # Set PWM frequency to 60Hz

def setDegree(channel, d):
    degreePulse = servoMin
    degreePulse += int((servoMax - servoMin) / maxDegree) * d
    pwm.setPWM(channel, 0, degreePulse)
# Set up curses for arrow input
scr = curses.initscr()
scr.addstr(0, 0, "Servo Volume Control")
scr.addstr(1, 0, "UP to increase volume")
scr.addstr(2, 0, "DOWN to decrease volume")
scr.addstr(3, 0, "q to quit")

degree = 60 # Start off at lowest volume
setDegree(0, degree)

key = ''
while key != ord('q'):
    key = scr.getch()

    if key == curses.KEY_DOWN:
       degree += degIncrease

      if degree > maxDegree:
         degree = maxDegree

      setDegree(0, degree)

    elif key == curses.KEY_UP:
       degree -= degIncrease

       if degree < 0:
          degree = 0

       setDegree(0, degree)