Leer el puerto serie de Arduino con Python y PySerial

[singlepic id=20 w=320 h=240 float=right]Desde hace ya un tiempo he hoy buenos comentarios sobre Python y lo “fácil” que es programar con él, su potabilidad entre sistemas, etc. Me he puesto ha ello, y la verdad es que es muy fácil programar con él, después de un rato, se le coge el tranquillo a esa forma tan peculiar de escribir el código que tiene, solo utilizando tabulación, sin puntos y comas, llaves o cualquier otra forma de indicar el inicio y el fin de las lineas,  a la declaración de las variables, mejor dicho a la no declaración, la formar de trabajar con las funciones, etc. En general es un lenguaje muy fácil de trabajar y encima puedes hacer verdaderas locuras con el. Me ha recordado mucho al Basic que aprendí ya hace muchas lunas.

Para empezar, que mejor que trabajar con Arduino. Lo primero que he hecho es leer del puerto serie la información que escribe el Arduino.

Para el Arduino solo le he metido un código muy simple, genera un numero aleatorio, de -100 a 100,  y lo escribe en el puerto serie.

Codigo para Arduino

Y en Python lo que he hecho es aprovechar la librería PySerial que hay para Python para leer el puerto y leer los datos que escribe el Arduino.  Para instalar la librería PySerial es muy fácil, solo tenemos que seguir los pasos que hay en la propia pagina de PySerial.

El código en Python es muy simple, este mismo código en Java, me llevo bastante tiempo pelearme con la librería RxTx, en cambio en Python es tan sencillo como escribir el siguiente código.

Código Pytho

Después de este código tan simple, ya tenemos un programa que nos lee los datos del puerto serie y lo muestra en pantalla. Esto con cualquier otro lenguaje te lleva un buen rato. Esto no me ha llevado mas de media hora de buscar por internet como se programa en Python y como funciona la libreria PySerial.

Que opinas de ello???

