¿Qué es la comunicación serie?

La electrónica integrada se conforma con circuitos interconectados (procesadores u otros circuitos integrados) para crear un sistema en el que están repartidas las funciones. Para que esos circuitos individuales intercambien su información, deben compartir un protocolo de comunicación común. Se han definido muchos protocolos de comunicación para lograr este intercambio de datos y, esencialmente, cada uno puede ubicarse en una de dos categorías: 1. Paralelo o 2. Serie.

Paralelo versus serie

Las interfaces paralelas transfieren múltiples bits simultáneamente. Por lo general, requieren barras (buses) de datos, que se transmiten a través de ocho, dieciséis o más cables. Los datos se transfieren en amplios oleajes de 1s y 0s.

Un bus de datos de 8 bits, controlado por un reloj,
que transmite un byte por cada pulso de reloj. Se utilizan 9 líneas


En cambio, las interfaces serie transmiten sus datos un bit a la vez. Estas interfaces pueden operar con tan solo un cable, por lo general nunca más de cuatro.

Ejemplo de una interfaz serie, transmitiendo un bit cada pulso de reloj. Solo se requieren 2 cables


Piense en las dos interfaces como una fila de automóviles: una interfaz paralela sería una autopista de 8 carriles o más, mientras que una interfaz en serie es más parecida a una carretera de dos carriles. Durante un lapso determinado, la autopista tiene el potencial de llevar a más personas a destino, pero en muchos casos ese sistema sencillo de dos carriles responde a su propósito, y construirlo cuesta una fracción de los fondos.

La comunicación paralela ciertamente tiene sus beneficios. Es rápida, directa y relativamente fácil de implementar. Pero requiere muchas más líneas de entrada/salida (E/S). Si alguna vez ha tenido que traspasar un proyecto de un Arduino Mega a un Arduino UNO básico, sabe que las líneas de E/S en un microprocesador pueden ser preciosas por lo limitadas. Por lo tanto, cada vez más optamos por la comunicación en serie, sacrificando una velocidad potencial para ahorrar pines.

Serie asíncrono (asincrónico)

A lo largo de los años, se han creado docenas de protocolos en serie para satisfacer las necesidades particulares de los sistemas integrados. USB (Universal Serial Bus = Bus Serie Universal) y Ethernet son dos de las interfaces serie de computación más conocidas en la actualidad. Otras interfaces serie muy comunes son SPI (del inglés Serial Peripheral Interface), I²C (del inglés Inter-Integrated Circuit) y el interfaz serie estándar TX/RX, del que hablaremos aquí. Estas interfaces serie pueden clasificarse en uno de dos grupos: sincrónico o asincrónico.

Una interfaz serie sincrónica siempre necesita tener una señal de reloj junto a las líneas de datos, por lo que todos los dispositivos en un bus serie sincrónico comparten un pulso común de reloj. Esto hace que en una transferencia en serie más directa, a menudo más rápida, también se requiera al menos un cable adicional entre los dispositivos de comunicación. Entre los ejemplos de interfaces sincrónicas están SPI e I²C.

Asincrónico significa que los datos se transfieren sin el respaldo de una señal de reloj conectada entre sistemas. Este método de transmisión es ideal para minimizar los cables necesarios, y en consecuencia la cantidad de pines de E/S utilizados, pero implica que debemos poner un poco de esfuerzo adicional en transferir y recibir datos de manera confiable. El protocolo en serie que analizaremos es la forma más común para las transferencias asincrónicas. De hecho, es tan común que cuando la mayoría de la gente dice «en serie», “o serial”, están hablando sobre este protocolo.

El protocolo serie sin reloj que analizaremos se usa ampliamente en electrónica integrada. Si está buscando agregar un módulo serie GPS, Bluetooth, XBee, LCD, o muchos otros dispositivos externos a su proyecto, es probable que necesite un interfaz serie.

Reglas de la comunicación serie

El protocolo serie asincrónico tiene una serie de reglas integradas: mecanismos que ayudan a garantizar transferencias de datos sólidas y sin errores. Estos mecanismos, que obtenemos para evitar la señal del reloj externo, son:

   ■ Bits de datos
   ■ Bits de sincronización
   ■ Bits de paridad
   ■ Velocidad en baudios

Teniendo en cuenta la variedad de estos mecanismos de señalización, vemos que no hay una sola manera de enviar datos en serie. El protocolo es altamente configurable. La parte crítica es asegurarse de que ambos dispositivos en una línea serie estén configurados para usar exactamente los mismos protocolos.

Velocidad en baudios

La especificación de velocidad de transmisión indica qué tan rápido se envían los datos a través de una línea serie. Normalmente se expresa en unidades de bits por segundo (bps). Si se invierte la velocidad en baudios, se puede averiguar cuánto tiempo se tarda en transmitir cada bit. Este valor determina durante cuánto tiempo el transmisor mantiene en alto/bajo una línea serie, o a qué velocidad muestrea su línea el dispositivo receptor.

Las velocidades en baudios pueden ser casi cualquier valor dentro de lo que permite el hardware. El único requisito es que ambos dispositivos funcionen a la misma velocidad. Una de las velocidades en baudios más comunes, especialmente para cosas simples donde la velocidad no es crítica, es de 9600 bps. Otras velocidades en baudios «estándar» son 1200, 2400, 4800, 19200, 38400, 57600 y 115200.

Cuanto mayor sea la velocidad en baudios, más rápido se envían/reciben los datos, pero existen límites para la velocidad a la que se pueden transferir los datos. Por lo general, no verá velocidades superiores a 115200, lo que es suficientemente rápido para la mayoría de los microcontroladores. Aumente demasiado y comenzará a ver errores en el extremo receptor, ya que los pulsos de reloj y los períodos de muestreo no pueden mantenerse.

Estructurando los datos

Cada bloque de datos (generalmente un byte) que se transmite se envía en realidad en un paquete de bits. Los paquetes se crean agregando bits de sincronización y paridad a nuestros datos.

