Lectura de datos serie en tiempo real en Python


Estoy usando un script en Python para recopilar datos de un microcontrolador PIC a través de un puerto serie a 2Mbps.

El PIC funciona con sincronización perfecta a 2Mbps, también el puerto serie usb FTDI funciona muy bien a 2Mbps (ambos verificados con osciloscopio)

Estoy enviando mensajes (tamaño de unos 15 caracteres) alrededor de 100-150 veces por segundo y el número allí aumenta (para comprobar si tengo mensajes que se pierden y así sucesivamente)

En mi portátil tengo Xubuntu corriendo como máquina virtual, puedo leer el puerto serie a través de Putty y a través de mi script (python 2.7 y pySerial)

El problema:

  • Al abrir el puerto serie a través de Putty veo todos los mensajes (el contador en el mensaje aumenta 1 por 1). ¡Perfecto!
  • Al abrir el puerto serie a través de pySerial, veo todos los mensajes, pero en lugar de recibir 100-150x por segundo, los recibo a aproximadamente 5 por segundo (aún así, el mensaje aumenta 1 por 1), pero probablemente se almacenan en algún búfer, ya que cuando apago la foto, puedo ir a la cocina y volver y todavía estoy recibiendo mensajes.

Aquí está el código (omití la mayor parte del código, pero el bucle es el mismo):

ser = serial.Serial('/dev/ttyUSB0', 2000000, timeout=2, xonxoff=False, rtscts=False, dsrdtr=False) #Tried with and without the last 3 parameters, and also at 1Mbps, same happens.
ser.flushInput()
ser.flushOutput()
While True:
  data_raw = ser.readline()
  print(data_raw)

¿Alguien sabe por qué pySerial tarda tanto tiempo en leer desde el puerto serie hasta el final de la línea? Alguna ayuda?

Quiero tener esto en tiempo real.

Gracias

Author: Vasco Baptista, 2013-11-11

3 answers

Puede usar inWaiting() para obtener la cantidad de bytes disponibles en la cola de entrada.

Entonces puedes usar read() para leer los bytes, algo así:

While True:
    bytesToRead = ser.inWaiting()
    ser.read(bytesToRead)

¿Por qué no usar readline() en este caso de Docs:

Read a line which is terminated with end-of-line (eol) character (\n by default) or until timeout.

Está esperando el tiempo de espera en cada lectura, ya que espera eol. la entrada de serie Q sigue siendo la misma, solo un montón de tiempo para llegar al "final" del búfer, Para entenderlo mejor: está escribiendo a la entrada Q como un coche de carreras, y leyendo como un coche viejo :)

 27
Author: Kobi K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-11 15:07:32

Debe establecer el tiempo de espera en" Ninguno " cuando abra el puerto serie:

ser = serial.Serial(**bco_port**, timeout=None, baudrate=115000, xonxoff=False, rtscts=False, dsrdtr=False) 

Este es un comando de bloqueo, por lo que está esperando hasta recibir datos que tengan una nueva línea (\n o \r\ n) al final: line = ser.readline ()

Una vez que tenga los datos, volverá LO antes posible.

 4
Author: Fabian Meier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-21 10:41:09

De el manual:

Posibles valores para el parámetro timeout: … x establecer el tiempo de espera en x segundos

Y

Readlines (sizehint=None, eol='\n') Lee una lista de líneas, hasta el tiempo de espera. sizehint se ignora y solo está presente para API compatibilidad con objetos de archivo incorporados.

Tenga en cuenta que esta función solo devuelve en un tiempo de espera.

Por lo que su readlines volverá a lo sumo cada 2 segundos. Use read() como Tim sugirió.

 1
Author: msw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-11 14:57:56