35 thoughts on “Leer el puerto serie de Arduino con Python y PySerial”

  1. Buenas noches, me ha interesado mucho tu entrada, he intentado copiarte pero me dice que le puerto que abro no existe, cómo puedo saber que puerto tengo que poner en lugar de:

    (‘/dev/ttyACM0’, 9600)

    ???

    Muchas gracias!!

    1. Depende con que sistema operativo estés utilizando, para linux, el normal es ese, pero puede variar si ese puerto se encuentra ocupado, puedes utilizar variantes de ese como /dev/ttyACMX donde x puede cambiarlo por cualquier numero, tienes un programa hecho en python que escanea todos los puertos que utiliza el arduino, también puede ir a la carpeta de /dev/ y ver que carpeta aparece al conectar el arduino. Para windows hay que cambiar el /dev/ttyACM0 por com1, com2, etc. Para mac es algo como esto “/dev/tty.usbmodem621”, no manejo muchos los mac y no se exactamente que puerto crea.

      1. Ese es el puerto que crea el Raspberry para los puertos serie. Solo cambia el nombre, el funcionamiento es igual que cualquier Linux o Apple.

    2. Si estas en linux tienes que enlazar a ttyS5 o cualquier numero
      puesto que el serial de python solo reconoce puertos del tipo ttyS

  2. Estimado; muchas gracias por la información. Tengo una pregunta, cuando quiero enviar numeros decimales, como debo escribirlos en arduino y recibirlos en python?

    1. Como te de la gana, yo todos los datos los trato como si fueran cadenas. si lo que envió son números después de leer los datos los cambio al formato que necesito. Por ejemplo, paso los siguientes valores de arduino a python, “valor1|valor2|Valor3|fin”. Luego divido la cadena utilizando el separador “|” que he puesto, y paso las cadenas al formato correspondiente. Así no me complico la vida, todo los datos entre arduino y python son cadenas. Estoy terminado un mini proyecto, donde leo unos sensores de temperatura y presión y se los paso a python, en cuanto termine pondré un post sobre ello.

      1. Estoy realizando un proyecto parecido donde envío varios datos desde arduino separados por una coma (,) y con python quiero recibirlos para almacenarlos en una base de datos, pero no sé como debo hacer que sea capaz de distinguir cada dato, es decir, hasta la primera coma valor1, hasta la segunda valor2, hasta la tercera valor3,….. podrías ayudarme?
        ese miniproyecto del que hablabas está ya terminado??me sería de gran ayuda. Gracias.

    1. Me extraña mucho, ya que tengo varios proyectos hechos como base ese código, funcionando sin problemas. Si concretas más podre ver donde me he confundido y solucionarlo.
      Muchas gracias.

  3. que onda amigo, estoy trabajando con raspberry pi (rasbian) es linux basicamente, y con arduberry (shield de arduino uno para raspberry pi) ya he podido leer datos analógicos de un potenciometro y he podido imprimirlos usando python, pero no he podido conseguir que estos se grafiquen en tiempo real, si me puedes echar la mano, es decir cuando yo gire el potenciometro que la grafica cambie. gracias

    1. El verlo en tiempo real dependerá de cuanto tardes en enviar los datos desde el arduino al Raspberry y cuanto tardes en leer los datos, para el tiempo real tendrías que programar un hilo que estuviera constantemente leyendo del puerto. Nunca he trabajado con el shield que dices, no se si el envío al raspberry lo hace el automáticamente o lo tienes que programar, pero aun, sin conocerlo, me decanto por esta ultima opción

  4. Hola, ante todo gracias por compartir.

    Llevo ya varios dias intentando instalar la libreria de pyserial en mi pc con windows 7 y no hay manera, sigo el metodo que sale en la pagina oficial, el que hace:

    python setup.py install

    ya que la manera de hacerlo desde PYPI me es imposible a que tampoco consigo instalar los setutools sin que me de algún error inesperado.

    Agradezco la ayuda un saludo

    1. En Windows no suelo utilizar python, pero por lo que he visto y probado, no hay ningún problema. Para Windows no hace falta hacer la instalación de esa forma, esa forma en mas bien para Linux, existe un versión ejecutable de la instalación, para descargar para Python 2.x desde aqui , y para la versión de Python 3.x desde aquí.
      Tanto una versión como la otra funcionan perfectamente, por lo que he visto tienes que asegurarte de que la ruta al ejecutable del interprete de Python este dentro de las rutas por defecto de Windows (variable del sistema PATH).

      1. Muchas gracias por contestar, hice lo del path de paso, aunque tuve que reinstalar python, luego con lo que me dijiste se soluciono.

        Aunque tengo otro problema algo mas grave, no quiero abusar mucho de tu tiempo, pero estoy haciendo un programa que lee del puerto, y esa información la quiero enviar a raspberry.

        Tengo el programa ya hecho, usando la libreria socket, lo que pasa que al añadir las lineas para usar los puertos el dato que lee del puerto serial de arduino no me varia es siempre el mismo, te dejo el codigo por aqui a ver si tu o alguien me puede decir que le pasa, lo que hace es simple, lee del puerto serial de arduino y lo envia via internet a la raspberry, la comunicacion la he llegado hacer, el problema es que siempre coge el mismo dato del puerto serie.
        Si quito las lineas de codigo que tienen que ver con los socket si me coge bien la salida del arduino.

        # codigo para leer valores del puerto serial de arduino y enviarlos a raspberry
        #funciona como servidor, programa para pc

        import serial
        import socket
        import sys
        import select

        #creamos el codigo que servira de socket servidor:

        UDP_IP = “0.0.0.0” #Recibira informacion de cualquier cliente
        UDP_PORT = 10000 # definimos un puerto por el que se hara la comunicacion
        UDP_HOST = sys.argv[1] #leemos la ip destino del mensaje por linea de comandos
        serversocket = socket.socket(socket.AF_INET, #internet
        socket.SOCK_DGRAM) # se enviaran los paquetes via UDP

        #asociamos las variables definidas anteriormente al socket:
        serversocket.bind((UDP_IP,UDP_PORT))

        #Finalmente escuchamo por el puerto a la espera de un cliente:
        #serversocket.listen(1) #restringimos el numero de clientes a 1(la raspberry)

        #ponemos el socket en no bloqueo
        serversocket.setblocking(0)

        #abrimos el puerto de arduino a 9600 igual que inicializamos en el arduino
        PuertoSerie = serial.Serial(‘COM3’,9600)

        while True:
        #leemos hasta encontrar el final de la linea
        sArduino = PuertoSerie.readline()
        print “sArduino: ” + sArduino.rstrip(‘\n’)

        if sArduino:
        dato = sArduino.rstrip(‘\n’)
        print “Mensaje que se enviara: ” + dato
        #enviamos el dato:
        serversocket.sendto(dato,(UDP_HOST,UDP_PORT))
        #valida si hay algo en el socket
        hay_dato = select.select([serversocket],[],[],0.5)

        if hay_dato[0]:
        tam_socket = serversocket.recv(1024) #definimos el tamaño del buffer de red
        #en este paso la raspberry enviaria los datos por serial a arduino
        sArduino = []
        hay_dato = []

        Muchisimas gracias por todo, y por la posible ayuda

  5. Amigo no soy un experto en programacion pero he estado mirando un poco de python y probando pyserial. Tengo un problema y presumo algo se me escapa. Al colocar tu codigo y enviar datos mediante el puerto serial nunca me imprime en la consola lo que le envio. Asi lo haga con el final de linea \n. Estoy utilizando un simulador llamado TERMINAL V1.93b. En el caso de utilizar read si puedo leer byte por byte. Pero en readline no he logrado imprimir en la consola la linea que envio. Espero tu ayuda y gracias

    1. No entiendo muy bien tu pregunta, ya que no comentas ni sistema utilizado ni lo que están intentando realizar, pero intentare responder hasta donde te he entendido. Los datos leídos no se muestras en ningún sitio ya que los datos los lees y se almacena en una variable. No entiendo lo de utilizar el “Terminal” lo estas utilizando para enviar los datos en vez de hacerlo desde un Arduino?. Si es así, como manda el programa de terminal los datos?, la mayoría de estos programas los hacen byte a byte, que es por que te funciona en el modo de lectura read. YA que con readline esta esperado un final de linea que jamas llegara, ya que si envías “/n” son dos caracteres por un lado la barra y por otro la n. Y hasta aquí es lo que he entendido.

  6. Disculpa,
    Quisiera usar esta lectura en una interfaz pero el ciclo infinito no me deja ejecutar la ventana …
    alguien sabe como sustituir el ciclo infinito por alguna funcion que solo lea los datos cuando los recibe y no cicle el programa?
    les dejo lo que tengo del programa
    import sys
    import serial
    import time
    from PyQt4 import QtGui

    ser = serial.Serial(‘/dev/ttyACM0’, 9600)
    time.sleep(.2)

    app = QtGui.QApplication(sys.argv)
    ventana = QtGui.QWidget()

    while True:
    data = ser.readline()
    print (data)

    ventana.show()
    sys.exit(app.exec_())

  7. si buscaba algo como eso, muchas gracias, tengo poco estudiando python y desconozco muchas librerias, trato de graficar las señales para una interfaz de control supervisorio con arduino si me pudieras dar una idea de que librerias puedo usar te lo agradeceria

  8. Se muy poco de python, quisera preguntar si el puerto esta disponible, es decir, que solo muestre cuando le llega info al puerto.

    Gracias,

    1. En sistemas Linux, el puerto se crea cuando conectamos el arduino al ordenador, luego tendremos que estar constantemente mirando si hay datos en el, no tenemos ningún evento, como podríamos tener en Visual C#, que nos salte cuando hay datos disponibles en el. Lo mejor para esto, es poner una función en un hilo a parte del principal y provocar nosotros mismo la notificación.

Deja un comentario

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