Algunos símbolos en la estructura del paquete tienen tamaños de bits que son configurables.

Vamos a entrar en los detalles de cada una de estas partes de la estructura del paquete, o bloque.

Bloque de datos

La verdadera sustancia de cada paquete serie es la información que lleva. Ambiguamente llamamos a este bloque de datos un “bloque”, porque su tamaño no está específicamente establecido. En este estándar, la cantidad de datos en cada paquete se puede establecer en valores de 5 a 9 bits. Ciertamente, el tamaño de datos clásico es un byte de 8 bits, pero se usan otros tamaños. Un bloque de datos de 7 bits puede ser más eficiente que 8 si solo está transfiriendo caracteres ASCII de 7 bits.

Después de acordar la longitud para un caracter, ambos dispositivos serie también tienen que acordar el formato de sus datos. ¿Se envían los datos desde el bit más significativo (most significative bit = msb) al menos significativo, o viceversa? Si no se indica lo contrario, generalmente se puede asumir que los datos se transfieren enviando primero el bit menos significativo (least significative bit = lsb).

Bits de sincronización

Los bits de sincronización son dos o tres bits especiales transferidos con cada porción de datos. Son el bit de inicio y el(los) bit(s) de parada. Tal como indica su nombre, estos bits marcan el principio y el final de un paquete. Siempre hay un único bit de inicio, pero la cantidad de bits de parada se puede configurar en uno o dos (aunque normalmente se deja en uno).

El bit de inicio siempre se indica mediante una línea de datos inactiva que pasa de 1 a 0 (ALTO a BAJO). Los bits de parada volverán al estado inactivo manteniendo la línea en 1 (ALTO).

Bits de paridad

La paridad es una forma de comprobación de errores muy simple y de bajo nivel. Se presenta en dos variantes: impar o par. Para generar el bit de paridad, se suman todos los bits del byte de datos (5 a 9), y el resultado de la suma define si el bit es 1 o 0. Por ejemplo, suponiendo que la paridad se establece en par y se agrega a un byte de datos como 0b01011101, que tiene una cantidad impar de 1s (5), el bit de paridad quedaría en 1. Por el contrario, si el modo de paridad se configuró en impar, el bit de paridad sería 0.

La paridad es opcional, y no se usa mucho. Puede ser útil para transmitir a través de medios ruidosos, pero también ralentizará un poco la transferencia de datos y requiere que tanto el transmisor como el receptor implementen el manejo de errores (generalmente, si se detecta error, los datos recibidos con falla deben reenviarse).

Un ejemplo

9600 8N1 – 9600 baudios, 8 bits de datos, sin paridad y 1 bit de parada: es uno de los protocolos serie más utilizados. Entonces, ¿cómo se vería un paquete o dos de datos de 9600 8N1?

Un dispositivo que transmita los caracteres ASCII ‘O’ y ‘K’ tendría que crear dos paquetes de datos. El valor ASCII de O (en mayúsculas) es 79, que se divide en un valor binario de 8 bits de 01001111, mientras que el valor binario de K es 01001011. Todo lo que queda es agregar bits de sincronización.

No se establece específicamente, pero la norma más aceptada es que los datos se transfieren enviando primero el bit menos significativo. Observe cómo se envía cada uno de los dos bytes a medida que se lee de derecha (bit 0) a izquierda (bit 7).

Dado que estamos transfiriendo a 9600 bps, el tiempo empleado en mantener cada uno de esos bits alto o bajo es 1/9600 (bps) o 104 µs por bit.

Por cada byte de datos transmitidos, en realidad como mínimo se envían 10 bits: un bit de inicio, 8 bits de datos y un bit de parada. Entonces, a 9600 bps, en realidad estamos enviando 9600 bits por segundo o 960 (9600/10) bytes por segundo.

Ahora que sabemos cómo construir paquetes serie, podemos pasar a la sección de hardware. Allí veremos cómo esos 1s y 0s, y la velocidad de transmisión, se implementan a un nivel de señal.

Cableado y Hardware

Un bus serie consta de solo dos cables, uno para enviar datos y otro para recibir. Entonces, los dispositivos serie deben tener dos pines serie: el receptor: RX y el transmisor: TX.

Cableado en serie

Es importante tener en cuenta que esas etiquetas RX y TX son con respecto al dispositivo en sí. Entonces, el RX de un dispositivo debe ir al TX del otro y viceversa. Es extraño si uno está acostumbrado a conectar Vcc con Vcc, GND con GND, MOSI con MOSI, etc., pero —pensándolo— tiene sentido. El transmisor debe estar comunicándose con un receptor, no con otro transmisor.

Una interfaz en serie en la que ambos dispositivos pueden enviar y recibir datos es dúplex completo (full-duplex) o semidúplex. Full-duplex significa que ambos dispositivos pueden enviar y recibir simultáneamente. La comunicación semidúplex significa que los dispositivos serie deben turnarse para enviar y recibir.

Algunas conexiones serie pueden implementarse con una sola línea entre un dispositivo de transmisión y un dispositivo de recepción. Por ejemplo, los LCD que tienen conexión serie son solo receptores, y realmente no tienen ningún tipo de información para devolver al dispositivo de control. Esto es lo que se conoce como comunicación serie simplex. Todo lo que necesita es un solo cable desde la transmisión del dispositivo maestro a la línea RX del que recibe.





Implementación de hardware

Hasta ahora fue una cobertura de la comunicación serie asíncrona desde un lado conceptual. Sabemos qué cables necesitamos, pero, ¿cómo se implementa realmente la comunicación en serie a nivel de señal? En una variedad de formas, en realidad. Hay todo tipo de estándares para la comunicación en serie. Veamos algunas de las implementaciones de hardware más populares de serie: nivel lógico o TTL, y RS-232.

