fbpixel
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

16-channel-pwm-controller-pca9685-module Using a PCA9685 module with Raspberry Pi

Hardware

  • 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.

16-channel-pwm-controller-pca9685-module-overview Using a PCA9685 module with Raspberry Pi

Schematic

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.
16-channel-pwm-controller-pca9685-raspberry-pi_bb Using a PCA9685 module with Raspberry Pi
raspberrypi-gpio-wiringpi-pinout Using a PCA9685 module with Raspberry Pi

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 -*-

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

#Constants
nbPCAServo=16 

#Parameters
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]

#Objects
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():

	pcaScenario();


# 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
			time.sleep(0.01)
		for j in range(MAX_ANG[i],MIN_ANG[i],-1):
			print("Send angle {} to Servo {}".format(j,i))
			pca.servo[i].angle = j
			time.sleep(0.01)
		pca.servo[i].angle=None #disable channel
		time.sleep(0.5)




if __name__ == '__main__':
	init()
	main()

Applications

  • Controlling the Quadrina6 robot

Sources