Configuración de las comunicaciones serie entre Arduino y Python

publicado en: Portada | 8

Usar un puerto USB como puerto serie TTL

Es infrecuente encontrar en un ordenador de escritorio moderno puertos serie y de existir tampoco podrían usarse directamente con Arduino, ya que trabaja con niveles TTL, por lo que habría que adaptar los que provee el puerto serie EIA232 o RS232, el más usado en un ordenador personal.

Los puertos USB sí que están muy presentes en los ordenadores modernos y la mayoría de las placas Arduino disponen de un conector USB que se usa como un puerto serie (coloquialmente llamado TTL por los niveles de voltaje comentados arriba) Este puerto serie, desde un punto de vista funcional, está clonado en un par de pines de la placa (TX/RX) Además, algunas placas como Arduino Mega, o Arduino Due, disponen de más puertos serie UART aparte del correspondiente al conector USB.

Para conectar con el puerto USB del ordenador podrá usarse directamente el conector USB de la placa Arduino o un conversor TTL en el ordenador, que conectará a los pines TX/RX de la placa Arduino, como alguno de los de la imagen de abajo.

Conversores USB serie TTL para comunicaciones serie Python-Arduino

Encontrar el puerto serie en uso

Para poder acceder a un puerto serie del ordenador desde Python es necesario conocer el identificador que corresponde al que conecta con Arduino.

La librería pySerial incluye algunas utilidades que simplifican el trabajo con los puertos serie. Una de ellas muestra una lista de los puertos que hay disponibles en el ordenador; para lanzar esta utilidad y ver la lista de puertos se utiliza la orden python -m serial.tools.list_ports desde la consola.

Linux Guadalinex python -m serial.tools.list_ports
Buscando dispositivos serie con python -m serial.tools.list_ports en Linux (Guadalinex v9)
Windows Python -m serial.tools.list_ports
Lista de puertos serie con python -m serial.tools.list_ports en Windows
Apple Mac OS X Python -m serial.tools.list_ports recortado
Buscar dispositivos serie con python -m serial.tools.list_ports en OS X

Como puede verse en los anteriores listados, si existen varios puertos serie, el problema puede ser identificar cada uno de ellos. De darse el caso, dependiendo de la plataforma, hay algunas técnicas que pueden ser de ayuda.

En el caso de Linux hay varios recursos. Por ejemplo, se puede conectar el adaptador USB a serie TTL y consultar los mensajes con dmesg para buscar el dispositivo por su nombre o ver qué se ha conectado en último lugar. En la siguiente se muestra un ejemplo de cómo localizar una placa Arduino Leonardo con la información proporcionada por dmesg sobre el puerto USB-serie al que se conecta, ttyACM0, en el ejemplo.

dmesg señalando el puerto USB de Arduino Leonardo

En el caso de Windows, se puede explorar, en el administrador de dispositivos, la lista de puertos COM y LPT mostrará el nombre del dispositivo (la placa Arduino Leonardo del ejemplo) y el nombre del puerto al que se conecta (COM3, en este caso)

Windows administrador de dispositivos puerto serie COM Arduino Leonardo

En el caso del sistema operativo OS X, lo más sencillo es usar la orden ls /dev/tty.* desde la consola (shell) y tratar de reconocer el dispositivo USB buscado, tty.usbmodem7d11 en el ejemplo de abajo.

Apple Mac OS X ls dev tty

Configurar el puerto serie en Python

La librería pySerial permite acceder a un puerto serie por su nombre o por su número. La segunda forma es independiente de la plataforma: en todos los sistemas operativos el primer puerto serie será el 0, el segundo el 1, el tercero el 2… pero, como se ha visto en los apartados anteriores, en Linux puede llamarse /dev/ttyUSB0, en Windows COM1 y en OS X algo como /dev/tty.usbmodem7d22, por lo que para realizar una aplicación multiplataforma, en la que se deba elegir el puerto a cada uso, habrá de contar con esas diferencias.

Según se describe en la documentación de la API de la librería PySerial, para configurar el puerto serie se puede elegir entre hacerlo al crearlo pasando directamente los datos de configuración o crearlo y configurarlo más adelante.

Si se configura directamente al crearlo no será necesario usar la función open() para abrirlo antes de empezar a enviar o recibir datos por el puerto serie recién asignado.

