TODOPIC

Lenguajes de programación para PC => Python => Mensaje iniciado por: Miquel_S en 20 de Julio de 2016, 15:27:43

Título: Error puerto serie (SOLUCIONADO)
Publicado por: Miquel_S en 20 de Julio de 2016, 15:27:43
Hola estoy intentando aprender la comunicación serie con python y estoy usando un ejemplo en python 2.7 pero mi idea es realizarlo con python 3.5 y al ir probando por partes me da este error y no se como subsanar dicho error.

Código:
Código: Python
  1. #!/usr/bin/env python3.5
  2. # -*- coding: iso-8859-15 -*-
  3.  
  4. import serial
  5. import sys
  6.  
  7. puerto = '/dev/ttyUSB0'
  8.  
  9. #-- Cadena de pruebas
  10. cadena = 'Hola como estas'
  11.  
  12. #-------------------------
  13. #-- Abrir puerto serie
  14. #-------------------------
  15. try:
  16.         sg = serial.Serial(puerto, 9600)
  17.         sg.timeout = 1;
  18.  
  19. except serial.SerialException:
  20.         #-- Error al abrir el puerto serie
  21.         sys.stderr.write("Error al abrir el puerto " +str(puerto) +"\n")
  22.         sys.exit(1)
  23.  
  24. #-- Mostrar nombre del dispositivo serie utilizado
  25. print("Puerto: " +str(puerto))
  26.  
  27. #-------------------------
  28. #-- Prueba del puerto
  29. #-------------------------
  30.  
  31. #-- Enviar cadena de pruebas
  32. print("ENVIADO: " + str(cadena))
  33. sg.write(cadena);
  34.  
  35. #-- Esperar hasta recibir la cadena
  36. recibido = sg.read(len(cadena));
  37.  
  38. sg.close()

Error:
(http://www.todopic.com.ar/foros/imgtiny/a9pohf.png)

Gracias.
Título: Re:Error puerto serie
Publicado por: KILLERJC en 20 de Julio de 2016, 16:20:03
Proba con:

Código: Python
  1. sg.write(cadena.encode('ascii'));
  2.  
  3. sg.write(b"Probando");

Citar
a Unicode string is a sequence of code points, which are numbers from 0 through 0x10FFFF (1,114,111 decimal). This sequence needs to be represented as a set of bytes (meaning, values from 0 through 255) in memory. The rules for translating a Unicode string into a sequence of bytes are called an encoding.

Todas las string son unicode, por lo tanto no es lo mismo que el ASCII, es decir cada letra posee muchos mas bits.

https://docs.python.org/3/library/stdtypes.html#str.encode

https://docs.python.org/3/library/codecs.html#standard-encodings

La b lo convierte en un objeto de bytes, y solo acepta caracteres ASCII
Título: Re:Error puerto serie
Publicado por: Miquel_S en 20 de Julio de 2016, 16:53:48
Gracias KILLERJC en principio cambiando
Código: Python
  1. sg.write(cadena);
por
Código: Python
  1. sg.write(cadena.encode('ascii'));
ha desaparecido el error.

Saludos!
Título: Re:Error puerto serie
Publicado por: Miquel_S en 21 de Julio de 2016, 13:35:39
Perdón por preguntar de nuevo, con referencia a esta instrucción
Código: Python
  1. sg.write(cadena.encode('ascii'));
no se donde buscar los parámetros que van dentro del
Código: Python
  1. sg.write( );
solo he encontrado esto y creo entender que str seria el string y el encode junto a 'ascii' entiendo lo que hace pero no coincide con
Código: Python
  1. os.write(fd, str)

os.write(fd, str)

    Write the bytestring in str to file descriptor fd. Return the number of bytes actually written.

    Note

    This function is intended for low-level I/O and must be applied to a file descriptor as returned by os.open() or pipe(). To write a “file object” returned by the built-in function open() or by popen() or fdopen(), or sys.stdout or sys.stderr, use its write() method.

    Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the function now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).


Gracias.
Título: Re:Error puerto serie
Publicado por: KILLERJC en 21 de Julio de 2016, 14:08:28
sg, es una inicializacion de serial

Por lo tanto deberias buscar la documentacion del modulo serial

