Vertical Plotter

1. Introducción

Objetivos

Después de realizar una exhaustiva búsqueda creativa en el blog de la asignatura y en internet en general, el equipo llegó a un consenso sobre el objetivo principal del proyecto: Concebir, construir y programar un plotter vertical eficiente y preciso, capaz de transformar instrucciones G-Code en trazos físicos sobre una superficie.

La motivación central de los estudiantes radicaba en obtener una experiencia integral en el diseño de sistemas empotrados, fusionando aspectos teóricos y prácticos de diversas disciplinas. Dado que el proyecto abordaba cuestiones matemáticas, físicas, electrónicas y de programación, se consideró la opción más adecuada para alcanzar este objetivo ambicioso.

Ideas y Consideraciones

El desarrollo del Plotter ha requerido una verdadera amalgama de conocimientos, provenientes de diferentes disciplinas.

En relación al ámbito físico-matemático, por ejemplo, se ha abordado la cinemática del sistema, comprendiendo las ecuaciones necesarias para la conversión de las coordenadas y la precisión de los movimientos, así como el funcionamiento de los motores.

Por otro lado, la comprensión profunda del formato G-Code ha sido esencial, ya que constituye el método de comunicación entre el plotter y el usuario. La interpretación correcta de las instrucciones ha sido clave para lograr que los trazos fueran todo lo fieles posible a la realidad.

Por esto, se consideró cuidadosamente el proceso de transformar diseños gráficos en instrucciones G-Code. La reflexión sobre cómo llevar dibujos a G-Code a través de archivos .svgs y el uso de software como Adobe Illustrator fue una parte integral del enfoque del proyecto. La utilización de .svgs permitió una transición fluida desde la creación de diseños gráficos hasta la generación de instrucciones G-Code, optimizando así el flujo de trabajo y facilitando la adaptación de una amplia variedad de diseños al sistema del plotter.

Diseños Iniciales

Para hablar de los diseños iniciales, es necesario dividir el proyecto en dos partes fundamentales: Cuerpo principal y góndola.

Cuerpo principal

Se trata de toda la estructura que sujeta el dispositivo. Para realizarla se han utilizado los siguientes materiales:

  • Dos piezas de madera para sujetar los motores Stepper, a las que se les incrusta un par de poleas GT2 de 5mm y 36 dientes. Están conectados a los motores mediante un tornillo prisionero que bloquea las poleas.
  • Cuatro tornillos, tuercas y arandelas, utilizadas para sujetar las piezas sobre cualquier superficie.
  • Correa GT2 que transmite el movimiento de los motores a la pieza central (góndola).
  • Dos pesas atadas a cada uno de los extremos de la correa.

Góndola

La góndola, denominada así por ser la parte del mecanismo que sujeta el bolígrafo o rotulador, fue diseñada tomando como inspiración las herramientas de dibujo, como los compases, que poseen una pieza externa que permite la adición de un lapicero a su estructura.

 Finalmente, se llegó a un diseño formado por:

  • Un cuadrado 10×10 cm de madera con un orificio de 25mm ligeramente desplazado del centro, que constituye la estructura base de la pieza.
  • Un tubo de pvc de 25mm de diámetro, situado sobre el orificio del componente anterior. Este tiene un tornillo en el lado más cercano al borde de la pieza de madera, que al enroscarlo, permite fijar el lapicero en el centro de la estructura.
  • Dos tornillos colocados en las dos esquinas superiores, que aseguran la correa conectada a ambos motores, proporcionando la fuerza necesaria para los movimientos.
  • Una pesa colocada en la parte más baja de la estructura para equilibrar la estructura y optimizar la precisión en el trazo.

Imágenes del Proceso de Diseño

Este diseño ha sido fruto de un proceso iterativo y colaborativo, donde cada ajuste se realizó con el objetivo de mejorar la eficiencia y la estabilidad del plotter. Como prueba de esto, a continuación se adjuntan imágenes de dicho proceso:

Cuerpo principal

Góndola

Materiales requeridos y precio total