Cuando los microcontroladores y otros circuitos integrados de bajo nivel se comunican en serie, generalmente lo hacen a un nivel TTL (Transistor Transistor Logic = Lógica Transistor-Transistor). Las señales serie TTL están en el rango del voltaje que alimenta a un microcontrolador, generalmente de 0V a 3,3V, 0V o 5V. Una señal en el nivel VCC (3,3V, 5V, etc.) indica una línea inactiva, un bit de valor 1 o un bit de parada. Una señal de 0V (GND) representa un bit de inicio o un bit de datos de valor 0.

El protocolo RS-232, que se puede encontrar en algunas de las computadoras y periféricos más antiguos, es como una interfaz serie TTL puesta cabeza abajo. Las señales RS-232 generalmente oscilan entre -13V y 13V, aunque la especificación permite cualquier cosa desde +/- 3V a +/- 25V. En estas señales, un voltaje bajo (-5V, -13V, etc.) indica la línea inactiva, un bit de parada o un bit de datos de valor 1. Una señal RS-232 alta significa un bit de inicio o un bit de datos de valor 0. Eso es lo contrario del protocolo TTL.

Entre los dos estándares de señal en serie, el TTL es mucho más fácil de implementar en circuitos integrados. Sin embargo, los niveles de baja tensión son más susceptibles a sufrir pérdidas en las líneas de transmisión largas. El RS-232 o estándares más complejos —como RS-485— son más adecuados para transmisiones en serie de largo alcance.

Cuando conecte dos dispositivos serie juntos, es importante asegurarse de que coincidan los voltajes de su señal. No se puede conectar directamente un dispositivo serie TTL con una línea RS-232. Se deben adaptar esas señales.

Continuando, exploraremos la herramienta que usan los microcontroladores para convertir sus datos que se encuentran presentes en un bus paralelo desde y hacia una interfaz serial: se llama UART.

UARTs

La última pieza de este armado en serie es encontrar algo para crear los paquetes en serie y controlar las líneas de hardware físico. Esto se concreta con un módulo llamado UART (Universal Asynchronous Receiver/Transmiter = Receptor/Transmisor Asíncrono Universal).

Un receptor/transmisor asíncrono universal es un bloque de circuitos responsable de implementar la comunicación en serie. En esencia, este UART actúa como un intermediario entre las interfaces paralelas y seriales. En un extremo del UART hay un bus de ocho o más líneas de datos (más algunos pines de control), en el otro lado están los dos cables serie: RX y TX.

UART simplificado
UART
Los UART existen como circuitos integrados independientes, pero en la actualidad es más común que se encuentren dentro de los microcontroladores. Debemos consultar la hoja de datos de un microcontrolador para ver si tiene algún UART. Algunos no tienen, otros tienen uno, otros tienen varios. Por ejemplo, el Arduino UNO, basado en el «antiguo y fiel» ATmega328, tiene un solo UART, mientras que el Arduino Mega, construido sobre un ATmega2560, tiene cuatro UART.

Como lo indican las letras R y T en el acrónimo, los UART son responsables de enviar y recibir datos en serie. En el lado de transmisión, un UART debe crear el paquete de datos —agregando la sincronización y los bits de paridad— y enviar ese paquete por la línea TX con una sincronización precisa (de acuerdo con la velocidad de transmisión establecida). En el extremo de recepción, el UART tiene que muestrear la línea de RX a velocidades acordes con la velocidad de transmisión que se espera, seleccionar los bits de sincronización y entregar como resultado los datos.

UART interno

Los UART más avanzados pueden enviar los datos que reciben a un archivo de memoria de respaldo, llamado búfer, donde pueden permanecer hasta que el microcontrolador vaya a buscarlos. Los UART generalmente publicarán sus datos almacenados en un búfer con un sistema de “el primero que entra es el primero que sale” (First In First Out = FIFO). Los búfer pueden tener apenas unos pocos bits, o pueden ser de gran tamaño, como miles de bytes.

Diagrama de bloques de un UART con FIFO


UARTs de software

Si un microcontrolador no tiene un UART, o no tiene suficientes, se puede implementar la interfaz en serie en bits que son controlados directamente por el procesador. Este es el enfoque que tienen las bibliotecas de Arduino como SoftwareSerial. El uso de bits es intensivo en el procesador, y no suele ser tan preciso como un UART, pero funciona en caso de necesidad.

Errores comunes

Eso fue todo lo básico sobre la comunicación en serie. Podemos dejar señalados algunos errores comunes que un ingeniero, de cualquier nivel de experiencia, puede llegar a cometer:

RX a TX, / TX a RX

Parece bastante simple, pero es un error que algunos cometen un par de veces. Por mucho que desee que sus etiquetas coincidan, siempre asegúrese de cruzar las líneas RX y TX entre los dispositivos serie.

FTDI Basic programando un Pro Mini. Note que RX y TX están cruzados


Discrepancia en la velocidad de transmisión

Los valores de baudios son como claves en lenguajes de la comunicación en serie. Si dos dispositivos no están hablando a la misma velocidad, los datos pueden ser mal interpretados o completamente perdidos. Si todo lo que el dispositivo receptor ve en su línea de recepción está compuesta de caracteres extraños, llamados “basura” en el ambiente, verifique que coincidan las velocidades en baudios definidas en ambos extremos.

Datos transmitidos a 9600 bps, pero recibidos a 19200 bps. Desajuste de baudios = basura


Contención de transferencia en la línea

La comunicación en serie está diseñada para permitir que solo dos dispositivos se comuniquen a través de un bus en serie. Si más de un dispositivo está intentando transmitir en la misma línea serie, podría encontrarse con una contención de bus.

Por ejemplo, si está conectando un módulo GPS a su Arduino, puede conectar la línea de transmisión de ese módulo a la línea RX de Arduino. Pero ese pin Arduino RX ya está conectado al pin TX del convertidor de USB a serie (por ejemplo un chip FTDI) que se usa cada vez que se programa el Arduino, o se usa el Monitor Serie. Esto establece la situación potencial en la que tanto el módulo GPS como el chip FTDI intentan transmitir en la misma línea al mismo tiempo.

