Para mover el cuerpo de nuestro robot necesitaremos conocer y controlar los llamados servomotores

¿Qué son ellos?

Un servomotor es un motor eléctrico al que podemos controlar tanto la velocidad, como la posición del eje que gira (también llamada dirección del eje o giro del rotor).

Por lo general los servomotores giran 180º hacia la izquierda o hacia la derecha (ida y retorno).
Las características principales de un servomotor son el par y la velocidad.

El par: fuerza que es capaz de hacer en su eje. El par también se puede llamar torque. Se suele expresar en Kg/cm, por ejemplo 3Kg/cm. A mayor par, mayor corriente de consumo del servo, pero no suelen consumir mucho, dependiendo del tipo de servomotor.

Velocidad: velocidad angular o de rotación.

Normalmente la tensión de alimentación de los servos en c.c. está entre 4 y 8V (voltios).


Usos de un Servomotor

Los servomotores industriales (para uso de la industria) tienen una gran cantidad de usos. Algunos de ellos puede ser: Robótica, brazos, zoom de una cámara de fotos, puertas automáticas de un ascensor, en las impresoras para el control de avance y retroceso del papel, máquinas herramientas, robots industriales, sistemas de producción, coches de radiocontrol, en el timón de los aviones, timones.


En los sistemas se seguimiento solar, para el movimiento de los paneles solares en dirección del Sol, también se utilizan servomotores. En fresadoras, tornos, máquinas de troquelado, etc... que son máquinas que se utilizan en la industria para hacer cortes, se utilizan los servomotores para controlar los cortes y poder hacerlos muy precisos.


Partes de un Servomotor


Un servomotor es un sistema compuesto por:

- Un motor eléctrico: es el encargado de generar el movimiento, a través de su eje.

- Un sistema de regulación: formado por engranajes, que actúan sobre el motor para regular su velocidad y el par. Mediante estos engranajes, normalmente ruedas dentadas, podemos aumentar la velocidad y el par o disminuirlas.

- Un sistema de control o sensor: circuito electrónico que controla el movimiento del motor mediante el envío de pulsos eléctricos.

- Un potenciómetro: conectado al eje central del motor que nos permite saber en todo momento el ángulo en el que se encuentra el eje del motor. Recuerda que potenciómetro es una resistencia eléctrica variable.

¿Cómo Funciona un ServoMotor?


Funciona por medio de pulsos eléctricos. 


Manejo preciso de servos en Arduino: grados y milisegundos


Una señal se comprueba con osciloscopio. Por suerte dispongo tanto de uno antiguo, con pantalla CRT, como de los que se pueden comprar ahora dentro de la familia Arduino, dotado de un pantalla TFT.

Para programar un servo Arduino usa la biblioteca Servo.h. También ofrece una herramienta (en la función servo.attach) que, bueno, puede ser que no hayamos investigado y que por algo está disponible. Esto puede parecer algo para principiantes, pero hasta que uno empieza a tener estas complicaciones no se da cuenta, y luego de tener una comprensión mejor se logra usar la biblioteca de servo de Arduino con facilidad y dominando lo que hace.

Función write()

La razón de ser de una biblioteca es que uno se pueda desentender del manejo de programa específico de un elemento conectado a una placa de microcontrolador, y bueno, la biblioteca Servo de Arduino fue hecha para facilitar el control de los servos con un mínimo de código y complicaciones. La página de referencia de Arduino para el comando write(), que es parte de la biblioteca Servo.h, trae el siguiente código de ejemplo:

Este código de ejemplo le indica a un servo, conectado en este caso al pin 9, que se mueva a su posición central (que se define como 90°). Si se tratara de un servo de rotación continua, esto detendrá el movimiento del servo… pero este es tema para otro artículo.

Al correr este pequeño programa de demostración, los servos que se han conectado a ese pin se colocarán en sus posiciones centrales. Pero bueno, si lo consideramos desde la faceta mecánica, este punto medio puede que en algunos servos no sea exactamente el centro del arco completo del recorrido.