Para llevar a cabo este proyecto, se han aprovechado varios componentes proporcionados en la caja Elegoo facilitada por la universidad:

  • Un motor Stepper.
  • Cableado.
  • Un joystick.
  • Placa y breadboard de Arduino.

Sin embargo, a pesar de contar con estos elementos, fue necesario realizar algunas adquisiciones de manera personal para garantizar el éxito del proyecto. Estos componentes adicionales, indispensables para continuar con el desarrollo, incluyeron:

  • Un motor Stepper adicional (1,50€)
  • Una correa GT2 (8m) (10,24€)
  • Dos poleas GT2 de 5mm y 36 dientes (3,70€)
  • Una tabla de contrachapado (4,50€)
  • Un tubo de PVC (1,00€)
  • Un bote de pegamento extra fuerte (6,55€)
  • Tornillos, tuercas, pizarra y pesas (Propiedad de los alumnos)

El costo total de estos materiales adicionales ascendió a 27,49€, aunque es importante señalar que al considerar los gastos de envío de algunos de estos elementos, el costo total del proyecto fue de 32,99€. Esta inversión resultó crucial para asegurar la disponibilidad de los recursos necesarios y mantener la viabilidad y calidad del proyecto en su conjunto.

2. Desarrollo del proyecto

Funcionamiento de los Steppers

En primer lugar, comenzamos el proyecto averiguando cómo funcionan los motores. Estos están conectados al driver ULN2003 que se conecta a 4 pines digitales en la placa de Arduino.

En el código, se asignan los pines a cada una de las entradas y la rotación se establece mediante la función step, que indica el número de pasos que tiene que dar el motor.

Fue necesario utilizar una librería en la que se implementara su funcionamiento, inicialmente empezamos a implementar unas funciones propias para el control de los motores (funciones step personalizadas, controlando la secuencia de la actuación de los polos del motor de forma directa), ya que con la librería que proporciona Arduino nos fue imposible hacer que rotasen simultáneamente debido al interbloqueo de su función step(). Finalmente, recurrimos a una librería llamada «CheapStepper», puesto que la encontramos mientras estábamos implementando nuestra propia librería y decidimos usarla para ahorrar tiempo (porque era un problema resuelto). Esta librería permitió resolver los problemas de sincronización de los motores[link] por medio de las funciones de movimientos no-bloqueantes (step() y run()). Sin embargo, a pesar de haber utilizado una librería externa, fue necesario modificarla para el proyecto.

Clases implementadas y modelo matemático

Para facilitar la representación de los datos y el modelo matemático del sistema hemos creado algunas clases y structs:

  • Una clase Vec2 para el facilitar el uso y las operaciones de vectores y coordenadas.
  • Un struct Belt que permite almacenar las longitudes de las correas que corresponde a cada motor. 

Estos datos se utilizan en una serie de funciones:

  • canvasCoordinatesToBeltLengths. Calcula la longitud que se corresponde a la posicion sobre el lienzo proporcionada. Hace esto calculando las distancias a los ejes de los motores desde el punto del lienzo (para poder hacer este cálculo correctamente primero traduce las coordenadas del lienzo a coordenadas de “mundo” que son el sistema de referencia de los motores).

  • beltLengthsToCanvasCoordinates.

  • worldToCanvasCoordinates. Convierte las coordenadas globales (el sistema de referencia de los motores), a coordenadas del lienzo. En el caso de las coordenadas globales, el punto (0,0) está situado en la esquina superior izquierda (sobre el motor 0) el eje coordenado x (horizontal) avanza hacia la derecha, mientras el eje y (vertical) crece hacia abajo en el caso de las coordenadas del lienzo, el punto (0,0) está colocado en el origen que se le ha indicado.

  • canvasToWorldCoordinates. Convierte las coordenadas del lienzo a coordenadas globales.

  • moveToPoint. Mueve la góndola a la coordenada indicada, traduciendo la longitud de las correas a número de pasos que mueve el motor.

  • moveBelts. Establece una longitud concreta de las correas.

Joystick y funciones para probar el funcionamiento