Ejemplo de contención de línea (o bus)

No es bueno que dos dispositivos intenten transmitir datos al mismo tiempo en la misma línea. En el mejor de los casos, ninguno de los dispositivos podrá enviar sus datos. En el peor de los casos, las líneas de transmisión de ambos dispositivos se volverán locas (aunque eso es raro y generalmente están protegidos contra esta situación).

Puede ser seguro conectar varios dispositivos receptores a un solo dispositivo de transmisión. Realmente no cabe dentro de las especificaciones, y probablemente esté mal visto por un ingeniero experimentado, pero funcionará. Por ejemplo, si conectamos un LCD serie a un Arduino, el método más sencillo puede ser conectar la línea RX del módulo LCD a la línea TX del Arduino. El TX de Arduino ya está conectado a la línea RX del programador USB, pero eso deja solo un dispositivo controlando la línea de transmisión.

Implementación segura pero dudosa de un transmisor y dos receptores

La distribución de una línea de transmisión de este tipo puede ser peligrosa desde la perspectiva del firmware, ya que no puede elegir qué dispositivo recibe cual transmisión. La pantalla LCD terminará recibiendo datos que no están destinados a ella, lo que podría ordenarle que pase a un estado desconocido.

Hay formas de implementarlo, usando un poco de hardware adicional, pero esto es tema para otro artículo.



Manejo preciso de servos en Arduino: grados y milisegundos

Siendo miembro de grupos donde uno se entera de diversos problemas que se les presentaron a otros, a veces uno que resulta básico pero nunca se le ha presentado. En este caso se trató de un problema con el manejo de un servo que es el más vendido para los que se inician, y que a demás viene con los kits básicos de Arduino: el mini o micro servo SG90. El problema se presenta con la biblioteca Servo, pero también puede ocurrir con otro programa.

Me dije —ya que he manejado servos desde antes de que apareciera Arduino— que el problema debía ser una señal de posicionamiento incorrecta. Para entender bien de qué hablo, le pueden dar una mirada al artículo Servos: características básicas.

Una señal se comprueba con osciloscopio. Por suerte dispongo tanto de uno antiguo, con pantalla CRT, como de los que se pueden comprar ahora dentro de la familia Arduino, dotado de un pantalla TFT.

Después de algunas mediciones, me di cuenta de que el funcionamiento de la biblioteca Servo.h de Arduino deja un poco que desear, ya veremos por qué. Pero también ofrece una herramienta (en la función servo.attach) que, bueno, puede ser que no hayamos investigado y que por algo está disponible. Esto puede parecer algo para principiantes, pero hasta que uno empieza a tener estas complicaciones no se da cuenta, y luego de tener una comprensión mejor se logra usar la biblioteca de servo de Arduino con facilidad y dominando lo que hace.

Función write()

La razón de ser de una biblioteca es que uno se pueda desentender del manejo de programa específico de un elemento conectado a una placa de microcontrolador, y bueno, la biblioteca Servo de Arduino fue hecha para facilitar el control de los servos con un mínimo de código y complicaciones. La página de referencia de Arduino para el comando write(), que es parte de la biblioteca Servo.h, trae el siguiente código de ejemplo:

Este código de ejemplo le indica a un servo, conectado en este caso al pin 9, que se mueva a su posición central (que se define como 90°). Si se tratara de un servo de rotación continua, esto detendrá el movimiento del servo… pero este es tema para otro artículo.

Al correr este pequeño programa de demostración, los servos que se han conectado a ese pin se colocarán en sus posiciones centrales. Pero bueno, si lo consideramos desde la faceta mecánica, este punto medio puede que en algunos servos no sea exactamente el centro del arco completo del recorrido.

Un pulso con un ancho de 1.500 microsegundos debe corresponder a 90°, posición definida como el punto central del recorrido. Los servos más comunes aceptan entradas de 1.000 µs (1 ms) a 2.000 µs (2 ms), y 1.500 µs (1,5 ms) correspondientes a la posición central. Para un servo con un recorrido de 0 a 180°, esto sería 90°.





Ahora me toca aclarar que siempre utilicé valores en microsegundos para controlar servos, ya que la precisión del posicionamiento es mucho mayor. La biblioteca de servos permite usar el comando writeMicroseconds, que define el ancho de pulso exacto que se desea enviar a un servo. Los problemas comienzan cuando se usan ejemplos —ya escritos— en los que se utiliza el comando de escritura con un parámetro en grados (en el ejemplo de arriba, 90°).

Parecería lógico que un comando de escritura que instruye a un servo para que se ajuste a 90° debería enviar los mismos pulsos que un comando writeMicroseconds que envía pulsos de 1.500 µs. Es decir, write(90) y writeMicroseconds(1500) deberían enviar pulsos idénticos de 1500 µs. Pero resulta que esta suposición puede llevarnos a problemas.

Basándome en un ejemplo de internet, subí el siguiente código a un Arduino UNO R3, y visualicé las señales con osciloscopio.

Aquí es cómo se ven las salidas de los pines 3, 4 y 5:

■ El pin 3 de Arduino, fijado en 90°, da un pulso de 1,472 ms
■ El pin 4 de Arduino produce un pulso de 1.500 µs: 1,500 ms
■ El pin 5 de Arduino, fijado en 90°, da un pulso de 1,500 ms

El ancho de pulso se mide con el programa del osciloscopio. Por las dudas de que sea un problema técnico del osciloscopio, midiendo con un papel superpuesto sobre la pantalla se puede observar que sí existe la diferencia.

Y también al superponer señales, se observa la diferencia.

Esta diferencia entre 1.472 µs y 1.500 µs es pequeña y puede ser que ni siquiera implique diferencias en las posiciones del servo.

