Curso Arduino y robótica: Servomotores – Control en bucle

Si queremos hacer que las cosas se muevan necesitamos motores. Durante este tutorial no solo vamos a aprender a mover nuestros servomotores, sino que además desarrollaremos un modo de control que nos permitirá mejorar nuestros programas aplicados a el movimiento de robots.

Servomotores

Un servomotor es un dispositivo similar a un motor de corriente continua que tiene la capacidad de ubicarse en cualquier posición dentro de su rango de operación, y mantenerse estable en dicha posición.

El servomotor se compone de un motor de corriente continua, una caja reductora, y un sistema de posicionamiento, generalmente un potenciómetro. En el siguiente video se muestra como es un servomotor por dentro.

Los servomotores pueden ser de giro continuo, en los que se puede controlar la velocidad de giro, o de giro fijo que son los que giran dentro de un rango limitado para control de posición.

Es importante saber definir cuál vamos a utilizar nosotros ya que son muy parecidos, así que a la hora de comprar tendremos que fijarnos muy bien en ese detalle.

Por ejemplo, un servomotor de rotación continua, nos vendrá bien para crear un coche siguelineas, mientras que un servomotor de rango puede ser útil para proyectos como un robot bípedo.

Cables y conexión de un servomotor

Es bastante posible que los cables de nuestros servomotores sean diferentes dependiendo del modelo. En resumen necesitaremos 3 cables para conectar un servomotor. Vcc ( + ), GND ( – ) y el pin de señal.

En la siguiente imagen podremos ver rapidamente que cables son los más usuales en función del fabricante.

Entonces solamente necesitaremos conectar nuestra placa Arduino al correspondiente pin de voltaje, tierra y a un pin de señal.

IMPORTANTE: Solamente podemos conectar nuestros servomotores a los pines que tienen salida PWM. Para identificar este tipo especial de pines de salida, tenemos un símbolo para reconocerlos.

 

PWM – Pulse Width Modulation

En un tutorial anterior sobre entradas y salidas digitales y analógicas identificábamos las señales con capacidad para obtener un estado digital 1 ( Activo ON ) ó 0 (Inactivo OFF ) y las analógicas a las que se le corresponde un conjunto de valores entre 0 y 1023.

En el caso de un motor, se requiere más control que el que nos ofrece una salida digital que solamente nos encendería o apagaría el motor. Por ello, existe un modelo de señal digital que nos permite controlar la potencia y definir estados intermedios para definir la posición o la velocidad.

Una señal PWM ( Pulse Width Modulation ) – Modulación por ancho de pulsos es una señal periódica digital que establece un estado activo en porcentaje proporcional a la potencia suminstrada que controla la velocidad o la posición de nuestro servomotor.

A este porcentaje entre el tiempo de la señal digital activa y el tiempo total del ancho de pulso se le define como ciclo de trabajo ( Duty Cycle ) que es el parámetro de entrada que tendremos que definir en nuestro programa.

 

 

Los servomotores que vamos a usar tienen unos requisitos muy bajos de potencia, y pueden ser utilizados directamente con el Arduino, pero hemos de tener cuidado a la hora de conectar demasiados ya que su consumo puede superar la potencia que puede suministrar una placa Arduino y para ello requeriríamos de una fuente externa.

Programando nuestros servomotores de rango fijo

Para programar un servomotor necesitaremos cargar una librería denominada Servo.h que ya tendremos preinstalada en nuestro IDE de Arduino.

Un aspecto muy importante a tener en cuenta es que la salida definida para el ciclo de trabajo de un servomotor es un número de 0 a 180. 0 determina potencia nula, mientras que 180 definirá la máxima potencia.

En el caso de un servomotor de giro 180 grados, el mismo valor de señal identificará el ángulo al que se tendrá que mover.

Para usar la librería, debemos usar un modelo de programación orientado a objetos en el que instanciaremos un objeto de la clase Servo como si de una variable se tratara.

Las funciones que debemos de usar a la hora de instanciar un motor son las siguientes.

  • attach() -> define el pin al que conectaremos nuestro servomotor.
  • write() -> Mueve el servomotor especificando su valor de giro.
  • detach() -> Desconecta el servomotor del pin.
  • read()-> Lectura de la posición actual del servomotor.

Empezaremos por realizar estos dos programas básicos. ¿Antes de probarlo podríamos saber cuál delos dos funcionará?

#include <Servo.h>