Para poder probar el funcionamiento de las clases implementadas, se utilizó un joystick que controla la dirección en la que se mueve la góndola. Este joystick va conectado a un pin digital para usar el clic del botón y a dos pines analógicos que reciben la entrada de los ejes en los que se mueve.

Se utiliza la siguiente función para procesar el joystick:

Además del joystick, antes de pasarle a Arduino código de G-Code, se probó también el funcionamiento del dispositivo mediante una función matemática que dibuja una circunferencia:

G-Code a Arduino

Antes de poder pasarle una imagen a Arduino, primero, hay que obtener un archivo .gcode del camino que se quiera recorrer, y por tanto dibujar. Para obtener este .gcode, hemos optado por generarlo a partir de archivos vectoriales .svg procesándolos con svg2gcode. Estos archivos vectoriales los hemos obtenido a partir de imágenes (.png o .jpeg) por medio de la herramienta de vectorización de Image Trace de Adobe Illustrator. Además para previsualizar el recorrido G-Code final hemos utilizado gcode-viewer.

Esta página convierte gráficos vectoriales a G-Code, creando un archivo con las coordenadas de cada uno de los puntos de las figuras de la imagen, incluyendo la interpolación (discretización) de los puntos de las curvas propias del formato vectorial, a una resolución configurable (mediante prueba y error concluimos que la resolución óptima era de 0,1mm).

Una vez creado el archivo G-Code, lo interpretamos y comunicamos al Arduino a través de un script de Python que hemos programado.

Las funciones del script son las siguientes:

  • parse_gcode. Primero extrae la información de las coordenadas contenidas en el archivo .gcode.

  • normalize_and_map. Después se traducen estas coordenadas al sistema de referencia del lienzo del plotter, que el arduino es capaz de interpretar correctamente.

  • send_to_arduino. Finalmente estas coordenadas se transmiten al Arduino de forma progresiva, según el protocolo de comunicación que hemos desarrollado. Vamos a concretar el funcionamiento de este protocolo y el proceso de interpretación de las coordenadas del Arduino: El plotter realiza movimientos exclusivamente en línea recta, entre cada coordenada que recibe a su variable ‘targetPosition’ (bien sea interpretada de gcode o introducido por el terminal a través del puerto serial, o por la manipulación del Joystick) y su posición actual ‘carriagePosition’.

  • main. En el main se busca el archivo .gcode, se ajusta el tamaño del lienzo y se establece el puerto serie.

Ejemplo de protocolo de comunicación con Arduino en ejecución. R(coordenadas) ← la salida Serial del Arduino que recibe el script. Indica las coordenadas actuales de la góndola del plotter. La R señaliza ‘Ready’ de la solicitud de coordenadas al script. Las coordenadas que se muestran bajo el mensaje del plotter es el mensaje que envía el script por medio de la interfaz Serial, que son las coordenadas en el formato que comprende el plotter. Debajo se imprime el estado de ejecución que refleja el porcentaje de compleción del camino G-Code, el tiempo transcurrido (en segundos) y una estimación calculada dinámicamente del tiempo de dibujado restante.

Problemas encontrados

Durante el desarrollo del proyecto, encontramos varios problemas que tuvimos que solucionar o solventar de ciertas maneras. A continuación, explicamos cuales fueron y cómo fueron solucionados.

  • Tensión de las correas. Hemos tenido varios problemas a nivel físico. Uno de los mayores limitantes del proyecto es el problema ocasionado por el tensionado de las correas a medida que la góndola se aleja del centro. Cuando esta sube a una determinada altura, hay demasiada tensión en una de las correas, por lo que los motores deben girar mucho para moverse un poco, mientras que, cuando se mueve a una de las esquinas inferiores, la tensión en una de las correas es muy poca por lo que, con que el motor gire un poco, la góndola va a moverse mucho. A continuación, mostramos una imagen explicativa de este fenómeno:

