Introduction: Simple Arduino XY Plotter

Picture of Simple Arduino XY Plotter

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

Picture of 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

Picture of 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

Picture of 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

Picture of 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

Picture of 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

Picture of 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

Picture of 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.

Comments

Max1235 (author)2017-02-17

Thank Tomas! If someday in future you finished it, please let me know. Best Regards!

Max1235 (author)2017-02-16

Thank Tomas! Install Processing and load your code and it works. Thank you very much! Do you know how to use this device to print the drawing which made by other software such as CAD DXF format ?

tomasdecamino (author)Max12352017-02-17

It could be done with Processing. Haven't had the time to do it!

Max1235 (author)2017-02-15

Hi Tomas, It's a great project! I have built one and tested two servos that both are ok.What is the software that you used to make the drawing? It's very appreciated to received your reply! many thanks!

tomasdecamino (author)Max12352017-02-16

You can also try out this related project https://www.instructables.com/id/Cinem%C3%A1tica-Directa-Con-Arduino/

tomasdecamino (author)Max12352017-02-16

I'm using processing, you can donwload this sftware for free here https://processing.org/. When you have everything installed, load this code https://github.com/tomasdecamino/ProcessingStuff/blob/master/XY_Plotter/XY_Plotter.pde

FelipeA95 (author)2016-11-24

Buenas, no tengo idea de Arduino, pero quiero adentrarme haciendo por ejemplo un Plotter, este me pareció bastante simple, pero no entendí como se le pasan los diseños. Supongo que será con algoritmos de Arduino, pero me pregunto si se podrá enviar diseños vectoriales como con los plotters más avanzados (obviamente el resultado no será el mismo, pero por ejemplo, hacer una letra). Saludos y muchas gracias.

MrProzaki. (author)2016-05-20

Hello again ... got back after some learning , but i still cant get it to work , am having problems with aligning the arms of the servo . I tried working with proccessing in order to help me but am not making anything to work , ok so ill provide a picture and where i align with proccessing : the first image shows the paper in which am tryn to draw . What should i change in the code ? Or if its not the code i should change then what should i change ? am so confused ... and when i thought i was done ... thank you for your time .

MeriphiliaC (author)2016-05-13

Para el movimiento suave de los servos, recomiendo una librería muy buena llamada : varspeedservo :)

ofrece funciones extra para la velocidad

Gracias!

Devesh Kannappan (author)2016-05-02

i has science exhibition tommorow

Devesh Kannappan (author)2016-05-02

you know devesh kannappan and arjun devesh are same me k.devesh and arjun.t

Devesh Kannappan (author)2016-05-02

no, i got it you forgot #include <servo.h>

Devesh Kannappan (author)2016-05-02

it says that'servo does not name a type

Devesh Kannappan (author)2016-05-02

i am not having pro account

ArjunDevesh (author)2016-05-02