Un pulso con un ancho de 1.500 microsegundos debe corresponder a 90°, posición definida como el punto central del recorrido. Los servos más comunes aceptan entradas de 1.000 µs (1 ms) a 2.000 µs (2 ms), y 1.500 µs (1,5 ms) correspondientes a la posición central. Para un servo con un recorrido de 0 a 180°, esto sería 90°.





Ahora me toca aclarar que siempre utilicé valores en microsegundos para controlar servos, ya que la precisión del posicionamiento es mucho mayor. La biblioteca de servos permite usar el comando writeMicroseconds, que define el ancho de pulso exacto que se desea enviar a un servo. Los problemas comienzan cuando se usan ejemplos —ya escritos— en los que se utiliza el comando de escritura con un parámetro en grados (en el ejemplo de arriba, 90°).

Parecería lógico que un comando de escritura que instruye a un servo para que se ajuste a 90° debería enviar los mismos pulsos que un comando writeMicroseconds que envía pulsos de 1.500 µs. Es decir, write(90) y writeMicroseconds(1500) deberían enviar pulsos idénticos de 1500 µs. Pero resulta que esta suposición puede llevarnos a problemas.

Basándome en un ejemplo de internet, subí el siguiente código a un Arduino UNO R3, y visualicé las señales con osciloscopio.

Aquí es cómo se ven las salidas de los pines 34 y 5:

■ El pin 3 de Arduino, fijado en 90°, da un pulso de 1,472 ms
■ El pin 4 de Arduino produce un pulso de 1.500 µs: 1,500 ms
■ El pin 5 de Arduino, fijado en 90°, da un pulso de 1,500 ms

El ancho de pulso se mide con el programa del osciloscopio. Por las dudas de que sea un problema técnico del osciloscopio, midiendo con un papel superpuesto sobre la pantalla se puede observar que sí existe la diferencia.

Y también al superponer señales, se observa la diferencia.

Esta diferencia entre 1.472 µs y 1.500 µs es pequeña y puede ser que ni siquiera implique diferencias en las posiciones del servo.

Si se observa la señal de servo3, que también programa el movimiento del servo con el parámetro de colocarse en posición de 90°, se nota que el ancho del pulso es correcto, 1.500 µs, el mismo que para servo2, para el que se fijó el pulso en forma directa en 1.500 µs.

El comando write(90) es el mismo en la primera y la tercera señal de servo, así que… ¿por qué uno envía un pulso de 1,472 ms y el otro 1,500 ms?

Arduino attach()

La respuesta está en el comando attach de la librería Servo. La página de referencia de Arduino enumera dos formas del comando:

La primera versión es el código mínimo que requiere un programa para designar un pin de E/S para el control de un servo. El segundo formato incluye dos parámetros muy importantes, pero opcionales, que determinan el rango mínimo y máximo de ancho de pulso para el programa. Es posible que en el ejemplo de arriba, el uso de límites en el segundo servo haya acomodado los valores de tiempo para que el tercero reciba un pulso correcto; pero al volver el bucle al principio y correr la función para 90º sin topes definidos, se vuelve a desacomodar.

Tanto en la página de referencia del comando attach en arduino.cc como en la propia biblioteca Servo, se establece claramente que las configuraciones mínimas y máximas predeterminadas son 544 y 2.400 µs, respectivamente. Pero como hay servos con diferentes extremos de carrera, se pueden fijar estos límites “opcionales” de ancho de pulso, que en realidad —para evitar dolores de cabeza y roturas de los servos— sería bueno acostumbrarse a usar.

Si uno está habituado a usar el comando writeMicroseconds en lugar de write, es posible que nunca haya pensado en los parámetros de ancho de pulso mínimo y máximo. Pero si se usa el comando write y se establecen las posiciones de los servos con ángulos y grados, entonces DEBEMOS definir explícitamente estos parámetros en los programas de Arduino que usan Servo.h, previa lectura de los datos indicados en la hoja de datos del servo utilizado. O si no, definiéndolos experimentalmente; porque hasta existen diferencias entre servos del mismo modelo.