int motorPin;
int i;

Servo motor;

void setup() {

  motorPin = (int)(10);
  motor.attach(motorPin);

}

void loop() {
  for (i = 0; i <= 180; i++) { 
    motor.write(i); 
  } 
  for (i = 180; i >= 0; i--) {
    motor.write(i);
  }

}
#include <Servo.h>

int motorPin;
int i;

Servo motor;

void setup() {

  motorPin = (int)(10);
  motor.attach(motorPin);

}

void loop() {
  for (i = 0; i <= 180; i++) { 
    motor.write(i); 
    delay(10); 
  } 
  for (i = 180; i >= 0; i--) {
    motor.write(i);
    delay(10);
  }

}

 

Si ya lo hemos probado, curiosamente nos daremos cuenta que el segundo programa con retraso en el bucle es el que funciona correctamente.

Esto se debe a que las órdenes del bucle son más rápidas que lo que le cuesta al motor llegar a su posición mecánica. Es decir el programa ejecuta la siguiente posición antes de que le haya dado tiempo a llegar a ella. Por este motivo nuestro motor solo funciona al añadir un delay de 10 ms, que aunque es un valor pequeño, le permite llegar a su posición antes de ejecutar la siguiente instrucción.

Control de servomotores en bucle

En tutoriales anteriores, establecimos una norma muy importante a aplicar en robótica.

NO USAR DELAYS NUNCA

Si usáramos el mismo modelo de usar bucles dentro del bucle principal y sumáramos los retrasos del programa anterior multiplicados por el número de motores, obtendríamos  un tiempo de retraso de

180*2*10 = 3600 ms = 3.6 s

Si realizamos el siguiente ejercicio para leer la cuenta comprobaremos esta acumulación de tiempos y que nos añadiría un retraso de 3,6 segundos para leer alguno de nuestros sensores.

SOLUCIÓN

La solución reside en no usar bucles internos para ir de un ángulo a otro del motor. Solamente es necesario definir una vez la posición y el motor llegará sin ningún tipo de retraso sobre el programa. En caso de corregir la posición del motor a medio camino de su llegada hasta otro punto el motor se interrumpirá a medio camino, pero siempre manteniendo el bucle principal como solución de control.

Ejercicio del ultrasonido.

Un buen ejercicio a considerar es el uso de un radar, en el que podemos instalar un sensor ultrasonido montado sobre un motor de giro de 180 grados.

Este sensor requiere de hacer un barrido en todos los ángulos y obtener un mapa de distancias para conocer en qué zonas se encuentran los obstáculos y una vez haya hecho el barrido decidir que dirección tomar.


#include <Servo.h>

int motorPin;
long time;
int motor_pos;
int motor_step;
int direction;

Servo motor;

void setup() {
  Serial.begin(9600);

  motorPin = (int)(10);
  motor.attach(motorPin);
  time = (long)(0);
  
  motor_pos = (int)(motor.read());
  motor_step = (int)(1);
  direction = (int)(1);
}

void loop() {
  time = millis();
  
  motor_pos = motor_pos + direction * motor_step;
  motor.write(motor_pos);

  if (motor.read() >= 180) {
    direction = -1;
  }
  if (motor.read() <= 0) {
    direction = 1;
  }
  Serial.print("Time: ");
  Serial.println((millis() - time));

}

Aunque pueda ser una solución, este programa no es perfecto, ya que tendremos la misma saturación si hacemos que el motor se mueva a una posición sin dejarle tiempo a llegar al final y definir una nueva posición.

Para solucionar este modelo, requeriríamos de un sensor externo que nos comunicará en qué posición actual se encuentra el motor con respecto a la que le hemos mandado. Pero estos motores no nos permiten llevar a cabo este control.

De todas formas, este modelo es suficiente para ordenar a realizar un barrido ya que dentro de nuestro programa aún no hemos incluido más elementos, como motores y sensores.

Una información útil de cada motor es la velocidad angular con la que son capaces de moverse y que podemos informarnos desde su datasheet. La velocidad angular más común es 230 grados por segundo alimentado a 4.8V, o 190 grados por segundo alimentado a 3,3V.

 


Una vez completado este tutorial, puedes acceder al siguiente nivel.

 

Los ejercicios de código, proyectos y recursos que desarrollaremos durante el curso se pueden consultar a través de nuestro Github.

Documentacion ZaragozaMakerSpace Github

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

7 + 13 =

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.