Construimos el «ojoloco» de Alastor Moody de la película Harry Potter con arduino y un servomotor.

Producto final

Material necesario

  • 1 Servo motor Mitoot-microservo SG90.
  • 1 arduino nano.
  • 1 condensador 100mf (opcional).
  • Correa de cuero.
  • 6 Tornillos de madera 2.5x10mm (o pegamento fuerte).

En este episodio solo trataremos el artilugio que compone el ojo. Es decir, la ubicación del arduino y las pilas corre de tu cuenta. Propongo disimularlos en alguna parte del cuello de la chaqueta o entre alguna peluca.

Del «ojo» saldrá el cable del servomotor que consta de 3 terminales. Tierra, alimentación (+5V) y señal (D9).

Te corresponde a ti hacerlos llegar a la placa de control.

Servo motor SG90 9g

Un servomotor o comúnmente llamado servo, es un motor DC con la capacidad de ubicar su eje en una posición o ángulo determinado, internamente tiene una caja reductora la cual le aumenta el torque y reduce la velocidad, un potenciómetro encargado de sensar la posición del eje y una pequeña tarjeta electrónica que junto al potenciómetro forman un control de lazo cerrado.

Hemos de tener en cuenta que hay distintos fabricantes y versiones de este modelo que pueden variar en algunos milímetro en sus dimensiones. Esto me ha ocasionado ciertos problemas pues disponía de varios modelos. Así que estate atento a las dimensiones pues puede darse el caso que tu servo sea ligeramente distinto e impedir un encaje adecuado.

Diferencias de tamaño entre servo MiToot a la izquierda y el servo Tower pro a la derecha

En mi caso usaré servos de la marca china MiToot por su bajo coste en Aliexpress que son ligeramente más grandes.

El servo SG90 tiene un conector universal tipo “S”.Los cables en el conector están distribuidos de la siguiente forma: Rojo = Alimentación (+), marrón= Alimentación (-) o tierra, Naranjo = Señal PWM.

Las características del motor son las siguientes:

  • Dimensiones (L x W xH) = 22.0 x 11.5 x 28 mm
  • Peso: 9 gramos
  • Peso con cable y conector: 10.6 gramos
  • Par a 4.8 volts: 16.7 oz/in o 1.2 kg/cm
  • Voltaje de operación: 4.0 a 7.2 volts
  • Velocidad de giro a 4.8 volts: 0.12 seg / 60 º

Mi experiencia personal aconseja el uso de un condensador opcional de 100uF en la alimentación del motor, lo que entregará una alimentación más limpia evitando errores en su actuación.

Piezas

En el archivo que podrás descargar a continuación se encuentran 4 piezas imprimibles.

Algunas vistas del proyecto

Montaje

Para este proceso manipularemos las piezas y el motor a la par que manipulamos el software.

Es decir, usaremos

  • Un programa para encontrar el punto medio del servo y anclar su eje.
  • Otro de configuración para calcular los límites y el punto central del ojo.
  • El definitivo para realizar la función por la que se crea.

Programa inicial

Buscaremos el punto medio del servo, es decir, lo colocaremos en la posición 90º mediante al software para colocar la pieza en el eje.

Para ello usaremos el programa de inserción del servo que puedes ver bajo estas líneas. Este simple código, posicionará el servo en su posición mínima (0º), central (90º) y máxima (180º).

#include <Servo.h>
Servo myservo;

void setup() {
  Serial.begin(9600);
  Serial.println("Saludos");
  myservo.attach(9);
  myservo.write(0);
  Serial.println("Posición=0");
  delay(3000);
  myservo.write(90);
  Serial.println("Posición=90");
  delay(3000);
   myservo.write(180);
  Serial.println("Posición=180");
  delay(3000);
   myservo.write(90);
  Serial.println("Posición=90");
   Serial.println("Posición definitiva.");
   Serial.println("Programa terminado. Atornille el servo en esta posición.");
}

void loop() {
 }

En el monitor Serial se mostrarán los ángulos que variarán cada 3 segundos para que tengamos la referencia del centro de giro.

Por último adoptará la posición central para que podamos colocar la pieza en el eje de la manera adecuada, aproximadamente como se muestra en la figura.

La pieza blanca que usaremos de eje y los tres tornillos de sujeción vienen incluidos en el mismo kit del servomotor.

Atornillaremos al cilindro central el eje del servomotor con dos tornillos. Se puede realizar desde la parte superior, pues existen 2 orificios para tal fin, pero aconsejo que se introduzcan desde el interior del cilindro hacia el exterior.

Es el momento de fijar el servomotor. Recordaremos la posición aproximada del eje que vimos en el paso anterior y trataremos de asegurarlo de la misma manera.

En este caso debemos pasar un tornillo (también suministrado por el fabricante del servomotor) por uno de los orificios de la parte superior del cilindro central.

Ahora toca colocar el globo ocular en su lugar. Presionaremos el servo para que encaje en el lugar destinado haciendo cierta presión para conseguir un ajuste adecuado. 

Para asegurar el sistema y evitar que se salga con el movimiento, atornillaremos la plaquita que hace de tope.

Es momento de fijarnos en las asas que servirán para colocar del cuero que sujetará el artefacto a la cabeza.

Por último solo queda cerrar el sistema añadiendo la tapa que protegerá el ojo de cualquier movimiento. Irá sujeto con 4 tornillos.

Es el momento de cuantificar y asignar límites de movimiento al sistema. El objetivo de este programa es encontrar los máximos en cuanto a desplazamiento. Para ello cargaremos este código de calibración en el microcontrolador.

Aunque sabemos que el diseño permite un máximo de 82 grados, esto puede no ser cierto en la vida real, dependiendo de los materiales de fabricación, anatomía del servo y muchos otros factores.