Para definir los valores correctos de extremos de recorrido de un servo, puede utilizar un montaje como el que sigue, que se trata de una cartulina impresa y una aguja señaladora de cartón en el eje del servo, y enviar comandos con writeMicroseconds() hasta lograr el valor para el ángulo cero y el ángulo 180. El disco lo imprimí con un programa on-line muy útil para crear imágenes de discos de encoder.

Ingrese a esta página y pruebe primero con los siguientes parámetros:

Luego puede jugar con los valores hasta lograr el dibujo que usted necesite. Hay otras opciones en internet, incluso hay generadores de código postscript que se puede leer en Corel y que corren en Windows. Es cuestión de buscar.

Solución para la librería Servo

En el código de ejemplo, para la tercera señal de servo no dejaremos los anchos de pulso predeterminados y fijaremos los límites con los valores 1.000 y 2.000 µs. Esta es la razón por la que las señales del primero y tercer servo envían pulsos diferentes aunque se utilicen comandos idénticos.

Además de que no lograremos posicionamientos correctos de los servos con señales ligeramente descentradas, un servo podría interpretar de manera impredecible los anchos de pulso por encima o por debajo de los límites para los que fue diseñado. Los pulsos por debajo y por encima del límite también pueden dañar físicamente un servo.

Si un servo con recorrido de 0 a 180° está diseñado para responder a pulsos de 1.000-2.000 µs, interpretará 1.000 µs como 0°, y 2.000 µs como 180°. Pero, con un rango de límites de ancho de pulso predeterminado de 544 a 2.400 µs, el Arduino enviará una señal de ~1.000 µs para un ángulo de 44°. Un rango de pulsos de 1.000 a 2.000 µs se convertirá en un recorrido mecánico total de ~90° del eje del servo en lugar de 180°. Este y otros problemas potenciales pueden evitarse si se usan microsegundos en lugar de ángulos en grados, o si los parámetros opcionales de ancho de pulso para los extremos se definen en la configuración de pines para cada servo.

Es muy común que se dé por sentado que las bibliotecas de Arduino funcionan correctamente con sólo unos simples parámetros. La próxima vez que sus servos actúen de forma impredecible en un nuevo proyecto, vuelva a verificar que ha establecido los límites de ancho de pulso en la configuración del pin. Puede que con esto sea suficiente y se ahorre gran cantidad de tiempo.

Aquí les dejo una explicación breve y un ejemplo para poner en práctica👇


✔Otro ejercicio que deben aprender es usar los servomotores (pequeños motores de arduino)

Aquí les dejo un ejemplo que me pareció super claro para aplicar en dos servos👇


💻Otro proyecto con Servos

 

 CONTROLADOR DE SERVOS  CON ARDUINO


Tutorial Módulo Controlador de servos PCA9685 con Arduino

EL controlador PCA9685 fue diseñado para controlar leds por PWM, pero también nos permite controlar servos, ya que estos también se controlan por PWM, aplicación que actualmente es muy usada.


El Módulo Controlador de servos PCA9685 tiene la placa diseñada para el control de servos, tiene los pines en el orden correcto para simplemente conectar los servomotores, además una bornera para la alimentación de los servos y conectores para la alimentación de la parte lógica junto con los pines I2C para comunicarse con arduino.

Se puede establecer la dirección I2C soldando los puentes A0-A5 con esto podemos usar el mismo bus I2C para controlar más módulos PCA9685 u otros dispositivos I2C

 Módulo Controlador de servos PCA9685

EL PCA9685 nos permite controlar individualmente 16 salidas PWM con 12 bits de resolución y con frecuencia máxima de 1600Hz.

La salida PWM que envía el PCA9685 es de la siguiente forma:

 Pulso PWM PCA9685

 

Básicamente lo se tiene que establecer es la frecuencia de la señal PWM, frecuencia que será la misma para las 16 salidas PWM. Para establecer el ciclo de trabajo (Duty) tenemos que manipular el flanco de subida (Up) y flanco de bajada (Down), esto se configura individualmente para cada salida PWM, La resolución del PWM es de 12 bits (de 0 a 4095)