http://pythonhosted.org/pyserial/pyserial_api.html

Ahi dentro vas a ver que en el _init_ se define todo, y es cuando usas serial.Serial(), luego ese objeto o "link al puerto" que ahora llamas "sg", tiene todas las metodos/funciones de la clase serial.

Por eso podes buscar en la documentacion:

Citar
write(data)

Parameters:   data – Data to send.
Returns:   Number of bytes written.
Return type:   int
Raises SerialTimeoutException:
    In case a write timeout is configured for the port and the time is exceeded.

Write the bytes data to the port. This should be of type bytes (or compatible such as bytearray or memoryview). Unicode strings must be encoded (e.g. 'hello'.encode('utf-8').


Lo que estamos haciendo aca:

Código: Python
  1. sg.write(  cadena.encode('ascii')  );

Es simplemente hacer que el STRING "cadena", que posee sus propiedades y funciones por ser string la codificamos en otro formato, ya que no queremos UNICODE, sino uno de 8 bits.
Finalmente eso pasa a la funcion write.

-------------------------------------------------------------

os es un modulo ("libreria") totalmente distinto

Citar
os — Miscellaneous operating system interfaces
https://docs.python.org/3/library/os.html

que tambien tiene sus metodos/funciones como write, entre otras. Pero no es lo que estas usando, incluso para usar esta debes tener cargar el modulo primero
con import os


-------------------------------------------------------------

PD: hasta te indica la cantidad de bytes enviados el .write, podrias hacer:

Código: Python
  1. cantidadBytes = sg.write("texto".encode('ascii'))

Y cantidadBytes termina siendo un entero con el numero de bytes enviados
Título: Re:Error puerto serie
Publicado por: Miquel_S en 21 de Julio de 2016, 14:41:57
Yo quiero ser como tu  :( hay algo que no sepas.

MUCHAS GRACIAS.
Título: Re:Error puerto serie
Publicado por: KILLERJC en 21 de Julio de 2016, 14:55:29
Yo quiero ser como tu  :( hay algo que no sepas. Google no encuentre?

MUCHAS GRACIAS.

xD Arreglado, en serio, el 95% de los problemas se encuentra buscando en google :P, lo que veo que no tenias en claro lo de los modulos y objetos, ya que buscaste seguro sg.write por google, te faltaba eso nomas para entender que estabas haciendo y buscar correctamente, es decir buscar la documentacion del modulo "serial". Todo lo demas lo resolvio google :P

Y por ejemplo tu primer problema, busque acerca del error que te daba:

"Unicode strings are not supported, please encode to bytes"

2do o 3er link en una respuesta de stack overflow y tenes la razon y solucion a tu problema
Título: Re:Error puerto serie
Publicado por: Miquel_S en 23 de Julio de 2016, 06:33:51
Me falta mucho por aprender pero lo intento, he estado buscando que parámetros poner dentro del
Código: Python
  1. recibido = sg.read()
en la pagina de pyserial y veo que esta hablando del numero de bytes, pero no se como hacerlo, también he probado
Código: Python
  1. recibido = sg.read(len(cadena.encode('ascii')))
pero me dice que no coinciden:

(http://www.todopic.com.ar/foros/imgtiny/2gw56iw.png)

Codigo:
Código: Python
  1. #!/usr/bin/env python3.5
  2. # -*- coding: iso-8859-15 -*-
  3.  
  4. import serial
  5. import sys
  6.  
  7. puerto = '/dev/ttyUSB0'
  8.  
  9. #-- Cadena de pruebas
  10. cadena = 'Prueba SCI'
  11.  
  12. #-- Mensaje inicial
  13. print(("Pruebas con el puerto SCI"))
  14.  
  15. #-------------------------
  16. #-- Abrir puerto serie
  17. #-------------------------
  18. try:
  19.     sg = serial.Serial(puerto, 9600)
  20.     sg.timeout = 1
  21.  
  22. except serial.SerialException:
  23.     #-- Error al abrir el puerto serie
  24.     sys.stderr.write("Error al abrir el puerto " + str(puerto) + "\n")
  25.     sys.exit(1)
  26.  
  27. #-- Mostrar nombre del dispositivo serie utilizado
  28. print(("Puerto en uso: " + str(puerto)))
  29.  
  30. #---------------------------
  31. #-- Prueba del puerto
  32. #---------------------------
  33.  
  34. #-- Enviar cadena de pruebas
  35. print(("ENVIADO: " + str(cadena)))
  36. sg.write(cadena.encode('ascii'))
  37.  
  38. #-- Esperar hasta recibir la cadena
  39. recibido = sg.read(len(cadena.encode('ascii')))
  40.  
  41. #--Comprobar lo recibido
  42. if len(recibido) != 0:
  43.     #-- Imprimir cadena recibida
  44.     print(("RECIBIDO:" + str(recibido) + "\n"))
  45.  
  46. #-- Comprobar si lo recibido es igual que lo enviado
  47.     if recibido == cadena:
  48.         print(("OK... coincide con lo enviado"))
  49.     else:
  50.         print(("¡¡ERROR!! Lo recibido no coincide con lo enviado" + "\n"))
  51.  
  52. else:
  53.     #-- No se ha recibido ninguna cadena
  54.     print(("TIMEOUT..."))
  55.  
  56. #-- Cerrar puerto serie
  57. print(("Fin de la prueba..."))
  58. sg.close()

Saludos!
Título: Re:Error puerto serie
Publicado por: tsk en 23 de Julio de 2016, 11:01:31
Tiene que ver con la codificación, cuando lo imprimes en pantalla se ve esa b al inicio del texto  recibido

No es lo mismo b’Texto’ a ‘Texto’ en python 3, en python2 si los toma como iguales.
Código: [Seleccionar]
$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> d =b'23456'
>>> d
'23456'
>>> dd ="23456"
>>> dd == d
True
>>>

Código: [Seleccionar]
$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> d = b'2348'
>>> d
b'2348'
>>> c = "2348"
>>> c == d
False
>>> c == d.decode("utf-8")
True

Si quieres evitar saber cuantos bytes vas a recibir envía los datos con la terminación “\n” en ese momento puedes usar readline en lugar read, este es un ejemplo sencillo usando bottle (web framework para python) y arduino

Código: [Seleccionar]
import serial
import time
from bottle import run, route
#Init the serial port

ser = serial.Serial("/dev/ttyUSB0",9600,timeout=1)
time.sleep(2)
@route("/arduino1")
def arduino1():
    ser.write('a')
    read_val = ser.readline()
    return '{"id":23,"value":%s}'%read_val

run(host="localhost",port=8080)
#close the serial port on exit
ser.close()

Código: [Seleccionar]
int randNumber;
int c;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available())
  {
    c = Serial.read();
    randNumber = random(200);
    Serial.println(randNumber,DEC);
  }
}
Título: Re:Error puerto serie
Publicado por: Miquel_S en 23 de Julio de 2016, 13:19:53
Gracias tsk por las molestias pero no estoy intentando comparar números ni trabajo con arduino.

Saludos!
Título: Re:Error puerto serie
Publicado por: tsk en 23 de Julio de 2016, 13:41:14
Gracias tsk por las molestias pero no estoy intentando comparar números ni trabajo con arduino.

Saludos!

No són números es texto todo lo que esta entre ' ' es texto

Código: [Seleccionar]
'1234' --> Texto
"1234" --> Texto
1234 --> Número

Código: [Seleccionar]
>>> type(1234)
<class 'int'>
>>> type('1234')
<class 'str'>
>>> type("1234")
<class 'str'>
>>>

Y sólo lo puse de ejemplo para que vieras que el uso del readline (era el ejemplo que tenía a la mano más rápido) para que te evites conocer el tamaño de la cadena a recibir. Para el pic sólo debes de mandar '\n' al final de lo que vas a mandar.
----------
Tipos de datos nativos en python

http://www.diveintopython3.net/native-datatypes.html

Título: Re:Error puerto serie
Publicado por: KILLERJC en 23 de Julio de 2016, 14:17:15
Te lo pongo mas facil Miguel

Tu problema esta aca:

Código: Python
  1. if recibido == cadena:

Y lo que intento decirte tsk, que estuvo genial con explicaciones y todo, es que :

recibido tiene una codificacion ascii
cadena tiene una codificacion UNICODE

Por lo tanto ambos string nunca van a ser iguales. proba asi:

Código: Python
  1. if recibido == cadena.encode('ascii'):

Lo que si no encuentro es el readline() que comenta tsk EN la documentacion, pero en la pagina del modulo SI aparece.

El readline como te dijo haria que no necesites hacer esto:

Código: Python
  1. recibido = sg.read(len(cadena.encode('ascii')))

es decir, decirle la cantidad de bytes a recibir, sino:

Código: Python
  1. recibido = sg.readline()

y funcionaria SIEMPRE Y CUANDO:

- Envies un "\n" al final, ya que este guarda hasta que llegue ese "\n". Es decir:

Código: Python
  1. cadena = 'Prueba SCI\n'

- Y tenes que seleccionar un timeout, sino cuando no reciba el \n este quedaria atrapado para siempre alli. Por default el timeout esta desactivado.

El timeuot es un opcion del serial.Serial

Citar
timeout (float) – Set a read timeout value.

Possible values for the parameter timeout which controls the behavior of read():

timeout = None: wait forever / until requested number of bytes are received
timeout = 0: non-blocking mode, return immediately in any case, returning zero or more, up to the requested number of bytes
timeout = x: set timeout to x seconds (float allowed) returns immediately when the requested number of bytes are available, otherwise wait until the timeout expires and return all bytes that were received until then.

Código: Python
  1. sg = serial.Serial(puerto, 9600, timeout=3)

3 segundos de timeout.

------------------------------

Espero que quede bastante mas claro lo que quiso decir tsk
Título: Re:Error puerto serie
Publicado por: Miquel_S en 23 de Julio de 2016, 15:18:59
Gracias de nuevo a los dos, ahora si me funciona, aunque a no ser que me haya equivocado solo me funciona de una de las maneras y es usando
Código: Python
  1. if recibido == cadena.encode('ascii'):
lo que no se si con alguna aplicación real pudiera dar problemas el que lo enviado sea Prueba SCI y lo recibido sea b'PruebaSCI'
(http://www.todopic.com.ar/foros/imgtiny/34e9j01.png)

De nuevo GRACIAS.
Título: Re:Error puerto serie
Publicado por: KILLERJC en 23 de Julio de 2016, 15:28:43
Código: Python
  1. print(("RECIBIDO:" + str(recibido, 'ascii') + "\n"))

Lo que recibis es en ASCII, o un objeto de bytes, para pasarlo a texto unicode lo que haces es pasarlo de ASCII a UNICODE.

Tambien podrias hacer:

recibido = recibido.decode('ascii')

Luego de recibir el dato, Y te serviria tu comparacion de antes:

Código: Python
  1. if recibido == cadena:

, y no tendrias problema por que ambos serian unicode. El print te daria correcto tambien.
Título: Re:Error puerto serie
Publicado por: Miquel_S en 23 de Julio de 2016, 19:01:25
Se agradece KILLERJC.
Título: Re:Error puerto serie (SOLUCIONADO)
Publicado por: Miquel_S en 23 de Julio de 2016, 21:25:56
Una duda aunque no tenga que ver con el puerto serie, si escribo
Código: Python
  1. valor = 5896
y despues
Código: Python
  1. str(valor)
me convierte valor a un string pero si escribo
Código: Python
  1. print(("Valor: " + str(valor)))
me imprime en pantalla valor como un int ¿Porque de esta manera no me convierte valor a string?

Gracias.
Título: Re:Error puerto serie (SOLUCIONADO)
Publicado por: KILLERJC en 23 de Julio de 2016, 23:03:37
En realidad el str te lo convierte a un string en ambos casos, el "+" en un string es concatenar.

"Valor: " + str(valor)

Es lo mismo que :

"Valor: " + "5896"

Y por ende:

"Valor: 5896"
Título: Re:Error puerto serie (SOLUCIONADO)
Publicado por: Miquel_S en 24 de Julio de 2016, 05:56:27
He abierto otro tema para no mezclar un tema con otro.
http://www.todopic.com.ar/foros/index.php?topic=46587.0

Miquel_S