Icono del sitio AranaCorp

Usando un módulo PCA9685 con Arduino

El módulo PCA9685 es un controlador de 16 canales que puede controlar 16 salidas PWM a través de la comunicación I2C. Permite, entre otras cosas, liberar las entradas y salidas de su microcontrolador y manejar hasta 16 LEDs o servomotores (o cualquier otro módulo que tome una señal PWM como entrada) usando dos pines (SCL y SDA) mientras mantiene los pines de su microcontrolador para otros módulos como los sensores.

Prerrequisitos: Conducir un servomotor con Arduino

Hardware

Principio de funcionamiento

El módulo se basa en el controlador PCA9685, que permite controlar las salidas PWM mediante la comunicación I2C y un reloj integrado. Este módulo tiene 6 puentes para seleccionar la dirección de la placa y para colocar en el mismo bus hasta 62 controladores para un total de 992 actuadores (direcciones disponibles 0x40 a 0x7F).
Puede manejar salidas PWM con frecuencia ajustable y resolución de 12 bits. El módulo es compatible con microcontroladores de 5V y 3.3V.

Diagrama

El módulo está equipado con un bus I2C y una entrada de energía. El bus I2C está conectado de la siguiente manera:

Código

Para usar el módulo PCA9685, usamos la biblioteca Adafruit_PWMServoDriver.h. Los anchos de los PWM suelen darse en microsegundos durante un período de 20ms (50Hz), pero estos valores pueden cambiar de un actuador a otro y entre proveedores. Tendrá que modificar los valores del código para adaptarlos a su actuador.
En nuestro caso, utilizamos el actuador MG90S cuyos rangos son de 400-2400µs sobre 20ms.

Para establecer el comando PWM, la biblioteca proporciona dos funciones: setPWM() y writeMicroseconds(). La función writeMicroseconds() nos permite usar los valores del constructor directamente. Para la función setPWM, necesitamos encontrar el ancho de pulso correspondiente en el 4096 (2^12, 12bits).

Ejemplo: La frecuencia es de 50Hz por lo que un período de 20ms o 20000µs.
pwmvalmin=400/200004096=81.92-> 90 redondeo con un margen de seguridad pwmvalmax=2400/200004096=491.52 -> 480 redondeo con un margen de seguridad


Lo que nos da la siguiente equivalencia:
pca.writeMicrosegundos(i,400) es igual a pca.setPwm(i,0,90)
y pca.writeMicrosegundos(i,2400) es igual a pca.setPwm(i,0,480)
Depende de ti usar la función que más te convenga.

//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;
}

Aplicaciones

Fuentes

Salir de la versión móvil