Conexión Entre Arduino y Modulo PCA9685

 

Módulo PCA9685

Arduino Uno, Nano, Mini.


  GND

GND

  OE

GND


  SCL

A5


  SDA

A4


  VCC

5V


  +V

No conectado


 

VCC es la alimentación para la parte lógica del módulo y V+ es la alimentación para los servomotores, entonces adicionalmente se tienen que conectar una fuente externa a V+ y GND, fuente que debe ser  del voltaje correspondiente a los servos. No usar los 5V que entrega Arduino para alimentar a lo servos pues los 5V que entrega la placa Arduino es de poca corriente.

La mayoría de servos trabajan con voltajes de 4.5 y 6V nosotros usaremos una fuente de 5V / 5A.

La corriente mínima de la fuente externa depende del tipo de servomotores que se use y de la cantidad de servos que estarán conectados, Si bien la corriente no es un dato constante en el servomotor es mejor sobredimensionar la fuente para que trabaje correctamente, si la fuente no es muy estable o genera ruido, es necesario soldar un condensador en el espacio de la placa del Módulo con una valor de 1000uF o el equivalente a 100uF por cada servomotor.

Entonces, gráficamente las conexiones serian dela siguiente forma:

 Conexion arduino y PCA9685

 

Librería PCA9685 para Arduino

Usaremos la librería de Adafruit el cual lo pueden descargar aquí:
https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library

Después de descargar necesitan importar la librería al IDE Arduino

Expliquemos como usar la librería:

Como cualquier librería inicialmente se incluyen las librerías correspondientes y se declara la variable u objeto:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver servos = Adafruit_PWMServoDriver(dirección);

La dirección si no han modificado en su placa del módulo PCA9685 es 0x40, si desean modificar la dirección, necesitan soldar los puentes de la placa, y queda establecida por: Dirección=0|1|A5|A4|A3|A2|A1|A0, por ejemplo si no sueldan ningún puente seria 01000000=0x40, si sueldan el segundo puente seria: 01000100=0x44

El siguiente paso es inicializar el objeto creado anteriormente.

  servos.begin();  

Posteriormente configurar la frecuencia del PWM, que será la misma para los 16 canales PWM

  servos.setPWMFreq(60); 

La frecuencia que usamos es de 60Hz que equivale una señal PWM con periodo 16,6ms que se encuentra dentro del rango del ciclo de trabajo de la mayoría de los servos

Para establecer el ancho de pulso de una salida PWM usamos la siguiente función

  servos.setPWM(n_servo, up, down);  

En este caso n_servo es el número de servo o salida que van a configurar (valor entre 0 y 15), up es el valor de cuentas en el que se producirá el flanco de subida, y down el valor para el flanco de bajada, ambos valores deben estar entre el valor de 0 y 4096 (12bits). El ancho de pulso será la resta de down-up.

Explicado el uso de la librería vamos a ver unos ejemplos:

 

Realizando un Sweep, barrido de 16 servos:

Este ejemplo hace una barrido de 0 a 180° y después de 180° a 0°, el barrido se hace a todos los servos por igual.

Antes de empezar necesitamos saber el ancho de pulso (duty) para la posición 0° y el correspondiente para 180°

Trabajaremos con 172 (0.7ms) para la posición 0° y 565(2.3ms) para la posición 180°  

Para otros valores de los extremos del servo pueden calcularlo con la siguiente formula:

nCuentas=Pulso_ms*(frecuencia_Hz/1000)*4096

Generalmente se acostumbra aumentar o disminuyen los valores mínimo (0°) y máximo (180) hasta conseguir los valores para el rango correcto,

El sketch es el siguiente:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver servos = Adafruit_PWMServoDriver(0x40);

unsigned int pos0=172; // ancho de pulso en cuentas para pocicion 0°
unsigned int pos180=565; // ancho de pulso en cuentas para la pocicion 180°

void setup() {
  servos.begin();  
  servos.setPWMFreq(60); //Frecuecia PWM de 60Hz o T=16,66ms
}