El constructor de la clase espera los siguientes parámetros opcionales.

  • port Nombre o número de puerto al que se conecta.
  • baudrate Velocidad expresada en baudios.
  • bytesize Número de nits de datos. Pueden usarse las constantes FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS para referirse a 5, 6, 7, u 8 bits respectivamente.
  • parity Tipo de control de paridad. Se pueden usar las constantes PARITY_NONE (sin paridad), PARITY_EVEN (par), PARITY_ODD (impar), PARITY_MARK (marca) y PARITY_SPACE (espacio)
  • stopbits Número de bits de parada. Están disponibles las constantes STOPBITS_ONE (u bit de parada), STOPBITS_ONE_POINT_FIVE (un bit y medio) y STOPBITS_TWO (dos bits)
  • timeout Tiempo de espera de lectura antes de lanzar una excepción si no se reciben datos.
  • xonxoff Activar el control de flujo por software.
  • rtscts Activar el control de flujo por hardware DSR/DTR.
  • dsrdtr Activar el control de flujo por hardware DSR/DTR.
  • writeTimeout Tiempo de espera entre escritura.
  • interCharTimeout Tiempo de espera entre carácteres.

Si el objeto para acceder a las comunicaciones serie se crea con algo como puerto=serial.Serial() es decir, sin parámetros de configuración, posteriormente se podrá configurar asignándole la configuración a la instancia que se ha creado. Para asignar el número de puerto se usa puerto.port=0, para asignar la velocidad (en baudios) algo como puerto.baudrate=9600, puerto.timeout=2 para el tiempo de espera y así sucesivamente.

La configuración por defecto corresponde a una velocidad de 9600 baudios, 8 bits de datos, sin paridad y con un bit de parada (algo, por cierto, bastante común) que suele expresarse como 9600,8,N,1 o 9600_8N1

Si se cambia el valor de port la conexión se asocia a ese puerto de comunicaciones serie de forma que, si estubiera abierta se cierra y se vuelve a establecer con el nuevo valor.

En el siguiente código de ejemplo en Python se han resaltado las dos líneas (2 y 3) que establecen el puerto serie y directamente su configuración.

Configurar el puerto serie en Arduino

En la parte de Arduino también habrá que elegir el puerto serie con el que se trabaja, si es que hay varios disponibles; en este caso es más sencillo ya que existe un objeto Serial para cada uno de los disponibles. En una placa Arduino Uno, por ejemplo, sólo existe el objeto Serial (aunque siempre pueden inplementarse por software comunicaciones serie usando GPIO) mientras que en una placa Arduino Mega puede usarse tanto el objeto Serial (que corresponde con el puerto USB) como Serial1, Serial2 y Serial3 a los que se accedes por los pines correspondientes del a placa.