Si se observa la señal de servo3, que también programa el movimiento del servo con el parámetro de colocarse en posición de 90°, se nota que el ancho del pulso es correcto, 1.500 µs, el mismo que para servo2, para el que se fijó el pulso en forma directa en 1.500 µs.

El comando write(90) es el mismo en la primera y la tercera señal de servo, así que… ¿por qué uno envía un pulso de 1,472 ms y el otro 1,500 ms?

Arduino attach()

La respuesta está en el comando attach de la librería Servo. La página de referencia de Arduino enumera dos formas del comando:

La primera versión es el código mínimo que requiere un programa para designar un pin de E/S para el control de un servo. El segundo formato incluye dos parámetros muy importantes, pero opcionales, que determinan el rango mínimo y máximo de ancho de pulso para el programa. Es posible que en el ejemplo de arriba, el uso de límites en el segundo servo haya acomodado los valores de tiempo para que el tercero reciba un pulso correcto; pero al volver el bucle al principio y correr la función para 90º sin topes definidos, se vuelve a desacomodar.

Tanto en la página de referencia del comando attach en arduino.cc como en la propia biblioteca Servo, se establece claramente que las configuraciones mínimas y máximas predeterminadas son 544 y 2.400 µs, respectivamente. Pero como hay servos con diferentes extremos de carrera, se pueden fijar estos límites “opcionales” de ancho de pulso, que en realidad —para evitar dolores de cabeza y roturas de los servos— sería bueno acostumbrarse a usar.

Si uno está habituado a usar el comando writeMicroseconds en lugar de write, es posible que nunca haya pensado en los parámetros de ancho de pulso mínimo y máximo. Pero si se usa el comando write y se establecen las posiciones de los servos con ángulos y grados, entonces DEBEMOS definir explícitamente estos parámetros en los programas de Arduino que usan Servo.h, previa lectura de los datos indicados en la hoja de datos del servo utilizado. O si no, definiéndolos experimentalmente; porque hasta existen diferencias entre servos del mismo modelo.

Para definir los valores correctos de extremos de recorrido de un servo, puede utilizar un montaje como el que sigue, que se trata de una cartulina impresa y una aguja señaladora de cartón en el eje del servo, y enviar comandos con writeMicroseconds() hasta lograr el valor para el ángulo cero y el ángulo 180. El disco lo imprimí con un programa on-line muy útil para crear imágenes de discos de encoder.

Ingrese a esta página y pruebe primero con los siguientes parámetros:

Luego puede jugar con los valores hasta lograr el dibujo que usted necesite. Hay otras opciones en internet, incluso hay generadores de código postscript que se puede leer en Corel y que corren en Windows. Es cuestión de buscar.

Solución para la librería Servo

En el código de ejemplo, para la tercera señal de servo no dejaremos los anchos de pulso predeterminados y fijaremos los límites con los valores 1.000 y 2.000 µs. Esta es la razón por la que las señales del primero y tercer servo envían pulsos diferentes aunque se utilicen comandos idénticos.

Además de que no lograremos posicionamientos correctos de los servos con señales ligeramente descentradas, un servo podría interpretar de manera impredecible los anchos de pulso por encima o por debajo de los límites para los que fue diseñado. Los pulsos por debajo y por encima del límite también pueden dañar físicamente un servo.

Si un servo con recorrido de 0 a 180° está diseñado para responder a pulsos de 1.000-2.000 µs, interpretará 1.000 µs como 0°, y 2.000 µs como 180°. Pero, con un rango de límites de ancho de pulso predeterminado de 544 a 2.400 µs, el Arduino enviará una señal de ~1.000 µs para un ángulo de 44°. Un rango de pulsos de 1.000 a 2.000 µs se convertirá en un recorrido mecánico total de ~90° del eje del servo en lugar de 180°. Este y otros problemas potenciales pueden evitarse si se usan microsegundos en lugar de ángulos en grados, o si los parámetros opcionales de ancho de pulso para los extremos se definen en la configuración de pines para cada servo.

Es muy común que se dé por sentado que las bibliotecas de Arduino funcionan correctamente con sólo unos simples parámetros. La próxima vez que sus servos actúen de forma impredecible en un nuevo proyecto, vuelva a verificar que ha establecido los límites de ancho de pulso en la configuración del pin. Puede que con esto sea suficiente y se ahorre gran cantidad de tiempo.



¿Qué es BeagleBone Blue?


BeagleBone® Blue es una computadora integrada en un sistema compacto en una placa, basada en Linux y pensada para robótica, que consta de una sola plaqueta pequeña (8,9 cm x 5,5 cm).

El microprocesador es Octavo Systems OSD3358, posee wifi/bluetooth, IMU, barómetro, regulación de potencia y estado de LED de carga para una batería LiPo de 2 celdas. Tiene puentes H y conectores para 4 motores de CC + sus codificadores (encoders), para 8 servos y todos los buses comúnmente necesarios para adicionar periféricos en aplicaciones integradas.

De código abierto y con un activo respaldo de una comunidad, su rendimiento en tiempo real, flexibilidad para funcionan en redes y el amplio conjunto de capacidades orientadas a la robótica hacen que construir robots móviles con Blue sea rápida, ágil, asequible y divertida.

Especificaciones

■ Procesador: Octavo Systems OSD3358
■ AM335x 1GHz ARM® Cortex-A8 processor
■ 512MB DDR3 RAM
■ 4GB 8-bit eMMC flash storage
■ Manejo Integrado de alimentación.
■ 2×32-bit 200-MHz unidades programables de tiempo real (programmable real-time units, PRUs)
■ Acelerador NEON de punto-flotante.
■ ARM Cortex-M3
■ USB 2 cliente con alimentación y comunicaciones, USB 2 host
■ Programado con Debian Linux

Connectividad y sensores

