O módulo PCA9685 é um controlador de 16 canais que permite controlar 16 saídas PWM através de comunicação I2C. Seu uso libera entradas e saídas do seu microcontrolador, possibilitando conduzir até 16 LEDs ou servomotores (ou qualquer outro módulo que tome um sinal PWM como entrada) usando dois pinos (SCL e SDA). Com isso, os pinos do seu microcontrolador ficam livres para outros módulos, como sensores.
Pré-requisito: Conduzir um servomotor com o Arduino
Material
- Computador
- Arduino UNO
- Cabo USB A Macho/B Macho
- Módulo PCA9685
Princípio de funcionamento
O módulo é baseado no controlador PCA9685, que controla saídas PWM usando comunicação I2C e um relógio integrado. Este módulo comporta 6 pontes que permitem selecionar o endereço da placa e colocar, no mesmo barramento, até 62 controladores, para um total de 992 servomotores (endereços disponíveis de 0x40 a 0x7F).
Ele permite acionar saídas PWM com uma frequência ajustável e uma resolução de 12 bits. O módulo é compatível com microcontroladores de 5V e 3,3V.
Esquema
O módulo é equipado com um barramento I2C e uma entrada de energia. O barramento I2C se conecta da seguinte forma:
- Pino A5 ou SCL no pino SCL do módulo
- Pino A4 ou SDA no pino SDA do módulo
- Pino 5V no pino Vcc do módulo
- Pino GND no pino GND do módulo
Neste tutorial, usamos a placa Arduino UNO, mas ele pode ser adaptado a outros microcontroladores. Basta adaptar os pinos I2C disponíveis no microcontrolador em questão e, possivelmente, o código.
Código
Para utilizar o módulo PCA9685, usamos a biblioteca Adafruit_PWMServoDriver.h. As larguras de PWM são geralmente dadas em microssegundos por um período de 20ms (50Hz), mas estes valores podem mudar conforme o fornecedor e o servomotor utilizado. Nesse caso, é preciso modificar os valores do código para adaptá-los ao seu servomotor.
Aqui, utilizamos o servomotor MG90S, cujos gamas são de 400-2400µs por 20ms.
Para definir o comando PWM, a biblioteca apresenta duas funções: setPWM() e writeMicroseconds(). A função writeMicroseconds() permite utilizar diretamente os valores do construtor. Para a função setPWM, precisamos encontrar a largura de pulso correspondente em 4096 (2^12, 12bits).
Exemplo: A frequência é de 50Hz, logo um período de 20ms ou 20000µs.
pwmvalmin=400/20000*4096=81.92-> 90 arredondando com uma margem de segurança
pwmvalmax=2400/20000*4096=491.52 -> 480 arredondando com uma margem de segurança
Isso nos dá as seguintes equivalências:
pca.writeMicroseconds(i,400) equivale a pca.setPwm(i,0,90)
pca.writeMicroseconds(i,2400) equivale a pca.setPwm(i,0,480)
Utilize a função que melhor lhe convier.
//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(double 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; }
Aplicações
- Controlar o robô Quadrina6
Fontes
- http://adafruit.github.io/Adafruit-PWM-Servo-Driver-Library/html/class_adafruit___p_w_m_servo_driver.html#aa892432ed08e4b3892c8eb0478168dd8
- https://robojax.com/learn/arduino/robojax-PCA6985.pdf
- https://www.nxp.com/products/power-management/lighting-driver-and-controller-ics/ic-led-controllers/16-channel-12-bit-pwm-fm-plus-ic-bus-led-controller:PCA9685
- https://www.arduino.cc/en/reference/wire
- https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie