Caratteri ascii seriale arduino e python

Ciao a tutti sto cercando di inviare dati alla seriale, la variabile che acquisisce da Serial.read() è impostata come byte

byte data = Serial.read()

però se invio l'intero 10 da seriale questo viene visto come newline "\n", c'è modo di ovviare a questo inconveniente?, io invio dati da seriale tramite python, invio i dati proprio come byte con questa sintassi

serial.write(bytes([2,10]))

per la maggior parte dei numeri non ho molti problemi, ma col 10 e qualche altro intero si.

Grazie

Scusate ma è il Serial.write() di arduino che lo converte nella sua forma ascii, se uso il Serial.print mi stampa 10, non c'è modo di fargli inviare il 10.

Grazie

potresti inviare prima '1' e poi '0' e riunirli lato arduino...

Da seriale invii dei byte che possono essere interpretati come numeri da 0 a 255 o come caratteri ascii.

Se tu scrivi in serial.write(10), stai inviando un byte di valore 10 che interpretato come carattere da '\n'.

Quindi o lo usi come numero "int o byte" o lo usi come carattere "char" in questo caso avrà codice valore ascii.

Per inviare un numero da seriale conviene inviare una stringa rappresentante il numero e poi convertirla in numero in arduino. In questo modo non sei limitato a valore massimo 255, un byte
può contenere al massimo il valore 255, e quindi non potresti trasmettere 1000 con un byte. Usando una stringa e poi convertirla in numero ti permette di usare numeri interi o float superiori a 255.

Da seriale python invii una stringa ser.write("10".encode())

String valore;

void loop(){

    valore=Serial.readString();

    int numero =valore.toint();

}

A me per quello che devo fare bastano i numeri fino a 255 ma non riesco a capire come far leggere a pithon il byte 10 come int10 e non come char '\n' ho provato sia con read() che con readline(),

Se era un problema di cosa riceve Arduino , posti una domanda sul forum Arduino , se è un problema su cosa reve python posti in un forum python. Comunque prova
Int(serial.read()) su python

torn24:
Se era un problema di cosa riceve Arduino , posti una domanda sul forum Arduino , se è un problema su cosa reve python posti in un forum python. Comunque prova
Int(serial.read()) su python

Ho postato qui perchè mi sono accorto dopo che il problema era in ricezione da parte di python.

Comunque grazie adesso provo.

Ho eseguito varie prove, e con "ord(serial.read())" il 10 viene correttamente convertito, però il problema è che alcuni numeri arduino li invia come caretteri, metre altri come hex, ad esempio il 200 lo invia come 0xc8, si può fare in modo che Serial.write() di arduino invii tutto come hex?

Grazie

credo (ma non ho mai provato) che basti usare la notazione esadecimale... il 10 dovrebbe essere 0xA...

Ragazzi, fissate bene in testa quanto segue: qualunque cosa trasmettiate su qualunque mezzo digitale, quel che viaggia sono SEMPRE byte!

Senza pontificare troppo, un byte è un "piccolo numero intero" che può valere da 0 a 255, nulla di più, nulla di meno.

Se preferite dirlo in esadecimale (base 16), allora va da 0 a FF. Se preferite il binario (base 2), va da 0 a 11111111, ma è solo una questione di rappresentazione, il valore è sempre lo stesso. È un po' come parlare in italiano o in inglese, le parole sono diverse ma i concetti sono gli stessi.

Per comodità, nel seguito userò la rappresentazione decimale.

Ora, a meno che non si voglia trasmettere appunto una serie di tali piccoli numeri, bisogna in qualche modo trasformare quel che si vuole trasmettere in una sequenza di questi piccoli numeri. L'ASCII esiste apposta per questo, e assegna un "piccolo numero" ad ogni lettera dell'alfabeto e ad una serie di altri simboli utili. Ad esempio, la A maiuscola corrisponde a 65, la B a 66, ecc.

Tra i simboli che l'ASCII codifica, vi sono anche le cifre, ma le cifre intese come carattere, ovvero come simbolo, non come valore. Ad esempio, il simbolo che rappresenta il numero uno corrisponde a 49.

Ora, tu devi decidere se tra Python e Arduino vuoi spedire "piccoli numeri" o sequenze di caratteri che li rappresentano. È una tua scelta, con pro e contro: se devi spedire solo numeri < 255, un byte è sufficiente nel primo caso, mentre nel secondo ne possono servire fino a 3, visto che devi spedire la rappresentazione ASCII di ogni cifra. D'altro canto se devi spedire numeri arbitrariamente grandi, con un byte non lo puoi fare. Valuta tu, l'importante è che da un lato spedisci seguendo una rappresentazione, e dall'altra ricevi interpretandola correttamente,

PS: ord() è la funzione Python che, dato un carattere, restituisce il codice ASCII che gli corrisponde (per farla breve). chr() fa il contrario.

1 Like

Si so cosa fa "ord" in python, però il fatto è che con Serial.write() di arduino se gli do in pasto l'intero 10 python lo legge come carattere e me lo visualizza come 10 utilizzando "ord(serial.read(1))", ma se a Serial.write() gli do l'intero 200, python in lettura lo vede come un esadecimale, quindi con ord mi dà un errore in quanto non lo riconosce come carattere, quindi non riesco a capire se è arduino che invia in modo diverso o è python che legge in modo del tutto arbitrario.

Grazie

P.S. se utilizzo Serial.print() su arduino e "serial.readline().decode('utf-8')" in python visualizzo i numeri in modo corretto, solo che dovendo inviare una sequenza di 3 numeri, con Serial.write() invio solo 3 byte, con Serial.print() posso arrivare fino a 9 se tutti e tre i numeri sono a tre cifre.

Arduino invia semplici byte correttamente, i problemi che riscontri sono dovuti a python.
Pur essendo un linguaggio molto usato, a volte per problemi specifici è difficile trovare documentazione.

Io ti propongo di trasmettere da arduino una stringa Serial.println("200")

e riceverla e trasformarla in intero da python int( serial.readline()), fai prima e risolvi il problema..

vinny74:
A me per quello che devo fare bastano i numeri fino a 255 ma non riesco a capire come far leggere a pithon il byte 10 come int10 e non come char '\n' ho provato sia con read() che con readline(),

Se Python ha ricevuto 10, che lo interpreti come \n o 10 intero sempre un 10 come cifra hai ricevuto.

Ma poi quello che leggi come lo stampi? Perché strano lo vedi in esadecimale.
Se è questo quello che ti capita: LINK mi pare ci sia anche la soluzione.
Di base mi pare di capire dal link che Python legge/scrive non a byte, il link spiega come forzare la situazione.

vinny74:
Si so cosa fa "ord" in python, però il fatto è che con Serial.write() di arduino se gli do in pasto l'intero 10 python lo legge come carattere e me lo visualizza come 10 utilizzando "ord(serial.read(1))", ma se a Serial.write() gli do l'intero 200, python in lettura lo vede come un esadecimale, quindi con ord mi dà un errore in quanto non lo riconosce come carattere, quindi non riesco a capire se è arduino che invia in modo diverso o è python che legge in modo del tutto arbitrario.

Probabilmente nessuna delle due. Intanto stabiliamo quale Python si sta usando 2.x o 3.x? Il trattamento dei byte è una delle differenze fondamentali tra le due versioni.

Se con Arduino e Serial.write() invii un byte 0..255, Python riceve sicuramente sempre e solo un byte 0..255, niente esadecimale o \n ecc che sono esclusivamente rappresentazioni di stampa. Quello che può succedere è usare in modo non corretto il dato ricevuto.

In Py2 un byte generico è "contenuto" in una stringa (come in C), il suo valore 0..255 si ottiene con ord().
In Py3 un byte generico è "contenuto" in un oggetto bytes, il suo valore è già "in chiaro".

La funzione struct.unpack('B'*len(sequenza), sequenza) è compatibile con entrambe le versioni e restituisce una nuova sequenza di interi 0..255 (ma è praticamente inutile in Py3 dove i valori sono già in chiaro).

In nessun caso devono saltare fuori esadecimali ecc, che sono solo rappresentazioni di stampa o (esplicitamente volute) rappresentazioni sotto forma di stringa di caratteri.

Io utilizzo python 3.4.3 e ottengo come rappresentazione di quei bit i caratteri corrispondenti in ascii.

Se da arduino invio tre interi:

int a = 200;
int b = 10;
int c = 95;

Serial.write(a);
Serial.write(b)
Serial.write(c);

su python faccio in questo modo

valoreDiRitorno = serial.read(3)
print(valoreDiRitorno)

e ottengo come risposta dalla print

b'\xc8\n_'

Prova:

for b in valoreDiRitorno:
print int (b)

SukkoPera:
Prova:

for b in valoreDiRitorno:
print int (b)

Adesso sono a lavoro appena rientro stasera provo
Grazie

SukkoPera:
Prova:

for b in valoreDiRitorno:
print int (b)

Funziona mi visualizza il byte 10 come intero 10, ho però provato anche con i float, ma mi stampa solo la parte intera e non quella decimale.

in python faccio così

for b in valoreDiRitorno:
    print(float(b))

mentre in arduino uso il Serial.write(10.15).

Quindi mi chiedo se è arduino che non invia i float tramite il Serial.write() o è python che non gestisce il punto come numero e quindi lo evita?

Grazie

Non l'ho specificato chiaramente, e ho quindi corretto il post precedente, ma un byte può contenere solo valori INTERI compresi tra 0 e 255.

Se vuoi inviare dei numeri decimali devi inventarti qualcosa, tipo:

  • Moltiplicarli per 10 o 100, in modo da trasformarli in interi (ma sempre <= 255), trasmetterli come tali, e ridividerli a destinazione. Questo ovviamente limita il range e la precisione.
  • Usare una qualche codifica, tipo IEEE-754, ma lascia perdere :).
  • Inviarli come stringhe, che probabilmente è la soluzione migliore, nonché quella che qualcuno ti ha già suggerito qualche post fa. Questo vuol banalmente dire usare Serial.println() da Arduino, e lato Python fare più o meno quello che stai facendo ora. Riceverai i numeri separati da un "a capo".

SukkoPera:
Non l'ho specificato chiaramente, e ho quindi corretto il post precedente, ma un byte può contenere solo valori INTERI compresi tra 0 e 255.

Se vuoi inviare dei numeri decimali devi inventarti qualcosa, tipo:

  • Moltiplicarli per 10 o 100, in modo da trasformarli in interi (ma sempre <= 255), trasmetterli come tali, e ridividerli a destinazione. Questo ovviamente limita il range e la precisione.
  • Usare una qualche codifica, tipo IEEE-754, ma lascia perdere :).
  • Inviarli come stringhe, che probabilmente è la soluzione migliore, nonché quella che qualcuno ti ha già suggerito qualche post fa. Questo vuol banalmente dire usare Serial.println() da Arduino, e lato Python fare più o meno quello che stai facendo ora. Riceverai i numeri separati da un "a capo".

quote author=SukkoPera link=msg=3207937 date=1491406929]
Non l'ho specificato chiaramente, e ho quindi corretto il post precedente, ma un byte può contenere solo valori INTERI compresi tra 0 e 255.

Se vuoi inviare dei numeri decimali devi inventarti qualcosa, tipo:

  • Moltiplicarli per 10 o 100, in modo da trasformarli in interi (ma sempre <= 255), trasmetterli come tali, e ridividerli a destinazione. Questo ovviamente limita il range e la precisione.
  • Usare una qualche codifica, tipo IEEE-754, ma lascia perdere :).
  • Inviarli come stringhe, che probabilmente è la soluzione migliore, nonché quella che qualcuno ti ha già suggerito qualche post fa. Questo vuol banalmente dire usare Serial.println() da Arduino, e lato Python fare più o meno quello che stai facendo ora. Riceverai i numeri separati da un "a capo".
    [/quote]

Hai ragione lo avevi specificato bene e anche io lo sapeva, ma preso dal fatto che mi stampava il 10 ho cancellato dalla mente questo particolare, si quindi per i float utilizzerò Serial.print.

Grazie

SukkoPera:
Non l'ho specificato chiaramente, e ho quindi corretto il post precedente, ma un byte può contenere solo valori INTERI compresi tra 0 e 255.

Se vuoi inviare dei numeri decimali devi inventarti qualcosa, tipo:

  • Moltiplicarli per 10 o 100, in modo da trasformarli in interi (ma sempre <= 255), trasmetterli come tali, e ridividerli a destinazione. Questo ovviamente limita il range e la precisione.
  • Usare una qualche codifica, tipo IEEE-754, ma lascia perdere :).
  • Inviarli come stringhe, che probabilmente è la soluzione migliore, nonché quella che qualcuno ti ha già suggerito qualche post fa. Questo vuol banalmente dire usare Serial.println() da Arduino, e lato Python fare più o meno quello che stai facendo ora. Riceverai i numeri separati da un "a capo".