■ Soporte para batería LiPo de 2 celdas con carga balanceada y monitor LED del estado de carga
■ Entrada del cargador: 9-18 V
■ Conexión inalámbrica: wifi IEEE 802.11bgn, Bluetooth 4.1 y BLE
■ Control de Motores: 8 salidas para servo 6V, 4 salidas puente-H para motores CC, 4 entradas para encoder de cuadratura
■ Sensores: IMU MPU9250 de 9 ejes (acelerómetros, giroscopios, magnetómetro), BMP280 barómetro y termómetro
■ Interfaz de usuario: 11 LEDs programables por el usuario, 2 botones programables por el usuario
■ Interfaces con conectores JST para agregar buses y periféricos adicionales: GPS, radio DSM2, UARTs, SPI, I2C, 1,8V analog, GPIOs 3,3V

Compatibilidad de Software

ROS (Robot Operating System)
ArduPilot
MATLAB – Simulink
LabVIEW
Cloud9 IDE en Node.js
Python
OpenCV
Copter
■ Y aún más…

Especial para utilizarlo en drones y en robots navegadores autónomos.

Página de BeagleBone
Literatura de respaldo



Diseños de bases y accesorios para robots con impresora 3D

Soporte de motores, por zi3d
https://www.thingiverse.com/thing:750963
Enlaces para archivos de impresión
https://www.thingiverse.com/thing:750963/zip

Este soporte permite fijar los motores estándar de los kits más comunes con más firmeza, sin fijaciones que se rompen con facilidad, y sobre cualquier placa base del material que usted desee, sin necesidad de comprar las cortadas con láser.






DotBot por Dotbot-io
https://www.thingiverse.com/thing:1441937
Enlaces para archivos de impresión
https://www.thingiverse.com/thing:1441937/zip






Chassis para robot por metshein
https://www.thingiverse.com/thing:1011890
Enlaces para archivos de impresión
https://www.thingiverse.com/thing:1011890/zip






Chassis compacto por makerhacks
https://www.thingiverse.com/thing:2320298
Enlaces para los archivos (distintos modelos)
https://www.thingiverse.com/thing:2320298/zip


Montaje para motor con tacómetro por b2vn
https://www.thingiverse.com/thing:1473508
Archivos para impresión 3D
https://www.thingiverse.com/thing:1473508/zip


Montaje para motor, ruedas y orugas por edwardchew
https://www.thingiverse.com/thing:3228395
https://www.thingiverse.com/thing:3228359
Descargar todos los archivos para chassis y ruedas https://www.thingiverse.com/thing:3228395/zip
Descargar todos los archivos para orugas https://www.thingiverse.com/thing:3228359/zip






Chassis para robot por Malathar
https://www.thingiverse.com/thing:1316755
Enlaces de los archivos para impresión 3D
https://www.thingiverse.com/thing:1316755/zip


Seguidor de línea JJ1 por AndrewLinden
https://www.thingiverse.com/thing:2831729
Enlace para los archivos de impresión 3D
https://www.thingiverse.com/thing:2831729/zip

Es un chasis de robot para construir un robot seguidor de línea utilizando los motores amarillos de engranajes y un Arduino.

En lugar de los tres módulos de sensor de línea, también puede usar un conjunto de sensores de 8 canales.

El chasis tiene agujeros para esta placa de sensores también. Esta matriz tiene salida analógica y necesitas un Arduino Nano que posee pines adicionales A6 y A7 usar los 8 canales del sensor, que tiene salida analógica. También puede optar por agregar al Arduino uno un CD74HC4067, multiplexador de 16 canales.

Cuando use paquetes de batería LiPo sin protección, también debe usar un sensor de bateria Lipo con beeper como el de la imagen que sigue, o una protección similar.

Utilice un tornillo de cabeza redonda en uno de los orificios frontales. La parte frontal del robot se deslizará sobre ese tornillo.


Por supuesto, se pueden encontrar varios diseños más en el repositorio de diseños 3D https://www.thingiverse.com/



EasyDriver – Controladora de motor paso a paso con modos de micropaso

La EasyDriver nos da la capacidad de manejar motores paso a paso bipolares con consumos entre 150 mA a 700 mA por fase. Permite el control motores bipolares con mucha facilidad de programación en modo estándar de paso directo, y en modos de micropaso de 1/2, 1/4 y 1/8 de paso.

Con respecto a cuestiones de hardware, se pueden soldar cables directamente al EasyDriver, o utilizar conectores en la alimentación, motores y señales de control para poder realizar cableados de prueba. La mejor opción para usted dependerá de su aplicación.

Lecturas sugeridas

Si usted no está familiarizado con los siguientes conceptos, se recomienda revisarlos antes de empezar a trabajar con la EasyDriver.

Instalar el entorno de desarrollo integrado de Arduino (IDE)
Motores paso a paso
Video motor paso a paso

Descripción general del hardware

La placa EasyDriver fue diseñada por Brian Schmalz, y su núcleo principal es el circuito integrado A3967. Este integrado permite manejar motores paso a paso bipolares con configuraciones de 4, 6 u 8 cables. La placa puede trabajar controlado desde sistemas de 3,3 V o 5V, por lo que es extremadamente versátil. Dos agujeros de montaje en la placa le dan al usuario la opción de sostener la EasyDriver con tornillos o postes de sujeción.

Descripción de las entradas y salidas de la placa

Vamos a echar un vistazo a todos los pines perforados que conectan hacia el exterior el circuito integrado A3967 en la EasyDriver.

Conexiones de la parte superior de la placa

Si se observa a lo largo de la parte superior de la placa, podrá ver varias perforaciones de conexión.

Funcionan de la siguiente manera:

