En esta pequeña entrada probaremos la libreria "Adafruit_PWMServoDriver" (de Adafruit claro esta), para controlar un par de servomotores, especificamente 2 de Vigor y 2 de Futaba (que son los que tengo a la mano), el control de posicion de los servos sera atravez del monitor serial de arduino.
Circuito:
Para el circuito utilizado un arduino nano y el modulo PCA9685, al cual le he conectado dos servomotres Vigor en el canal 0 y 1, en el canal 8 y 9 he conectado otros dos servos pero de la marca Futaba, por lo tanto el esqumatico quedaria de la siguiente forma, importante mencionar que he alimentado el modulo con una fuente extarna de 5V/1.5A.
Firmware:
Antes que nada importante haber descargado la libreria "Adafruit_PWMServoDriver" para que esto funcione adecuadamente. La rutina es sencilla, primero tenemos que saber los valores minPWM_Duty y maxPWM_Duty ya que estos seran los encargados de limitar el moviento del servo, los valores mostrados en el codigo los he obtenido con otro ejemplo basico, en el cual variaba este valor con un potenciometro y analizaba la poscion del servo para hacer una aproximacion de minPWM_Duty = 0 grados y maxPWM_Duty = 180 grados, pero tambien podrias hacer un calculo considerando que la frecuencia es de 50Hz, por lo tanto el periodo del PWM sera de 20ms y considerando que el integrado PCA9685 tiene sus salidas a una resolucion de 12 bits, por lo tanto puede tener valores de 0 a 4095.
Los valores de cada pulso para los angulos puede variar dependiendo del servo que se este utilizando asi que recomiendo darle una checa al datasheet para corroborar el dato.
La funcion "void setPosServo(uint8_t n_servo, int angulo)" permite recibir los parametros servo y angulo, el primero parametro se refiere al numero de servo que se desea activar, el segundo simplemente es el angulo deseado.
La funcion "void serialEvent(void)" procesa los datos recibidos por el puerto serial desde arduino y pasamos todo el string a un array para poder obtener los valores correctos de ServoNumber y ServoAngle y dependiero del valor recibido activamos las banderas de trabajo.
La funcion loop la dejamos para setear los valores a cada servomotor o ejecutar una rutina en automatico cuando sea el caso, el codigo completo es el siguiente:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
* | |
* Control de servomotores con el modulo PCA9685 | |
* | |
******************************************************************************* | |
* FileName: NANO_CTRLServo_PCA9685Module.ino | |
* Processor: ATmega328 | |
* Complier: Arduino v1.8.19 | |
* Author: Pedro Sánchez (MrChunckuee) | |
* Blog: http://mrchunckuee.blogspot.com/ | |
* Email: mrchunckuee.psr@gmail.com | |
* Description: Control de servomotores Vigor y Futaba con el modulo I2C | |
* PCA9685 desde el monitor serial de Arduino. | |
******************************************************************************* | |
* Rev. Date Comment | |
* v1.0.0 06/04/2025 Prueba de la libreria de adafruit. | |
******************************************************************************/ | |
#include <Wire.h> | |
#include <Adafruit_PWMServoDriver.h> | |
Adafruit_PWMServoDriver servos = Adafruit_PWMServoDriver(0x40); | |
//Servo VIGOR VS-2 | |
unsigned int maxPWM_Duty = 505; | |
unsigned int minPWM_Duty = 130; | |
//Servo FUTABA S3003 | |
//unsigned int maxPWM_Duty = 500; | |
//unsigned int minPWM_Duty = 120; | |
bool updateFlag = false, autoFlag = false; | |
uint8_t ServoNumber; | |
uint16_t ServoAngle; | |
String serialDataString; | |
uint8_t rxDataBuffer[14] = {0}; | |
void setup() { | |
servos.begin(); | |
servos.setPWMFreq(50); | |
Serial.begin(9600); | |
showTextInit(); | |
servosInit(); | |
} | |
void servosInit(void){ | |
for(char x=0; x<16; x++){ | |
setPosServo(x, 0); | |
delay(50); | |
} | |
} | |
/* | |
* Funcion para setear el servo, acepta parametros de canal y angulo. | |
*/ | |
void setPosServo(uint8_t n_servo, int angulo) { | |
int duty = map(angulo, 0, 180, minPWM_Duty, maxPWM_Duty); | |
servos.setPWM(n_servo, 0, duty); | |
} | |
/* | |
* SerialEvent occurs whenever a new data comes in the hardware serial RX. | |
* This routine is run between each time loop() runs, so using delay inside loop can delay response. | |
* Multiple bytes of data may be available. | |
*/ | |
void serialEvent(void) { | |
if (Serial.available()) { // if there is data comming | |
serialDataString = Serial.readStringUntil('\n'); // read string until newline character | |
serialDataString.toCharArray(rxDataBuffer, serialDataString.length()+1); | |
ServoNumber = ((rxDataBuffer[5]-0x30)*10) + (rxDataBuffer[6]-0x30); | |
ServoAngle = ((rxDataBuffer[8]-0x30)*10) + ((rxDataBuffer[9]-0x30)*10) + (rxDataBuffer[10]-0x30); | |
Serial.println(serialDataString); | |
if(serialDataString == "AUTO"){ | |
autoFlag = true; | |
} | |
else{ | |
autoFlag = false; | |
} | |
updateFlag = true; | |
} | |
} | |
/* | |
* Muestra informacion de uso. | |
*/ | |
void showTextInit(void){ | |
Serial.println("Arduino + PCA9685 Driver"); | |
Serial.println("mrchunckuee.blogspot.com"); | |
Serial.println("Forma de uso:"); | |
Serial.println("Tipear ServoX=POS, donde X=canal y POS=posicion en angulos de 0 a 180"); | |
Serial.println("El numero del servo es a dos diguitos, ejem. Servo00, Servo05... Servo15"); | |
Serial.println("La posicion debe ser de tres digitos ejem. 000, 058, 180."); | |
} | |
void loop() { | |
if(updateFlag){ | |
if(autoFlag){ | |
setPosServo(0, 45); | |
setPosServo(1, 45); | |
setPosServo(8, 45); | |
setPosServo(9, 45); | |
delay(1000); | |
setPosServo(0, 90); | |
setPosServo(1, 90); | |
setPosServo(8, 90); | |
setPosServo(9, 90); | |
delay(1000); | |
setPosServo(0, 180); | |
setPosServo(1, 180); | |
setPosServo(8, 180); | |
setPosServo(9, 180); | |
delay(1000); | |
} | |
else{ | |
setPosServo(ServoNumber, ServoAngle); | |
updateFlag = false; | |
} | |
} | |
} |
Los datos viualizados en el monitor serial de arduino serian de la siguiente forma, en el cual se muestra la forma de enviar los comandos, si no se envia correctamentesimplemente no va a funcionar.
La opcion AUTO ejecuta una rutina en el cual setea los servos a un par de angulos y se mantieje ahi hasta que se envie un dato distinto.
Video:
Acá un pequeño video del circuito en funcionamiento:
Descargas:
Aquí el enlace directo para DESCARGAR los archivos disponibles, también puedes revisar o descargar la información desde mi repositorio en GitHub, si no sabes como descargarlo puedes checar aquí, bueno por el momento es todo si tienes dudas, comentarios, sugerencias, inquietudes, traumas, etc. dejarlas y tratare de responder lo mas pronto posible.
Donaciones:
Si te gusta el contenido o si los recursos te son de utilidad, comparte el enlace en tus redes sociales o sitios donde creas que puede ser de interés y la otra puedes ayudarme con una donación para seguir realizando publicaciones y mejorar el contenido del sitio. También puedes hacer donaciones en especie, ya sea con componentes, tarjetas de desarrollo o herramientas. Ponte en contacto para platicar, o puedes volverte uno de nuestros sponsors.
Pido una retroalimentación avisando cada que un enlace no sirva o tenga errores al momento de abrirlo, así también si una imagen no se ve o no carga, para corregirlo en el menor tiempo posible.
Bibliografía:
- Adafruit, "Adafruit-PWM-Servo-Driver-Library", https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
0 Comentarios