4 votos

Python de serie entre Arduino y Raspberry Pi: Los datos se modifican al recibirlos

Estoy usando un Arduino para las lecturas de los sensores y enviándolas a una Raspberry Pi vía USB, usando PySerial para la recepción de datos.

Funciona muy bien, excepto por el hecho de que los datos recibidos se modifican torpemente (y se establecen como constantes). Por ejemplo, estoy leyendo voltajes y calculando corrientes. Los resultados en la serie Arduino son los siguientes:

Volt   Current
4.93   0.38
4.92   0.37
4.92   0.37
4.92   0.36
...    ...

Sin embargo, en la Raspberry Pi, se lee constantemente de la siguiente manera (Observe cómo los dígitos se cambian a cero):

  Volt   Current
    4.99   0.30
    4.99   0.30
    4.99   0.30
    4.99   0.30
    ...    ...

He intentado varias vueltas, pero sin suerte. No estoy seguro de dónde está el problema, ya que estoy muy seguro de que mi código es impecable. Incluso he convertido las lecturas a cadena antes de enviarlas y, sin embargo, siguen apareciendo las lecturas constantes y los dígitos a cero. He añadido un contador de enteros que se ha enviado correctamente sin problemas.

¿Alguien ha probado esto antes? ¿Alguna idea sobre cómo solucionarlo?

Código Raspberry Pi:

from time import gmtime, strftime
import time
import serial
import struct
ser = serial.Serial('/dev/ttyACM1', 19200)
f = open('results.txt','w')

while 1:
        temp=strftime("%Y-%m-%d %H:%M:%S", gmtime())+'\t'+ser.readline()
        print(temp)
        f.write(temp)
        f.close()
        f = open('results.txt','a')
        time.sleep(5)

Código Arduino:

...

  double volt = 5.0*(analogRead(A0))/1023.0;

  double current = 5.18 - temp;   //Resistance ~= 1 Ohm if you are wondering

  buffer += d2s(volt,2)+'\t'+d2s(current,2)+'\t'+ d2s(count,0) +'\t' + d2s(minCount,0);

  Serial.println(buffer);

...

//I got this from the web

String d2s(double input,int decimalPlaces){

  String string;

  if(decimalPlaces!=0){
    string = String((int)(input*pow(10,decimalPlaces)));

       if(abs(input)<1){
          if(input>0)
              string = "0"+string;
          else if(input<0)
              string = string.substring(0,1)+"0"+string.substring(1);
  }

  return string.substring(0,string.length()-
decimalPlaces)+"."+string.substring(string.length()-decimalPlaces);
}

   else {
     return String((int)input);

}
}

0 votos

¿Puede mostrar los fragmentos de código pertinentes en ambos extremos?

0 votos

Hecho... Echa un vistazo

0 votos

Un ataque general a los problemas de este tipo es probar a hacer todo hacia y desde archivos de texto en lugar de fuentes de datos en vivo. Así que, por ejemplo, capturaría la salida del arduino a un archivo de texto, verificaría visualmente que es correcto, luego lo procesaría con el programa python y verificaría que la salida coincide con la entrada. Es probable que tengas un problema de parseo o de impresión con valores de punto flotante...

1voto

Doltknuckle Puntos 591

El arduino no es adecuado para hacer matemáticas en coma flotante, ni tampoco es particularmente adecuado para hacer manipulación de cadenas.

Estaría mejor enviando el valor leído de la entrada analógica directamente al código python en la Pi y hacer las matemáticas y la manipulación de cadenas en Python.

En el lado del arduino simplemente haz algo como esto:

int value;

value = analogRead(A0); // reads a 12bit integer value from the Analog input
Serial.println(value);  // converts the integer to a string and sends it over the serial port

Entonces, en el lado de Pi:

str = ser.readline()  # read a string from the serial port

value = float(str)    # convert a string to a floating point number

volt = 5.0 * value / 1023.0  # compute the voltage

0 votos

¡¿Por qué no se me ocurrió eso?! Sabía que los enteros se enviaban correctamente, lo único que necesitaba era convertirlos en el otro lado. Rápido, sencillo y funciona. ¡Muchas gracias!

0 votos

Aunque todavía tengo que averiguar el tema de que el Pyserial no lee correctamente las cadenas de punto flotante en primer lugar.

0voto

Michael WS Puntos 113

Encontré una manera de enviar la información correctamente usando Serial.write() pero aparentemente funciona byte a byte. Por lo tanto, tendré que escribir algo más de código para traducir todos y cada uno de los bytes.

Sin embargo, estoy seguro de que hay una manera mejor y más fácil.

0 votos

Nota: El envío de un array de bytes no ha funcionado

0voto

Stephen Denne Puntos 218

Si estás sospechando de la librería PySerial, tengo que decir que me sorprendería mucho que el problema estuviera ahí.

He usado PySerial bastante extensamente, tanto para datos binarios como ascii sin problemas (aunque no en una Raspberry Pi).

Una cosa que se me ocurre es que es posible que el puerto se esté abriendo de un modo extraño. Prueba a especificar manualmente el modo de paridad y bits de parada:

ser = serial.Serial('/dev/ttyACM1', baudrate=119200, bytesize=8, parity='N', stopbits=1)

La otra cosa que se me ocurre es que de alguna manera estés enviando un código de control ASCII, que PySerial está interpretando correctamente, y el terminal de Arduino no.
Si es posible, pruebe con otro terminal serie, y vea si coincide con uno u otro.


Sinceramente, esto me huele a problema de RAM. Estás utilizando un montón de funciones C++ (std::string), que tienen mucho consumo de RAM. Realmente deberías pensar en el arduino como un dispositivo C, y evitar las abstracciones C++, si es posible.

Además, ¿por qué diablos estás usando double s? La precisión del ADC es de 12 bits. Un simple float es de 32 bits en el arduino.

Además, confías en que tu código es "impecable", lo que me huele a inexperiencia (el único código perfecto es el que no existe).
Junto con ese hackeo (muy chapucero) de una función de conversión de doble a cadena (¡que encontró en internet!), me hace sospechar más del código del arduino.

Por favor, publique su todo fuente de arduino, no sólo un fragmento, también.


Otra cosa que se puede probar es almacenar e imprimir algunos de los resultados como cadenas puras:

Serial.println("4.93   0.38")
Serial.println("4.92   0.37")
Serial.println("4.92   0.37")
Serial.println("4.92   0.36")

Si eso falla, es muy probable que sea un problema en PySerial. Si no lo hace, es el código del arduino.

0voto

Abeey Ref Puntos 16

En realidad, pyserial lee los datos del Arduino como bytes, por ejemplo b234\r\n . Así que hay que quitar esos valores innecesarios antes de poder utilizarlos:

 valuebtw0to1023= serialObj.readline().strip('\r\n').strip()

0voto

lil'mustard Puntos 11

Si planea leer los datos en serie de la antena APC220 RF con python, tendrá que añadir la línea :

ser = serial.Serial('/dev/ttyACM1', 19200)
ser.setRTS(0) #  <------------------- this line solve the problem

Lo encontré después de un día entero de intentos y errores.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X