Étiquettes : , , , ,

Le module PCA9685 est un contrôleur 16 canaux qui permet de piloter 16 sorties PWM via la communication I2C. Il permet entre autre de libérer des entrées sorties de votre microcontrôleur et piloter jusqu’à 16 LED ou servomoteurs (ou tout autre module prenant en entrée un signal PWM) à l’aide de deux broches (SCL et SDA) tout en conservant les broches de votre microcontrôleur pour d’autres modules comme des capteurs.

Prérequis: Piloter un servomoteur avec Arduino

Matériel

  • Ordinateur
  • ArduinoUNO
  • Câble USB A Mâle/B Mâle
  • PCA9685Module

Principe de fonctionnement

Le module est basé sur le contrôleur PCA9685 qui permet de piloter des sorties PWM à l’aide de la communication I2C et d’une horloge intégrée. Ce module comporte 6 ponts permettant de sélectionner l’adresse de la carte et ansi de placer sur le même bus jusqu’à 62 contrôleurs pour un total de 992 servomoteurs (Adresses disponibles 0x40 à 0x7F).
Il permet de piloter des sorties PWM avec une fréquence ajustable et avec une résolution de 12 bits. Le module est compatible avec les microcontrôleurs 5V et 3.3V.

Schéma

Le module est muni d’un bus I2C et d’un entrée de puissance. Le bus I2C est branché comme suit:

  • Broche A5 ou SCL à la broche SCL du module
  • Broche A4 ou SDA à la broche SDA du module
  • Broche 5V à la broche Vcc du module
  • Broche GND à la broche GND du module
    Dans ce tutoriel, nous utilisons la carte Arduino UNO mais il peut être adapté à d’autre microcontrôleur. Il suffit pour cela d’adapter les broches I2C disponibles sur le microcontrôleur en question et éventuellement le code.

Code

Pour utiliser le module PCA9685, nous utilisons la librairie Adafruit_PWMServoDriver.h. Les largeurs de PWM généralement données en microsecondes sur une période de 20ms (50Hz) mais ces valeurs peuvent changer d’un servomoteur à l’autre et entre fournisseur. Il vous faudra modifier les valeurs du code pour les adapter à votre servomoteur.
Dans notre cas, nous utilisons le servomoteur MG90S dont les plages sont 400-2400µs sur 20ms.
Pour définir la commande PWM, la librairie présente deux fonctions setPWM() et writeMicroseconds(). La fonction writeMicroseconds() nous permet d’utiliser les valeurs constructeur directement. Pour la fonction setPWM, il nous faut trouver la largeur d’impulsion correspondante sur 4096 (2^12, 12bits).
Exemple: La fréquence est de 50Hz donc une période de 20ms soit 20000µs.
pwmvalmin=400/20000*4096=81.92-> 90 en arrondissant avec une marge de sécurité
pwmvalmax=2400/20000*4096=491.52 -> 480 en arrondissant avec une marge de sécurité
Ce qui nous donne l’équivalence suivante:
pca.writeMicroseconds(i,400) équivaut à pca.setPwm(i,0,90)
et pca.writeMicroseconds(i,2400) équivaut à pca.setPwm(i,0,480)
A vous d’utiliser la fonction qui vous arrange le plus.

//Libraries
#include <Wire.h>//https://www.arduino.cc/en/reference/wire
#include <Adafruit_PWMServoDriver.h>//https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library

//Constants
#define nbPCAServo 16

//Parameters
int MIN_IMP [nbPCAServo] ={500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500};
int MAX_IMP [nbPCAServo] ={2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500};
int MIN_ANG [nbPCAServo] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int MAX_ANG [nbPCAServo] ={180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180};

//Objects
Adafruit_PWMServoDriver pca= Adafruit_PWMServoDriver(0x40);

void setup(){
//Init Serial USB
Serial.begin(9600);
Serial.println(F("Initialize System"));
pca.begin();
pca.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
}

void loop(){
	pcaScenario();
}

void pcaScenario(){/* function pcaScenario */ 
////Scenario to test servomotors controlled by PCA9685 I2C Module
for (int i=0; i<nbPCAServo; i++) {
  Serial.print("Servo");
  Serial.println(i);
			//int middleVal=((MAX_IMP[i]+MIN_IMP[i])/2)/20000*4096; // conversion µs to pwmval
			//pca.setPWM(i,0,middleVal);
			for(int pos=(MAX_IMP[i]+MIN_IMP[i])/2;pos<MAX_IMP[i];pos+=10){
				pca.writeMicroseconds(i,pos);delay(10);
			}
			for(int pos=MAX_IMP[i];pos>MIN_IMP[i];pos-=10){
				pca.writeMicroseconds(i,pos);delay(10);
			}
			for(int pos=MIN_IMP[i];pos<(MAX_IMP[i]+MIN_IMP[i])/2;pos+=10){
				pca.writeMicroseconds(i,pos);delay(10);
			}
			pca.setPin(i,0,true); // deactivate pin i
		}
}

int jointToImp(int x,int i){/* function jointToImp */ 
////Convert joint angle into pwm command value
     
			int imp=(x - MIN_ANG[i]) * (MAX_IMP[i]-MIN_IMP[i]) / (MAX_ANG[i]-MIN_ANG[i]) + MIN_IMP[i];
			imp=max(imp,MIN_IMP[i]);
			imp=min(imp,MAX_IMP[i]);
			
 return imp;
}


Applications

  • Piloter le robot Quadrina6

Sources