void loop() {
  
  for (int duty = pos0; duty < pos180; duty=duty+10) {
    for(int n=0;n<16;n++)
    {
      servos.setPWM(n,0,duty);
    }   
  }
  delay(1000);
  for (int duty = pos180; duty > pos0; duty=duty-10) {
    for(int n=0;n<16;n++)
    {
      servos.setPWM(n,0,duty);
    }   
  }
  delay(1000);
}

Moviendo los servomotores en posiciones diferentes.

Para la mayoría de aplicaciones los servomotores van a estar en diferente posición, para este caso es mejor hacer una función que nos calcule y envié el valor en cuentas al servo y manipular el servo desde el void loop() con con valores de 0 y 180.

La función seria la siguiente:

void setServo(uint8_t n_servo, int angulo) {
  int duty;
  duty=map(angulo,0,180,pos0, pos180);
  servos.setPWM(n_servo, 0, duty);  
}

Con esta función podemos enviar a cualquier servomotor el valor del ángulo al que queremos que se ubique.

El sketch que se muestra a continuación mueve los servomotores cada segundo a posiciones establecidas:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver servos = Adafruit_PWMServoDriver(0x40);

unsigned int pos0=172; // ancho de pulso en cuentas para pocicion 0°
unsigned int pos180=565; // ancho de pulso en cuentas para la pocicion 180°

void setup() {
  servos.begin();  
  servos.setPWMFreq(60); //Frecuecia PWM de 60Hz o T=16,66ms
}

void setServo(uint8_t n_servo, int angulo) {
  int duty;
  duty=map(angulo,0,180,pos0, pos180);
  servos.setPWM(n_servo, 0, duty);  
}

void loop() {
  
    setServo(0,30);
    setServo(2,90);
    setServo(4,180);
    setServo(6,120);
    setServo(8,0);
    setServo(10,30);
    setServo(12,90);
    setServo(14,170);
    delay(1000);
    setServo(1,30);
    setServo(3,90);
    setServo(5,180);
    setServo(7,120);
    setServo(9,30);
    setServo(11,90);
    setServo(13,180);
    setServo(15,120);
    delay(1000);
    setServo(0,120);
    setServo(2,180);
    setServo(4,90);
    setServo(6,60);
    setServo(8,45);
    setServo(10,160);
    setServo(12,170);
    setServo(14,30);
    delay(1000);
    setServo(1,120);
    setServo(3,0);
    setServo(5,90);
    setServo(7,60);
    setServo(9,120);
    setServo(11,180);
    setServo(13,0);
    setServo(15,30);
    delay(1000);
    
}

Usando este ejemplo como base ya pueden realizar cualquier aplicación.

En el caso que usen diferentes tipos de servomotores con diferente rango del ancho de pulso; incluso siendo del mismo fabricante en sus modelos de servos los valores mínimo y máximo pueden variar, por ejemplo para algunos casos el ancho de pulso para la posición 0° puede ser 0.7ms, 1ms u otro valor, de igual forma para la posición 180°.

Para este caso se necesita tener en cuenta que si bien la señal PWM puede ser el mismo para todos los servos debemos de tener como referencia diferentes valores del rango del ancho de pulso. Esto lo hacemos haciendo las siguientes modificaciones en el código anterior:

Al declarar las posición 0 y 180, lo debemos hacer con valores independientes para los 16 servos:

unsigned int pos0[16]=  {172,172,172,246,246,172,246,200,200,150,160,172,172,172,200,246}; 
unsigned int pos180[16]={565,256,256,492,492,565,492,550,550,600,590,565,565,565,550,492}; 

Y en la función para mover el servo debemos de usar estos valores a la hora de convertir de ángulo a duty

void setServo(uint8_t n_servo, int angulo) {
  int duty;
  duty=map(angulo,0,180,pos0[n_servo], pos180[n_servo]);
  servos.setPWM(n_servo, 0, duty);  
}

También pueden modificar el valor 180 en caso quieran trabajar con valores de 0 a 255, valores con los que muchos traban puesto que ocupa un byte en la comunicación.

0 comments:

Post a Comment