Al final, debido a la complejidad que esto supondría y al resto de limitaciones que acompañan el proyecto, se decidió que lo más conveniente era establecer un lienzo en el que pintar, aproximado a la zona verde indicada en la imagen anterior.

  • Sincronización de los motores. Como ya se ha mencionado con anterioridad, los Steppers y la librería proporcionada por Arduino, no solventan los problemas de sincronización proporcionados al utilizar dos motores. Es por eso que se movían haciendo, primero un movimiento uno de los motores, y una vez acabado, se hacía el otro movimiento. Es gracias a una librería que encontramos en internet que proporciona funciones de movimiento no-bloqueantes, que pudimos abarcar este problema. A continuación, dejamos el enlace al repositorio de GitHub de esta librería: Repositorio de Github: CheapStepper

  • Traducción de longitud a pasos del motor. Otro de los problemas encontrados fue el paso de las revoluciones del motor a la longitud que recorre la correa. La ecuación que permite conocer este dato es la de la longitud de una circunferencia: 2*π * r . Sin embargo, esto no fue todo, ya que fue necesario pasar la longitud que recorría la góndola a steps del motor, lo que no fue fácil ya que lo mínimo que permite recorrer un motor es ½ paso. Si el paso es menor que esto, lo aproxima a 0 y no permite moverse. La manera en la que esto fue resuelto fue almacenando la cantidad de longitud que tiene que moverse cada vez que da un paso, por lo que, si es menor a medio paso, la siguiente vez que compruebe cuánto tiene que moverse, se moverá la longitud acumulada. Esto hace que siempre quede un pequeño error en las longitudes, por lo que se almacena también este valor en una variable.
  • Debug con Serial. Otro de los problemas que tuvimos al principio fue que para comprobar muchos valores simultáneos, imprimimos en Serial bastantes valores, para conocer las longitudes de la correa, el error, los pasos que se movía el motor, etc. Es por culpa de lo ineficiente de esta función que se ralentizaba el dispositivo e iba tan lento que no parecía funcionar correctamente. Finalmente concluimos con que era mejor debuguear cuando fuese necesario, y solamente con lo que queríamos comprobar en ese momento.
  • Líneas rectas. Uno de los problemas que encontramos al enviar las coordenadas de un punto era que, cuando tenía que moverse en línea recta, la góndola se movía haciendo una especie de zigzag, primero moviéndose como una diagonal, y al final moviéndose a la coordenada indicada. Para solventar este problema, se recurrió a subdividir los trazos en función de una constante, para que corrigiese la dirección del movimiento a medida que se fuese moviendo en la recta.

Solución:Para solventar esto se implementaron dos funciones, una ‘created Waypoints’ que establece las variables que se utilizan para la interpolación del recorrido (siempre que la longitud de este supere la resolución de subdivisión establecida en mm), y otra función ‘moveTo Waypoints’ que va moviendo la variable ‘targetPosition’incrementalmente según un vector en la dirección del trazo, con una magnitud dada por la resolución de subdivisión.

  • Verticales. Debido a un problema en una de las funciones programadas, cuando la góndola se movía en direcciones verticales, funcionaba incorrectamente. Esto se solucionó ya que nos dimos cuenta de que la función que permitía controlar el flujo del programa, runStepper (controla el no mandar un movimiento nuevo antes de acabar el anterior), que va sumando el número de pasos que tiene que hacer, sumaba incorrectamente, ya que no hacía el valor absoluto. Al moverse la góndola en vertical, los motores se movían en direcciones contrarias, y el valor que almacena los pasos que tiene que dar el motor valía 0 antes de tiempo, por lo que asumía una posición incorrecta.

Esta es la función en la que ocurría el error.

  • Orden de recorrido. Al procesar una imagen en Illustrator para obtener el archivo .svg y así convertirlo a G-Code y enviárselo a Arduino, el recorrido de las coordenadas que se realizaba no era el más óptimo, por lo que, al no haber implementado funcionalidad que permitiese levantar el bolígrafo de la góndola, el dibujo quedaba cubierto por un montón de líneas de tránsito. Es por ello que se programó un código que ordenaba en Illustrator los puntos en función al camino más corto, haciendo que el resultado final fuese mucho más legible.

Una vez solucionado el problema, el resultado es el siguiente:

Vídeo demostrativo

Apéndice

Código de Arduino

Código de Python:

TSP Sort para Illustrator:

También te podría gustar...

Deja una respuesta

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