Introduction: Simple Arduino XY Plotter

About: Músico, matemático, computación, ciencia... insolente y subversivo, pero siempre propositivo

En este instructable aprenderemos a construir un sencillo plotter XY, es decir, con dos servos controlaremos movimientos XY en un plano.

Para hacerlo, debemos entender un poco de la ley de cosenos, el manejo de entradas seriales al Arduino, y el manejo de servos.

El resultado es un plotter que funciona, pero que definitivamente tiene mucho espacio para mejorarlo, calibrarlo y hacerlo que funcione un poco mejor.

Step 1: Materiales

Ocupamos:

  1. Arduino UNO
  2. Breadboard
  3. 2 x servo motores
  4. cables
  5. 3 x paletas de helado
  6. Tiras de plástico

Step 2: Ensamblado

Vamos a utilizar las paletas de helado para poder armar los "brazos" del plotter. Como se muestra en la fotos simplemente se utilizan para pegar un servo al otro, amarrándolos con tiras de plástico. Luego se pueden acomodar los brazos para que ambos queden en posición 0 (o 180)

Step 3: Conexiones

Las conexiones son sencillas. Conectamos 5V y GND ald "+" y "-" del breadboard, para poder alimentar de poder los dos servos.

Los servos, se conectan al "+" y "-" del breadboard. En la foto se ven como cables rojos, cada motor necesita conectarse. Luego, el cable anaranjado, se conecta a los pines 7 y 8. El del pin 7 será nuestro servo1 que va en la base y el pin 8 será nuestro servo2.

Step 4: Ley De Cosenos

En trigonometría, la ley del coseno (fórmula o regla del coseno), establece una relación entre los lados de un triángulo, y uno de sus ángulos. Es una generalización del teorema de Pitágoras, ya que se aplica a cualquier triángulo. Cuando trabajamos con servos y cualquier tipo de brazo robótico, esta fórmula es extremadamente útil, ya que podemos calcular cualquier ángulo, conociendo simplemente los catetos, y es este precisamente el problema que enfrentamos.

La fórmula se muestra en la foto de forma gráfica. Adicionalmente, hay otra foto que lo compara con el brazo con dos servos que acabamos de armar. Queremos mover el brazo a una posición, simplemente al darle las coordenadas x,y. Es decir, dado un punto (x,y), queremos calcular cual será el ángulo que ambos motores deben tener.

En otras palabras. Si tenemos un triángulo con catetos a,b y c con sus ángulos opuestos A,B,C, Resolviendo para un ángulo A, cuyo cateto opuesto es a, tenemos:

cos A =( b^2 + c^2 - a^2 )/(2*b*c)

El símbolo "^" lo utilizo acá como "elevado a". Conocemos todos los catetos. En este caso, digamos que b y c son las paletas de helado, cuyo tamaño conocemos. El cateto a es el que que va desde el origen, hasta el punto al que queremos llegar. Muy fácil de calcular, pues si el origen es (0,0), y queremos medir la distancia a (x,y), entonces sabemos que a^2 = x^2 + y^2, por el teorema de Pitágoras.

Todas estas fórmulas se programan casi de forma directa en el código del Arduino. Pasemos ahora al código

Step 5: Código

El código acá es bastante sencillo. Lo primero es que cargamos la librería math.h. Esta incluye varias funciones trigonométricas, incluyendo acos y atan, que vamos a utilizar. Luego en el setup() simplemente asignamos el pin al servo (si quiere aprender más sobre el servo puedes seguir este instructable).

El ćodigo tiene dos elementos importantes:

  1. conexión serial
  2. funciones de movimiento y ley de cosenos

Lectura del puerto serial

En la líneas 29 a 30 del código:

if (Serial.available() > 0){
posX = Serial.parseInt();
posY = Serial.parseInt();
}

Por el puerto serial, vamos a enviar al Arduino las coordenadas como pares x,y separados por coma. La función parseInt(), permite leer del puerto serial cana elemento separado por coma. Al ejecutarlo por primera vez, lee el primero, hasta la coma, al ejecutarlo la segunda, lee inmediatamente después de la coma el siguiente y así. En este caso, leemos una primera vez y almacenamos en la variable global posX, y la segunda en posY, así entonces utilizamos luego en la línea 38, la función para calcular los ángulos y mover los servos.

Funciones

Creamos tres funciones importantes (acá hay un instructable sobre funciones). La primera que llamamos getAngle():

float getAngle(float a, float b, float c) {
return acos((square(b) + square(c) - square(a)) / (2 * b * c));
}

Que es simplemente la fórmula que explicamos en el paso anterior para calcular el ángulo usando la ley de cosenos.

La siguiente función es:

void armTo(float x, float y) {
float h = sqrt(square(x) + square(y));
//calculates angles based on desired point
float a1 = (getAngle(ARMLENGTH, ARMLENGTH, h) + atan2(y, x));
float a2 = (getAngle(h, ARMLENGTH, ARMLENGTH));
moveServo(a1, a2);
}

La cual es la que calcula, usando la ley de cosenos, los dos ángulos que ocupamos. Los ángulos los almacenamos en a1 y a2. Noten que a a1, le sumamos atan2(x,y), ese es el ángulo que hay desde la linea del horizonte hasta el punto, que hay que sumarle al ángulo del servo1.

La función moveServo, simplemente mueve los servo motores, convirtiendo los ángulos de radianes a grados que es lo que ocupa la función write() de los servos. esta función se puede mejorar muchísimo, para hacer mover los motores de apoco hacia el ángulo deseado... eso se los dejo de tarea.

Step 6: Funcionando Y Más

Listo. Abra el puerto serial, y desde la línea de comando puede enviar pares ordenados x,y para hacer mover el brazo a ese punto.

Bueno, el brazo no se mueve muy bien y hay bastante que se puede mejorar. Eso se los dejo a ustedes. Algunas cosas que se pueden mejorar:

  1. Imprimir en 3D los brazos (luego publico mi versión)
  2. Mejorar la función moveServo(), para que el movimiento de los servos sea suave
  3. Agregar aceleración y desaceleración a los servos.
  4. Incluir un algoritmo que dibuje algo bonito
  5. Conectar con processing para controlar el brazo desde allí (eso lo publico luego)

Step 7: Conectando Con Processing

Para extender el control del XY plotter, podemos conectarlo con Processing (descargar acá el programa). Adjunto está el código de processing y simplemente lo pueden conectar. Utilicen el código adjunto de Arduino que utiliza serialEvent(), para recibir la información por puerto serial de processing. Acá no explico detalles del código, luego hago un instructable con más detalles.