Para configurar el puerto serie en Arduino basta con llamar a la función begin() del objeto Serial que se vaya a utilizar, indicando la velocidad en baudios y una palabra de configuración que indica los bits de datos, la paridad y los bits de parada en el formato SERIAL_ABC siendo fijo el texto «SERIAL_» y correspondiendo A al número de bits de datos, B a la paridad (que puede ser N, E u O para referirse a sin paridad, par o impar respectivamente) y C a los bits de parada. La configuración más habitual es SERIAL_8N1 (8 bits de datos sin paridad y un bit de parada y es la que se usará si se omite este parámetro.

Como es parte de la configuración, la llamada a begin() para inicializar las comunicaciones suele incluirse en la función setup() del programa para Arduino, por ejemplo de esta forma.

Víctor Ventura

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

Más entradas - Página web

Sígueme:
TwitterLinkedIn

Seguir Víctor Ventura:

Programador multimedia y web + IoT. Mejor con software libre.

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

8 Respuestas

  1. Jean Carlo

    Buenas, gracias por la informacion amigo.

    Una consulta, no sabes como se puede, desde linux, colocarle un mismo /dev/ttyUSB0 al mismo arduino.

    Por ejemplo, en el caso que tenga 3 arduinos diferentes, crear una regla para que le asigne siempre el mismo puerto a «x» arduino…
    Asi que si conecto los arduinos , sin importar el orden , sabre cual puerto utiliza cada uno.

    Es un problema para mi ahorita, porque debo verificarlo siempre, y para un programa desde python debo colocar el puerto en el programa si este se modifico.

    En este link sale algo de lo que necesito, pero no me logra funcionar , agradezco si sabes algo al respecto,
    http://hintshop.ludvig.co.nz/show/persistent-names-usb-serial-devices/

    Saludos,

    • Víctor Ventura

      Hola, Jean Carlo.

      ¡Qué interesante pregunta! En el enlace que indicas explica bien cómo hacerlo (o por lo menos yo también lo hago así)
      He escrito una entrada en la que detallo cómo asignar un nombre fijo al puerto serie de una placa Arduino. Creo que puede servirte, en cualquier caso, lo resumo a continuación.

      Asignar un nombre fijo al puerto serie de un dispositivo.

      1. Identificar cada placa Arduino.

        • Si la acabas de conectar, lo más sencillo es dmesg y leer al final, allí está todo lo que necesitas para este caso: vendedor, producto y número de serie.
        • Si sabes en qué punto de la estructura /dev está conectada puedes ir al grano y localizar los datos con udevadm info -a -n /dev/ttyACM0 (siendo ttyACM0 el puerto serie/USB de la placa Arduino, que también puede tener el aspecto ttyUSB0 o lo que corresponda)
          Como va a mostrar mucha información, puedes discriminarla con udevadm info -a -n /dev/ttyACM0 | grep ‘ATTRS{serial}’ para el número de serie, con udevadm info -a -n /dev/ttyACM0 | grep ‘ATTRS{idProduct}’ para el identificador del producto…
      2. Crear un documento con las reglas en la carpeta correspondiente de tu sistema (en mi escritorio Debian es /etc/udev/rules.d) por ejemplo con sudo nano /etc/udev/rules.d/arduinas.rules
      3. Añadir tantas reglas (cada una en una línea) como placas Arduino quieras identificar. Suponiendo que a mi placa Arduino con número de serie 666666 le quiero dar el nombre Pilar y a mi placa Arduino con número de serie 999999 le quiero dar el nombre Carmela, las líneas que añadiría serían:

        • SUBSYSTEM==»usb», ATTRS{idVendor}==»1234″, ATTRS{idProduct}==»4567″, ATTRS{serial}==»999999″, SYMLINK+=»carmela», GROUP=»dialout»
        • SUBSYSTEM==»usb», ATTRS{idVendor}==»1234″, ATTRS{idProduct}==»4567″, ATTRS{serial}==»666666″, SYMLINK+=»pilar», GROUP=»dialout»

        Suponiendo, claro, que el identificador del vendedor de la placa es 1234 y el identificador del producto es 4567 (esto puedes verlo, como te decía, con dmesg, con lsusb, udevadm…)
        Como es lógico, debes cambiar el grupo dialout por el que sea que tenga los permisos correspondientes y al que tu usuario pertenezca.
        La «magia» consiste en que crea un enlace «carmela» o «pilar» dentro de /dev al puerto real correspondiente (por ejemplo /dev/ttyACM14) del que ya no te tienes que preocupar.

      4. Para que los nombres estén disponibles la próxima vez que conectes las placas, debes recargar las reglas conforme a tu sistema. En mi escritorio Debian lo hago con sudo /etc/init.d/udev restart No sé tu caso, a lo mejor con sudo udevadm control –reload-rules ya las reconoce o puede que las tengas que activar con sudo udevadm trigger

      Espero haberte ayudado.
      ¡Muchas gracias por tu aportación. Sigue visitando nuestro blog. Te esperamos pronto!

  2. Bruno

    Victor que interesante articulo, la pregunta siguiente, trate de hacer un prorama en python manejando el pyserial pero me da el siguiente error, y la verdad no se a que se deba.
    >>> import serial

    Traceback (most recent call last):
    File «», line 1, in
    import serial
    File «serial.py», line 6
    SyntaxError: Non-ASCII character ‘\xf3’ in file serial.py on line 6, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
    >>>

    Alguna vez te paso esto y si es asi como le diste solución.
    Gracias
    Bruno

    • Víctor Ventura

      Hola, Bruno.

      El error que dices no me sale pero, eso de que diga «Non-ASCII» me suena a un conflicto entre codificaciones ¿Usas UTF-8? ¿Al principio del documento tiene la línea # coding: utf-8 (o la línea # -*- coding: utf_8 -*-)? Puede que ese sea el problema.

      Espero que te ayude. Por favor, cuéntanos si eso lo resuelve o qué solución le das finalmente. Gracias.

  3. Daniel

    Buenas Victor, gracias por la información.
    Una consulta, si conectas varios arduinos a una raspberry usando python, es posible recibir los dats sin que se pisen y solo que haga caso al primer arduino conectado? My idea es conectar un segundo arduino y que el python ya lo reconozca sin tocar el codigo. Coloque en un array los nombres del arduino, pero solo recibo datos del primero que estaba conectado, y del segundo no, hasta que desconecte el primero.

  4. VICTOR HUGO MIRANDA TRUJILLO

    Hola Víctor,
    Una pregunta lo que pasa es que estoy creando un sensor de movimiento conectado a un arduino y que de ahí pase al programa de pynthon para bajar la información a mi base de datos con toda la información de cuando tuvo su primer movimiento y cuanto duro encendido en la base de datos.
    Es que el sensor de movimiento debe encender una luz cada ves que presenta algún movimiento y que toda la información se guarde en una base de datos utilizando pynthon.

Deja un comentario

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