Comunicación serie de bajo nivel.
Nuestro compañero Íñigo nos obsequia con un gran artículo. Tuvo además la gentileza de ofrecernos todo este conocimiento en modo presencial a través de un taller que realizó hace poco más de un mes en la sede de Bilbaomakers. El cometido de este que escribe el primer párrafo no es otro que presentarlo (él no es aún editor en el blog) y aportar la foto que va a continuación a modo de introducción. Me gustó tanto el título con el que presentó el taller (Susurrando a las máquinas) que visualicé la imagen casi de inmediato.
Os dejo con él.
1.- Contexto:
Con la aparición de impresoras 3d de bajo coste en el mercado, cada vez más personas nos lanzamos a este mundillo consistente en montar, ajustar y solucionar fallos de nuestras máquinas. De vez en cuando también conseguimos hasta imprimir algo 🙂
Para imprimir utilizamos normalmente tarjetas SD con el archivo de la pieza en cuestión. Pero también hay programas que, instalados en el ordenador, nos dan el control de la impresora vía USB (para qué creíais que vuestra impresora tenía ese puerto?). Estos programas permiten además el movimiento manual del cabezal, el ajuste de temperaturas, etc.
(Ejemplos:)
Octoprint
Fotografía tomada de: https://www.flickr.com/photos/creative_tools/
Pronterface
La realidad es que, aunque estos programas están muy bien (y merece la pena usarlos), lo único que hacen es pasar comandos a la impresora y escuchar su respuesta a través de… Sí, un puerto serie!!!
2.- Qué es eso del puerto serie?
Empecemos por la terminología: Un puerto es, en informática, un canal a través del cual entra y/o sale información. Este puede ser físico (como los USB, HDMI etc.) o lógico (por software: TCP/IP por ejemplo tiene muchos puertos: el 80 para una web, el 22 para SSH, el 110 para recibir emails vía POP…). Es un poco lío pero resumiendo podemos asociar la palabra «puerto» a «sitio por el que entran y salen datos».
Lo de «serie» es más sencillito: Viene a decir que los bits (los unos y ceros con los que nos comunicamos con nuestras queridas máquinas) salen «en fila india», es decir, primero uno y después el siguiente, etc. En una conexión paralela (que es el otro tipo) salen 8 bits -un byte- cada vez, cada uno de ellos por un canal diferente. Esto, en una conexión software no es -muy- importante, pero en una conexión física (con cables, como las que nos gustan) sólo hará falta un cable para cada canal de comunicación (en lugar de ocho). Pensad en un local con gente dentro. Si el local tiene 8 puertas la gente puede salir más rápidamente (en paralelo) que si sólo tiene una (en serie). Pero cuando las puertas son caras (y en seguida explico por qué) es más conveniente tener una para salir -quizá también otra para entrar- y organizar el horario de la gente para que no se amontonen 🙂
Por qué las puertas de la analogía son caras? Porque llevadas al terreno real del que hablábamos (comunicaciones entre máquinas), hace falta un cable por cada puerta que tengamos, además de un pin en el conector y una electrónica que se haga cargo de ello. En los ordenadores antiguos (pre-USB) existían el «puerto serie» y el «puerto paralelo»; para que os hagáis una idea el puerto serie llevaba un conector de 10 pines y el paralelo llevaba 26 (y valían para lo mismo, más o menos). Es mucho más fácil (y barato) trabajar con cables de 10 hilos que con cables de 26. De hecho, a medida que la informática ha ido evolucionando, los puertos paralelos (VGA para monitores, IDE para los discos duros…) se han ido cambiando por soluciones que envían y reciben los datos en serie (HDMI, S-ATA…)
3.- Volviendo al presente: Comunicaciones serie
Una vez que hemos pasado el mal trago de leer las historias del abuelo cebolleta, nos toca meternos en harina. Hablemos de comunicaciones serie de hoy en día!!!
En el mundillo en el que nos movemos, sobre todo cuando hablamos de proyectos de electrónica con Arduino y otros controladores, podemos encontrar referencias a varios sistemas de comunicación serie: I2C, SPI, UART e incluso USB. Todos ellos son diferentes entre sí -y sirven normalmente para cosas distintas- pero tienen una cosa en común: Son protocolos serie. No obstante, cuando hablamos de «puerto serie» nos referimos normalmente a UART y, algunas veces, a su abuelo el RS-232. Este último es el «serie» de los ordenadores antiguos del que hablábamos antes. No lo vamos a utilizar pero conviene conocerlo, ya que sus señales pueden freir nuestro arduino si no las adaptamos primero.
Como hemos dicho, vamos a centrarnos en el puerto serie «moderno», al que se conoce por UART (Universal Asynchronous Receiver-Transmitter, toma ya). Nuestros ordenadores no llevan un puerto UART integrado, pero podemos conseguir un adaptador USB-UART por muy poquito dinero (alrededor de 1 euro) en los habituales vendedores de oriente, sólo hay que buscar cosas como «USB-UART», «FTDI» o «CH340». No nos asustemos, que lo de «FTDI» y lo de «CH340» son simplemente el nombre de los chips que van a traducir nuestra comunicación USB a UART. La pinta que tienen estos adaptadores es la siguiente:
Por un lado se conecta un cable USB al ordenador, y por el otro salen los pines que van a proporcionar nuestra conexión serie. Para comunicar dos máquinas es necesario conectar como mínimo tres cables: GND (la masa del circuito), TX (transmisión de datos) y RX (recepción de datos). Hay una cosa un poco confusa, y es que (por poner un ejemplo) cuando conectamos un adaptador a un arduino el cable de TX va al pin RX de arduino y el cable RX va a TX en arduino. Si lo pensamos tiene su lógica, el cable que recibe datos en el arduino es el mismo que emite datos en el adaptador, y viceversa.
También debemos fijarnos en el voltaje de salida de nuestro adaptador, hay adaptadores de 5V y de 3.3V, aunque lo habitual es que lleve un jumper o un interruptor para elegir el voltaje de las señales. Tendremos que tener claro el voltaje con el que funciona el sistema con el que queremos hablar, o nos arriesgamos a freir nuestro sistema.
En otros casos la placa con la que queremos hablar lleva directamente un conector USB, esto normalmente nos quiere decir que es capaz de traducir las señales por sí misma y que no nos hace falta ningún adaptador, simplemente conectarla con el cable USB adecuado.
Y bien, qué podemos hacer con ello? Básicamente sirve para «hablar» con placas electrónicas, y lo bueno del caso es que casi todos los aparatos un poco complejos llevan algún tipo de comunicaciones: Placas controladoras de drones, de impresoras 3D, pantallas LCD, módulos de comunicaciones para arduino -bluetooth, wifi, GSM…- y muchas más cosas. Muchos electrodomésticos «inteligentes» llevan dentro placas con puertos de comunicación que permiten saber el estado del aparato en sí, o incluso recibir comandos. No todas estas comunicaciones son UART, pero una vez que nos sintamos cómodos con ésta, pasar a otro tipo de comunicaciones es bastante sencillo.
4.- Línea de comandos: No da miedo y queda muy hacker 🙂
Ya metidos en harina y con nuestra máquina (impresora, arduino… lo que sea) conectada correctamente al ordenador, tendremos que saber si la reconoce «de por sí» o hay que instalar algún driver. En windows iríamos al «administrador de dispositivos» (botón derecho en Mi PC > «propiedades») y allí buscamos si nos ha aparecido algún puerto COM nuevo. En Linux podemos usar el comando «lsusb» e investigar la salida de «dmesg». No entro en más detalles porque esto da para otro artículo, pero lo que sí es importante es que nos fijemos en el nombre de nuestro puerto (COM4, COM9, /dev/ttyUSB0, /dev/ttyS0…)
Además de esto tendremos que hacernos con una aplicación de terminal, un programa que se encargue de recibir nuestras pulsaciones de teclado y enviarlas por el puerto que nosotros le digamos. Hay muchas y la mayoría son muy sencillas, pero siguiendo un buen consejo nos centraremos en PuTTY, que es libre y lo hay para Windows y para Linux. Los usuarios de Mac tienen una aplicación integrada que se llama Terminal (muy imaginativo el nombre).
Página web de PuTTY (en inglés)
Página de descargas
Enlace directo a PuTTY.exe
Descargamos el programa y lo ponemos en alguna parte ya que no hace falta instalarlo, en windows con bajar PuTTY.exe y ponerlo por ahí en una carpeta es suficiente, en linux se podrá mirar en los respectivos repositorios, vosotros sabéis cómo hacerlo 😉
Una vez que estamos en PuTTY veremos una pantalla en la que nos pregunta la configuración de la conexión, dar con la configuración adecuada es quizá lo más difícil de todo el proceso pero no nos desanimemos que ya queda muy poco para poder hablar con nuestras máquinas!
Pantalla de inicio de PuTTY
En la parte derecha de la ventana nos saldrán unos botones para seleccionar el tipo de conexión (donde pone «Connection type»). Seleccionaremos ahí «Serial» que es de lo que estamos hablando hoy 🙂 y veremos cómo cambian los campos de texto que están justo encima, para pedirnos un puerto (Port) y una velocidad (Speed). El puerto es el que hemos localizado antes (COM1, /dev/ttyUSB0, etc) y la velocidad la conseguiremos buscando nuestra placa concreta en San Google. Por ejemplo, para las placas de las Geetech Prusa I3 chinas tan de moda, vemos en eBay que llevan una placa «GT2560». Buscamos «GT2560 baudrate» («baudrate» es un término técnico equivalente a velocidad en puertos serie) y en seguida encontramos que la velocidad es de 250000 bps (bits por segundo, los famosos «baudios»). Este dato suele ser fácil de encontrar, pero si en un caso concreto no lo localizamos podemos probar con las velocidades «estándar», que son 2400, 9600, 19200, 38400, 57600, 115200 y 250000. No son tantas y además no corremos ningún riesgo de estropear nada. Intentaríamos conectar a la velocidad mayor (es decir, a 250000 bps), enviamos un comando (lo veremos en seguida) y si no obtenemos respuesta, repetimos la conexión a la velocidad inmediatamente inferior (115200 bps). Así hasta que nuestra placa nos responda 🙂
Debajo de estas opciones hay un área en la que podemos guardar y cargar «perfiles de conexión». Para guardar la conexión simplemente hay que configurarla arriba, asignar un nombre donde pone «Saved Sessions» y dar al botón «Save». Para recuperar una conexión guardada seleccionamos el nombre, damos a «Load» y los parámetros se cargarán sólos.
En la parte izquierda de la ventana hay un árbol con un montón de configuraciones, la que viene de serie con el programa nos sirve por lo que no tendremos que tocar nada. Podemos recordar, eso sí, que las opciones «avanzadas» de la conexión serie (parity, stop bits, flow control…) están abajo del todo, en la sección «Serial». Algunas veces veremos que una conexión a un aparato el «115200 8N1». Este caso correspondería a una velocidad de 115200 bps, 8 data bits, «parity=none» y 1 stop bit.
Una vez que tenemos la conexión configurada daremos al botón «Open» y PuTTY nos abrirá una pantalla negra que será la terminal donde hablemos con nuestra máquina. Pero… En qué idioma? De momento -y si estamos conectados a una impresora 3D- podemos probar a escribir «M115» (sin comillas, y luego Enter) y ver si dice algo. El comando sirve para que la impresora nos diga la versión de firmware, cosa que también nos interesa saber.
5.- Gcode (el extraño idioma de las máquinas CNC)
Gcode es un idioma estándar muy utilizado en todo tipo de máquinas CNC, incluidas las impresoras 3D. Consta de una serie de «códigos G» y otros «Códigos M». Cada desarrollador de firmwares para impresoras hace una interpretación de los códigos por lo que puede que algunos funcionen y otros no, o hagan cosas diferentes. En cada caso habría que consultar (y tener a mano una copia en papel) de los códigos correspondientes a nuestra máquina, que suelen estar documentados en la página web del desarrollador.
Gcode de Marlin
Gcode de RepRap
Si abrimos un archivo gcode de nuestra tarjeta SD con cualquier editor de textos (bloc de notas, por ejemplo) veremos que éste se compone de un montón de líneas que empiezan por G o por M; pues bien, esas líneas son instrucciones que la impresora va leyendo y ejecutando una detrás de otra. También hay unas líneas que empiezan por el carácter «;» que son comentarios y la máquina las ignora. La mayoría de comandos Gcode llevan parámetros asociados, que se suelen definir con letras, por ejemplo:
M104 – Calentar extrusor a esta temperatura: Se especifica «M104 S220» para dar la orden de calentar el extrusor a 220ºC. Con «M104 S0» apagaríamos el extrusor.
M140 – Lo mismo, pero con la cama caliente. Se envía «M140 S50» para calentar la cama hasta 50ºC.
M106 – Velocidad de ventilador, que recibe un valor entre 0 y 255. «M106 S0» apagaría el ventilador, «M106 S127» lo haría girar a la mitad de rpm y «M106 S255» lo encendería a potencia completa.
G1 – Mover máquina a estas coordenadas. Esta instrucción es de las más habituales porque define los movimientos de la impresora, aunque también es de las más complejas porque recibe varios parámetros. «G1 X58.775 Y60.455 Z0.315 E1.34628 F300» indicaría a la máquina que mueva el cabezal a las coordenadas X Y Z indicadas (por los números, con decimales), el extrusor E a esa posición (es decir, que inyecte filamento) y el parámetro F nos indica el feedrate, es decir, la velocidad a la que hay que efectuar el movimiento. Hay que tener en cuenta, por supuesto, que pasar parámetros como este manualmente a la impresora puede hacer que ésta se rompa por golpear alguna pieza de sí misma con la cabeza de impresión o por intentar mover la máquina fuera de sus límites mecánicos. Por ejemplo, es posible que si le decimos que mueva la cabeza de impresión a X250, la máquina intente hacer el movimiento aunque la superficie de impresión sea de 200×200, corriendo el riesgo de dañar motores, correas o husillos.
Bien, y para qué sirve todo esto?
En primer lugar saber hacer estas cosas ayuda a conocer mejor nuestra máquina y a hacer un uso más «fino» de ella. Podemos interpretar los archivos gcode que nos proporciona nuestro laminador (cura, repetier, slic3r), buscar fallos y modificar su comportamiento. Es una tarea tediosa, sí, pero puede hacerse. Por ejemplo puede ser interesante localizar un punto concreto en nuestro proceso de impresión (al iniciar la capa número 450, por ejemplo) e instertar en él una orden de pausa, de manera que la impresión quede interrumpida y nos dé tiempo a incrustar un elemento externo (un contrapeso, una tuerca, un imán…) dentro de la propia estructura de la pieza a imprimir, y mientras ésta se imprime. También podemos (al menos en Cura se puede) configurar unos «códigos de inicio» y otros «de final», que el programa se encargará de añadir al principio y al final de los archivos gcode que genere: Podemos apagar ventiladores, mover la cabeza y la cama a un punto en el que podamos extraer la pieza más fácilmente…
En segundo lugar, conocer los códigos gcode de nuestra impresora y poder comunicárselos nos permite hacer cosas que el programa con el que la usamos (los vistos en el punto 1: Octoprint, Pronterface…) no tenía previstos, como por ejemplo realizar un ajuste fino de los pasos por milímetro de los motores (M92 en Marlin) para que nuestras piezas tengan la máxima precisión dimensional posible, o ajustar los valores de aceleración de cada eje para evitar que los motores pierdan pasos. Es muy interesante leer la guía de códigos de nuestro firmware para descubrir lo que podemos hacer pasando gcodes a mano.
6.- Otras cosas que podemos hacer con conexiones serie
Ahora que ya sabemos hablar con nuestra impresora, no debería darnos miedo hablar con nuestros arduinos (por ejemplo). Si alguna vez habéis copiado de Internet un programa para arduino, posiblemente os hayais fijado que casi siempre contienen la línea «Serial.begin(9600);». Esta línea ordena al arduino que utlice su puerto serie (pines 0=RX y 1=TX normalmente) a la velocidad de 9600 bps. Si en ese mismo programa añadimos líneas como «Serial.write(«Hola»);» la placa transmitirá la palabra «Hola» por su puerto serie y nos aparecerá en nuestra pantalla de PuTTY. También puede recibir nuestras órdenes, utilizando la instrucción «Serial.read();» en el programa. De esta forma nuestro proyecto de arduino se podrá comunicar con nosotros y podremos activar las funciones que programemos en él sin necesidad de utilizar sensores o pulsadores para todo. Además viene muy bien activar las funciones de puerto serie para poder debuggear (encontrar y solucionar fallos) en nuestro programa (de hecho es la razón por la que los ejemplos la llevan), insertando en nuestro código instrucciones como «Serial.write(«Hemos entrado en el bucle for que va restando la variable nosecuál»);». De esta manera el programa nos va diciendo qué cosas va haciendo.
Es muy interesante aprender de los ejemplos que vienen incluídos con el programa Arduino que, por cierto, contiene su propio monitor serie (aparece pulsando Ctrl+Mayus+M o en el icono a la derecha). También resulta importante comentar que no conviene pasarse con la velocidad a la que conectamos con arduino, ya que su hardware es limitado y suele dar bastante guerra a partir de 115200 bps.
Otra aplicación muy interesante es el uso, mediante arduino o similares, de diferentes módulos. Por bastante poco dinero podemos utilizar un módulo bluetooth para conectar nuestro proyecto a un smartphone sin necesidad de cables. También podremos enviar y recibir SMS e incluso llamadas mediante un módulo GSM, o leer y escribir tarjetas RFID. Cada uno de estos módulos tendrá su propio «lenguaje» de comunicación (gcode es sólo para máquinas CNC) pero suelen ser bastante sencillos (por ejemplo, los códigos AT de los módems).
7.- Avanzando en las comunicaciones serie: Pistas y siguientes pasos
Es un buen momento para mirar atrás por un momento y ver lo que hemos hecho: A que hace unas horas nos daba mucho miedo esto de enchufarnos diréctamente a nuestra electrónica? En cuanto hayamos hecho un par de veces las cosas de las que se habla en este post, seguro que nos parecerá lo más normal del mundo 🙂 Pero claro, por dónde tiramos ahora para profundizar en nuestros conocimientos sobre las comunicaciones electrónicas. Dejad que os dé un par de pistas:
Por un lado tenemos el código ASCII (seguro que os suena). Es un conjunto de caracteres que viene de antaño (dice Wikipedia que se creó en 1963), y sirve para representar y controlar sistemas mediante entrada y salida de texto. Os suena, no? Exacto! Es lo que hemos estado haciendo! De hecho las comunicaciones a través de UART se codifican mediante el estándar ASCII y cada símbolo se expresa mediante un byte (8 bits), que es el tamaño «estándar» de paquete transportado por un puerto serie. Se suele representar en forma de tabla, por eso muchas veces se la llama «La tabla ASCII«.
Por otra parte tenemos los códigos Hayes (más conocidos como comandos AT), que son los que utilizan la mayoría de módems, tanto de línea telefónica fija (aquellos que pitaban) como los modernos módems GSM. Tambien lo utiliza el famoso módulo bluetooth HC-05 (y su primo el HC-06) por lo que es interesante saber de qué va. Con esto pasa un poco como con el Gcode, cada módulo y cada fabricante implementa una interpretación del mismo, por lo que conviene comprobar la documentación del módulo en cuestión. No obstante, el conjunto de comandos Hayes estándar se puede consultar en la Wikipedia.
Además de estas dos cosas podemos interesarnos por otros protocolos de comunicación serie, como I2C y SPI, con los cuales podremos controlar -entre otras cosas- pequeñas pantallas OLED, tarjetas MicroSD y multitud de sensores. Aunque estos dan para otros dos artículos de 7 puntos cada uno 🙂
8.- Despedida y cierre
Ya hemos aprendido a conectarnos con nuestras máquinas y a hablar con ellas en su idioma y sin intermediarios. No está mal para una tarde verdad? Lo más importante del asunto es meterse en harina y perder el miedo, el resto viene sólo poco a poco, informándonos por internet y dándole a eso de «aprender haciendo». En cualquier caso espero que esta información os haya servido para ampliar vuestras capacidades y -ojalá- os hayais entretenido leyendo esto tanto como yo escribiéndolo. Si tenéis cualquier duda ya sabéis dónde encontrarnos. Habrá además miles de expertos en los foros de internet que estarán encantados de ayudaros. No tengáis vergüenza de preguntar.
Enhorabuena por este artículo tan didáctico. Llevo desde 2013 trasteando en este mundillo (empezando poco a poco y cada vez cogiendo más velocidad) y algunas cosas creía que las sabía, pero estaban muy desordenadas.
Muchas gracias!