Coil A+ : Salida del puente-H, polo + de la conexión para la bobina A del motor bipolar.
Coil A- : Salida del puente-H, polo – de la conexión para la bobina A del motor bipolar.
Coil B+ : Salida del puente-H, polo + de la conexión para la bobina B del motor bipolar.
Coil B- : Salida del puente-H, polo – de la conexión para la bobina B del motor bipolar.
PFD : Voltaje de entrada que selecciona el modo de descenso de la corriente de la salida. Si PFD > 0,6 Vcc, activa el modo de descenso de corriente lento. Si PFD < 0,21 Vcc, activa el modo de descenso rápido. Si el valor está en 0,21 Vcc < PFD < 0,6 Vcc se produce un descenso intermedio de la corriente. RST : Entrada lógica. Cuando está en BAJO, todos los comandos son ignorados y todos los transistores de salida se desactivan. Debe ser puesto en ALTO para habilitar el control de los pasos.
ENABLE : Entrada lógica. Permite que funcionen los transistores de salida dentro del puente H que maneja el motor. Si se pone en ALTO, desactiva los transistores, y el chip no manejará el motor. Si se pone en BAJO, los transistores de salida son habilitados, lo que permite el control del motor.
MS2 : Entrada Lógica. Ver tabla de verdad de abajo para los ALTOS y BAJOS que definen la funcionalidad.
GND : Tierra.
M+ : Fuente de alimentación. 6-30V, corriente 2A.

Conexiones de la parte inferior de la placa

También hay conexiones en la parte inferior de la placa. Sus funciones son:

GND : Tierra.
5V : Salida. Este pin puede ser utilizado para alimentar un circuito externo. Se pueden utilizar como máximo 70 mA para asegurar la funcionalidad del controlador.
SLP : Entrada lógica. Cuando pone a BAJO, las salidas están desactivadas y el consumo de energía se reduce al mínimo.
MS1 : Entrada lógica. Ver tabla de verdad de abajo para los ALTOS y BAJOS que definen la funcionalidad.
GND : Tierra.
STEP : Entrada lógica. Cualquier transición en este pin de BAJO a ALTO activa el motor para que avance un paso. La dirección y la extensión de los pasos se controla por la configuración de los pines DIR y MSx. Esta podrá ser de 0 a 5 V, o de 0 a 3 V en base al nivel lógico que se ha seleccionado.
DIR : Entrada lógica. Esta línea determina la dirección de rotación del motor. Los cambios en el estado de ALTO a BAJO, o BAJO a ALTO solo tienen efecto en el siguiente flanco de subida de la línea de comando STEP. Esta podrá ser de 0 a 5 V, o de 0 a 3 V en base al nivel lógico que se ha seleccionado.

Puentes de soldadura

Hay dos conjuntos de puntos de soldadura para soldar puentes de configuración en la placa. Estos proporcionan las siguientes elecciones para el usuario:

3/5 V – Este puente permite que el usuario defina la configuración de VCC entre 3,3 V o 5 V. Con el puente abierto, VCC será de 5 V. Si el puente está cerrado, VCC es de 3,3 V. El valor de VCC define los niveles lógicos que aceptará la placa en sus entradas.

APWR – Este puente habilita que la fuente VCC entregue + y GND en los pines de alimentación de hardware externo.

Potenciómetro de ajuste de corriente

El potenciómetro que se incluye en la placa permite que los usuarios puedan ajustar la corriente máxima que se suministra al motor. El rango de ajuste va de 150 mA a 750 mA. Esto requerirá saber qué valores de corriente puede manejar su motor. Revise la hoja de datos del motor para una calibración correcta.

Si usted no puede encontrar esta información, no se preocupe: todavía puede encontrar el ajuste adecuado de este potenciómetro. En primer lugar, establezca el potenciómetro en su valor mínimo. Tenga en cuenta que el potenciómetro es delicado, así que no fuerce el potenciómetro más allá de los topes mecánicos que lo detienen en ambos extremos de su giro. Aumente lentamente la corriente observando el movimiento del motor. Una vez que el motor se mueva a una velocidad lenta pero constante, gire poco a poco el potenciómetro y preste atención al comportamiento del motor. Usted debe encontrar un punto justo en el que el motor no salte o se observen tirones entre los pasos.

Conectar los cables de las bobinas del motor

Usted tendrá que determinar cuáles son los pares de cables de cada bobina del motor que va a utilizar. El método más fiable para hacerlo es observar la hoja de datos del motor, donde indicará los colores de los cables o la posición de los puntos de conexión.

Diagrama de bobinas de un motor paso a paso NEMA 16 con cables


Sin embargo, si usted va a utilizar cualquier otro motor paso a paso de 4 o 6 cables, es posible determinar los pares correctos de cables de cada bobina a conectar sin tener la hoja de datos.

Determinación de los cables de un motor paso a paso

En un motor de 4 cables, tome uno de los cables y compruebe con un multímetro su resistencia contra cada uno de los tres cables restantes. Aquel cable que muestre el menor valor de resistencia contra el primer cable es el que está apareado con él. Los otros dos cables deben mostrar resistencia similar entre ellos.

Para un motor de 6 cables, usted tendrá que determinar cuáles son los tres cables que están unidos a una bobina. Escoja un cable y pruebe su valor de resistencia contra todos los otros cables. Dos de los cables deben mostrar algún valor de resistencia entre ellos y el primer cable escogido, mientras que los otros tres no mostrarán conexión en absoluto. Una vez que se han determinado cuáles son los tres cables de una bobina, busque a dos entre estos tres que muestren la mayor resistencia entre sí. Estos serán los cables a usar de esta bobina. Repita el procedimiento para el segundo grupo de tres cables.




Una vez que haya determinado los pares de cables de la bobina, debe unirlos a la placa EasyDriver. El par de cables de la primera bobina debe ser conectado a la conexión Coil A+ y el otro a Coil A-. El par de cables de la segunda bobina se conecta a Coil B+ y a Coil B-. Las bobinas no tienen polaridad, así que usted no debe preocuparse de conectar una bobina al revés en la placa. En nuestro ejemplo, estamos usando un motor de 4 cables. Las conexiones entre la EasyDriver y el motor son como sigue.

