Tags: , ,

The PCA9685 module is a 16-channel controller that can control 16 PWM outputs via I2C communication. Among other things, it allows you to free up inputs and outputs of your microcontroller and drive up to 16 LEDs or servomotors (or any other module taking a PWM signal as input) using two pins (SCL and SDA) while keeping the pins of your microcontroller for other modules such as sensors. The Raspberry Pi is a microcontroller with integrated Bluetooth and Wifi modules. Very easy to use, it is lightweight and has a higher memory and computing capacity than the Arduino. We will see in this tutorial how to drive several servomotors with a Raspberry Pi and a PCA9685 module.

Prerequisite : Configuration of the Raspberry Pi in I2C


  • Ordinateur
  • RapsberryPi3B+
  • PCA9685Module

Principle of operation

The module is based on the PCA9685 controller, which allows PWM outputs to be controlled using I2C communication and an integrated clock. The module has 6 bridges to select the address of the board and thus allow up to 62 controllers to be placed on the same bus for a total of 992 servomotors (addresses available 0x40 to 0x7F).
It can drive PWM outputs with adjustable frequency and 12-bit resolution. The module is compatible with 5V and 3.3V microcontrollers.


The Raspberry Pi has dedicated pins for I2C communication (GPIO2/GPIO3).
The module is equipped with an I2C bus and a power input. The I2C bus is connected as follows:

  • GPIO3 or SCL pin to the SCL pin of the module
  • GPIO2 or SDA pin to the SDA pin of the module
  • 5V pin to Vdc pin of the module
  • GND pin to GND pin of the module
    In this tutorial we use the Raspberry Pi Zero card but it can be adapted to other microcontrollers. All that is required is to adapt the I2C pins available on the microcontroller in question and possibly the code.


Library installation

To use the PCA9685 module we use the following library adafruit_servokit.h. This library is not present by default in the Python installation. To install it, simply open a terminal and enter the following command line.

sudo pip3 install adafruit-circuitpython-servokit

Script Python

PWM widths are usually given in microseconds over a period of 20ms (50Hz) but these values can vary from one servo motor to another and between suppliers. You will need to modify the code values to suit your servomotor. In our case, we use the MG90S servomotor with pulse widths between 500 and 2500µs over 20ms.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time	#https://docs.python.org/fr/3/library/time.html
from adafruit_servokit import ServoKit	#https://circuitpython.readthedocs.io/projects/servokit/en/latest/


MIN_IMP  =[500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500]
MAX_IMP  =[2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500]
MIN_ANG  =[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
MAX_ANG  =[180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180]

pca = ServoKit(channels=16)

# function init 
def init():

	for i in range(nbPCAServo):
		pca.servo[i].set_pulse_width_range(MIN_IMP[i] , MAX_IMP[i])

# function main 
def main():


# function pcaScenario 
def pcaScenario():
	"""Scenario to test servo"""
	for i in range(nbPCAServo):
		for j in range(MIN_ANG[i],MAX_ANG[i],1):
			print("Send angle {} to Servo {}".format(j,i))
			pca.servo[i].angle = j
		for j in range(MAX_ANG[i],MIN_ANG[i],-1):
			print("Send angle {} to Servo {}".format(j,i))
			pca.servo[i].angle = j
		pca.servo[i].angle=None #disable channel

if __name__ == '__main__':


  • Controlling the Quadrina6 robot


How useful was this post?

Click on a star to rate it!

Average rating 3.5 / 5. Vote count: 16

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?