El diseño permite un giro de 41 grados hacia cada lado.

El siguiente código tiene como misión solventar estas vicisitudes de la vida real.

Programa de configuración

El primer paso es colocar el servomotor en la posición que originalmente consideremos el centro (90º).

Usaremos un método de interacción en la que participaremos visualmente para marcar estos límites. Debemos abrir el monitor Serial para introducir letras como nos indica el propio programa.

Primero buscaremos el límite por la izquierda. En el Serial monitor introduciremos una «z» o una «x» para desplazar el globo ocular en un sentido o en otro.

Incrementaremos el giro hasta alcanzar lo que consideremos como límite (cuando no se consiga movimiento). En ese momento presionaremos «g» para guardar este valor en la eeprom.

El motor volverá al valor 90º para en este casa pedirnos lo mismo pero para delimitar el máximo por la derecha.

Igualmente se guardará esta posición en la eeprom después de pulsar «g«.

Cuando tenga los dos límites calculará el punto medio real, y colocará el globo ocular en esa posición.

#include <Servo.h>
#include <EEPROM.h>
Servo myservo;
int topeizquierda, topederecha;
int posicion = 90;
void setup() {
  Serial.begin(9600);
  Serial.println("Saludos");
  Serial.println();
  Serial.println("INICIANDO CALIBRACION");
  Serial.println();
  Serial.println("Posición central sin calibrar (90)");
  myservo.attach(9);
  myservo.write(posicion);
  delay(100);
  Serial.println();
  Serial.println("Buscamos la posición máxima hacia la izquierda");
  Serial.println("Escribe Z o X para mover");
  Serial.println("Una vez encontrado el límite, pulsa G para guardarlo");
  while (topeizquierda == 0)
    if (Serial.available()) {
      char data = Serial.read();
      if (data == 'x') {
        posicion++;
        myservo.write(posicion);
        Serial.println(posicion);
        delay(25);
      }
      if (data == 'z') {
        posicion--;
        myservo.write(posicion);
        Serial.println(posicion);
        delay(25);
      }
      if (data == 'g') {
        EEPROM.write(1, posicion);
        topeizquierda = posicion;
        Serial.println("Guardo posición izquierda");
        Serial.println(posicion);
        posicion = 90;
        myservo.write(posicion);
        delay(150);
      }
    }
  Serial.println("Posición central (90)");
  Serial.println();
  Serial.println("Buscamos la posición máxima hacia la derecha");
  Serial.println("Escribe Z o X para mover");
  Serial.println("Una vez encontrado el límite, pulsa G para guardarlo");
  while (topederecha == 0)
    if (Serial.available()) {
      char data = Serial.read();
      if (data == 'x') {
        posicion++;
        myservo.write(posicion);
        Serial.println(posicion);
        delay(25);
      }
      if (data == 'z') {
        posicion--;
        myservo.write(posicion);
        Serial.println(posicion);
        delay(25);
      }
      if (data == 'g') {
        EEPROM.write(2, posicion);
        topederecha = posicion;
        Serial.println("Guardo posición derecha");
        Serial.println(posicion);
        posicion = topederecha - ((topederecha - topeizquierda) / 2);
        myservo.write(posicion);
        delay(150);
        Serial.println("Centrando a:");
        Serial.println(posicion);
      }
    }
}

void loop() {
}

A modo de orientación, unos valores adecuados deben estar sobre los 40 – 46 grados para el lado izquierdo y sobre 117 – 129 grados para el lado derecho. Lo que nos permite una cobertura de unos 70 grados totales de libertad para mover el ojo a un lado u otro.

Los valores conseguidos, al estar almacenados en la eeprom, serán leídos en el siguiente programa que será el que dará «vida» a nuestro ojo.

Programa definitivo

Con los datos obtenidos con los programas anteriores realizaremos unos movimientos aleatorios y espasmódicos a lo largo del rango de acción del ojo.

Las variables para ello son la velocidad de movimiento, la posición en grados y el tiempo entre un movimiento y otro.

#include <Servo.h>
#include <EEPROM.h>
Servo myservo;
int topeizquierda, topederecha;
int posicion, posicionnueva;
int rango;
int pausa;
int velocidad;
void setup() {
  Serial.begin(9600);
  Serial.println("Saludos");
  Serial.println();
  topeizquierda = EEPROM.read(1);
  topederecha = EEPROM.read(2);
  posicion = topederecha - ((topederecha - topeizquierda) / 2);
  Serial.println("Leyendo datos de la calibración previa");
  Serial.println("Se detectan los siguientes valores ");
  Serial.print("Max Izq: ");
  Serial.print(topeizquierda);
  Serial.print(", Max dch: ");
  Serial.print(topederecha);
  Serial.print(". Calculo el punto central en: ");
  Serial.println(posicion);
  Serial.println("Colocando servo en posición central calculada");
  delay(1000);
  myservo.attach(9);
  myservo.write(posicion);
  delay(500);
}
void loop() {
  pausa = random(50, 2000);
  delay(pausa);
  posicionnueva = random(topeizquierda, topederecha);
  velocidad = random(1, 25);
   if (posicionnueva >= posicion) {
    for (int i = posicion; i <= posicionnueva; i += 1) {
      myservo.write(i);
      delay(velocidad);
      posicion = posicionnueva;
    }
  }
   if (posicionnueva < posicion) {
  for (int i = posicion; i >= posicionnueva; i -= 1) {
      myservo.write(i);
      delay(velocidad);
      posicion = posicionnueva;
    }
   }
 }

Esquema eléctrico

Alimentaríamos el sistema con 4 pilas AA que darían un total de 6V, suficientes para el servo y asumibles para el arduino.

Vistas del objeto.