Conexión EasyDriver al motor (Nema 14, 16 o similar)

Conecte una fuente de alimentación

Una vez que el motor está cableado, puede conectar una fuente de alimentación para la EasyDriver. Se puede utilizar cualquier tipo de fuente de alimentación (de escritorio, adaptador de pared, una batería, etc.), pero compruebe que cualquiera sea la opción que se utilice debe ser capaz de entregar hasta 2 A y estar en el rango de 6 V a 30 V.

Conecte la fuente de alimentación a M+ y GND. Recuerde desconectar la alimentación antes de conectar o desconectar el motor.

Conectar a un microcontrolador

Necesitaremos:

Cables

Arduino UNO R3

Conectores

Motor paso a paso bipolar con corriente de bobina hasta un máximo de 700 mA

Para este ejemplo, vamos a utilizar un Arduino UNO. Sin embargo, cualquier microcontrolador que funcione con una lógica de 3,3 V o 5 V, y que posea entradas / salidas digitales con capacidad de trabajar en modo PWM sirve para utilizar con este ejemplo de circuito.

Aquí están las conexiones para nuestro ejemplo:

Circuito final

Una vez que está todo conectado, el circuito debe tener el siguiente aspecto:

Ejemplo de código básico para el Arduino

Ahora que usted tiene el hardware conectado y listo para funcionar, es el momento de obtener el código y cargarlo. En primer lugar, descargue el programa de ejemplo.

DESCARGAR EL PROGRAMA DE DEMOSTRACIÓN DE LA PLACA EASYDRIVER
DESCARGAR PROGRAMA COMPLETO CON COMENTARIOS Y NOMBRES EN ESPAÑOL

Para obtener el código más actualizado que esté disponible, se puede consultar el repositorio de GitHub. Si usted necesita un recordatorio en cuanto a cómo se instala una biblioteca en el IDE de Arduino, por favor vea este tutorial aquí.

La primera sección del programa define todas las conexiones entre el Arduino y la EasyDriver. También establece estos pines como salidas, y los pone a los niveles lógicos adecuados para comenzar a manejar el motor.

Una cosa que debemos señalar es que el código también inicializa la conexión serie a 9600 bps. Esto permite que el usuario dé las indicaciones para controlar la funcionalidad del motor y depurar las conexiones, si es necesario.

El bucle principal del código es bastante simple. Arduino comprueba el puerto serie para ver si hay una orden ingresada por el usuario. Cuando lo recibe, compara con las cuatro posibles funciones para el motor, que inicia su funcionamiento cuando llega la entrada del usuario. Si se escribe una entrada que no sea una de las opciones posibles, Arduino imprime una indicación de error en el puerto serie.

Después de que la solicitud de una función se ha completado, la EasyDriver se restablece a los valores predeterminados.

La primera de las cuatro funciones que se habilita en este programa de demostración es un ejemplo básico que muestra el motor girando en un sentido. El pin de dirección (DIR) se coloca en BAJO (LOW), que para nuestro programa se define como la dirección «Adelante». A continuación, pone el pin STEP a ALTO (HIGH), hace una pausa y, a continuación, lo coloca en BAJO.

Recuerde: el motor da pasos cuando hay transiciones en el pin STEP de BAJO a ALTO, por lo que hay que cambiar el estado del pin una y otra vez. Esto se repite 1000 veces y, a continuación, Arduino solicita una entrada de usuario para determinar la siguiente actividad del motor.

La función de giro inverso funciona exactamente de la misma forma que la anterior, la única diferencia es que en lugar de poner el pin de dirección a BAJO, lo establecemos en ALTO, por lo tanto cambiará la dirección de giro del motor.

Una cosa que usted puede probar en cualquiera de estas dos funciones es modificar la velocidad del motor al cambiar el valor pasado a delay(). Está establecido en 1 microsegundo, haciendo que el pulso para cada paso sea de 2 microsegundos. El aumento de la demora reduce la velocidad del motor, mientras que al disminuir el retardo aumenta la velocidad del motor.

La tercera función demuestra las diferentes opciones de micropasos (microstepping) que proporciona la EasyDriver. Para habilitar el motor paso a paso a 1/8 de paso, debemos establecer MS1 y MS2 en ALTO. Esto establece la lógica de la placa al modo de 1/8 de paso.

Si usted quiere probar el motor paso a paso con diferentes modos de paso, cambie la configuración de uno de los pines MS#. Compruebe la tabla en la sección de Descripción de Hardware, si usted necesita recordar qué modo se habilita al configurar los diversos estados de las entradas.

La última función de movimiento disponible muestra cómo el motor puede cambiar de dirección en un instante. La función trabaja como en el avance y retroceso de las funciones anteriores, pero cambia entre los estados con rapidez. Este ejemplo de prueba del motor paso a paso le hace dar 1000 pasos hacia adelante y, a continuación, invertir 1000 pasos. Esto permite, precisamente, mover algo con el motor en una dirección, y volver exactamente a la posición inicial.

El control preciso de posición es una gran ventaja de los motores paso a paso.

Una vez que la acción concluye, los pines de entrada se deben volver a establecer en el estado predeterminado para evitar comportamientos inesperados del motor, o no deseados. Hacemos uso de la función resetEDPins() para lograr esto.

Programa completo

Ejemplos adicionales

Además el ejemplo presentado aquí, también se puede instalar la biblioteca AccelStepper. Hay algunos ejemplos adicionales en esta biblioteca que pueden ser beneficiosos para utilizar con su EasyDriver. Descargue e instale la biblioteca en su carpeta de bibliotecas Arduino.

Usted también puede encontrar algunos ejemplos adicionales sobre la EasyDriver en la página aquí.

Recursos Adicionales

Eche un vistazo a estos recursos adicionales para obtener más información y otras ideas para sus proyectos.

Página de Schmalz Haus sobre el Easy Driver
Repositorio de GitHub
Hoja de datos del integrado A3967