actually sir we don`t know how to allign the gears of the servo

Do something like this in your arduino,

Servo myservo1, myservo2;

void setup() {

myservo1.attach(6);

myservo2.attach(9);

}

void loop() {

myservo1.write(90);

myservo2.write(0);

}

Then fix the arms, and then load the other code

For that just move servos to 90 and 0 in the setup() code and the put the arms

The base servo, has to be in position 90, the second servo in position 0

Devesh Kannappan (author)2016-05-02

can you give me your gmail id

You can use private messages on this platform...

ArjunDevesh (author)2016-05-02

Which country you are from? We are from india

Costa Rica

ArjunDevesh (author)2016-05-02

Which country you are from? We are from india

ArjunDevesh (author)2016-05-02

Thank you sir for helping me in science project

ArjunDevesh (author)2016-05-02

could you plz give on or before 8 pm today

ArjunDevesh (author)2016-05-01

plz plz tell me how to fix the servo motor send to me with video

Not sure what you want... could you please explain a little?

ArjunDevesh (author)2016-05-01

plz give me before 2nd may 2016 i have science exbition

MrProzaki. (author)2016-04-22

I hope you are still watching this post :). Ok first of all , great project awsome work . Ive been looking for something like this and finaly i found it so thanks .
My question now : I see you code but i cant understand how you get to use angle from first servo and the angle of second servo and by that you calculate (x,y).

Can you please show me how you did it based on your code ?
Green angle is servo 1 angle , while red is servo 2 angle . so we need based on those 2 angles to calculate brown angle as showed in your picture.
My trigonometry is bad , so please when you have time answer my questions . Thanks in advance .

tomasdecamino (author)MrProzaki.2016-04-22

Hi, glad it is useful. It is actually very simple, it is based on the law of cosines. You have the length of the arms and with the desired position x,y, you have the length of what would be the third side. Which is:

float h = sqrt(square(x) + square(y));

Now you can calculate first the angle of the first servo,

float a1 = (getAngle(ARMLENGTH, ARMLENGTH, h) + atan2(y, x));

Where getAngle is just the law of cosines given three known sides. Next with the same fomula (noting that the oposite and adjacent sides are different) you calculate the angle of the second servo

MrProzaki. (author)tomasdecamino2016-04-22

Thanks a lot for your fast reply i still fail to get it xD . Am a student atm at greece Automation Engineer and i still am dumb enough to understand trigonometry . So lets go one more time please :
L1 is the armlength of the base servo as you can see in the picture ,
L2 is the second servo armlength , so they are kinda different .
While φ1 is the angle of the base servo , and φ2 is the angle of the second servo.
Is this equation right ?

x= L1*cosφ1 + L2*cosφ2 .
y=
L1*sinφ1 + L2*sinφ2 .

if that equation is right am gona need some help to translate it into code , am sorry to put you through this .
Although your code seems advanced for my eyes it seems more awsome .. lets give it another try .

first you define this
int posX = 90, posY = 90;
then you say
armTo(posX, posY);

So the angle of the first and second servo is 90 .
And then you calculate this :
float h = sqrt(square(x) + square(y));

which seems to be the L3 = Length of the base of the triangle am i right ?

Next step you say this :
float a1 = (getAngle(ARMLENGTH, ARMLENGTH, h) + atan2(y, x));

So you have a function that takes the armlength of the base servo which in your case is 100 and second also 100 , and the length of that base of triangle which you calculated before the float h , but what is that atan2(y, x) and why you add it to your a1 ? a1 == x ? or y ?
I dont see it in your next line : where you calculate a2

float a2 = (getAngle(h, ARMLENGTH, ARMLENGTH));

Also at the getAngle function what is the use of this equation what is it called so i can look it up or something ?
return acos((square(b) + square(c) - square(a)) / (2 * b * c));

And finaly the moveServo is a function that you go from the radians to degree because the values you found from before
"a2 = (getAngle(h, ARMLENGTH, ARMLENGTH));" is radian , am i right ?

I analyzed your code better this time and i hope that i understood it better , i hope ...
Please take your time to explain me and thank you so much for your time i really appreciate it .

tomasdecamino made it! (author)MrProzaki.2016-04-22

Had a quick look and I think you are on the right track. atan2(x,y) is the angle from the base, to servo1 arm, that needs to be added. It is alfa in this image...

Unsafe At Any Speed (author)2016-01-20

Thomas,

I could not get it to work .

The X, Y coordinates fail to come out right.

I tried 0,0 - 0,50 50,0 - 50, 50 to make a square but it comes out more as a big triangle with 0,0 and 50,50 going to the same point.

Also, I notice the servo motors are mounted with one upside down in some pics and the same in other pics.

-Thanks

HI, dependint on the postion of servos (upside down or not), you have to change ths part of the code

float a1 = (getAngle(ARMLENGTH, ARMLENGTH, h) + atan2(y, x));

float a2 = (getAngle(h, ARMLENGTH, ARMLENGTH)); moveServo(a1, a2);

doing 180-1 to make movements right. Algo make sure you set the arms in the cero position. Let me know if this solves the problem

I tried a few things, adding the 180 in the
program, reversing the motors positions, reversing the motor plugs,
using different values for ARMLENGTH. It still does not work.

One thing I did not understand, how did you align the motors with the arms?

I just made the motors position at 90° and lined the arms up in the middle.

As you can see in the picture, the arms are longer than the Popsicle sticks in your example, it is 125mm from motor to motor.

You have to align the servo position and the arm to 0 or 180 (depending on the servo), not at 90. I think that might be the problem

Unsafe At Any Speed (author)2016-01-27

When I try to make a square as shown in you example; 0,0-50-0,0-50-50,50, it looks like the picture.

Unsafe At Any Speed (author)2016-01-27

Typo.........Position

Unsafe At Any Speed (author)2016-01-07

A very good and useful project!

I will have to make one.

Thanks for posting this.

Lorenzo Daidone (author)2016-01-04

Very nice!

anooooos (author)2016-01-04

I want to learn ARDUINO

anooooos (author)2016-01-04

I want to learn ARDUINO

anooooos (author)2016-01-04

هاي

About This Instructable

10,982views

57favorites

License:

Bio: Músico, matemático, computación, ciencia... insolente y subversivo, pero siempre propositivo
More by tomasdecamino:Cómo Crear Un InstructableKit Ciencia Y Arte: Máquinas Que Aprenden SonidoLámpara De Inventor
Add instructable to: