Processing: Varie ed Eventuali

Processing sragiona ? o forse io ? :)

Se su arduino stampo il carattere newline \n non ho problemi, riesco a riceverlo e gestirlo su processing, uso questo carattere come marker per comunicare la fine del valore del potenziometro:

ARDUINO:

Serial.print(analogRead(potPin)); 
  Serial.print("\n");

PROCESSING:

int MARKER = 10; \\ valore dec ASCII di \n
port.bufferUntil(MARKER);
brightness = float(port.readStringUntil(MARKER));
println(brightness);

Volendo invece usare un carattere arbitrario, ad esempio M, al posto di \n, non funziona. invece del valore del potenziometro su processing ricevo "NaN" ARDUINO:

Serial.print(analogRead(potPin)); 
  Serial.print("M");

PROCESSING:

int MARKER = 77;  \\ valore dec ASCII di M
port.bufferUntil(MARKER);
brightness = float(port.readStringUntil(MARKER));
println(brightness);

Ci sto' sbattendo la testa da qualche ora, mi arrendo :) Questo e' lo sketch completo sia lato Arduino che Processing http://ilblogdidami.blogspot.it/2011/10/arduino-and-processing-serial_03.html

Grazie

Mmm se può esserti d'aiuto, anche io ho avuto problemi con questa comunicazione. Nel primo esempio che hai citato tu (con lo \n) addirittura non mi funzionava e mi dava molti valori nulli prima che ricevesse il carattere, quindi ho risolto con:

if ( arduino.available() > 0) { 
    val=arduino.readStringUntil('\n');
    if(val!=null){
     altezza=val;
    }    
  }

Poi magari non c'entra niente..

però io mi chiedo, cosa succede quando il valore del potenziometro è proprio 10?

Potrebbe trattarsi di codifiche di caratteri differenti fra Arduino e Processing? Invece di quel loop in Processing perché non inizi stampando cosa effettivamente arriva dalla seriale, per capire quando mandi "M" da Arduino il computer cosa riceve e Processing cosa stampa.

provo subito, grazie dell'intervento :)

NaN non è possibile. E' una sigla per indicare che ha ricevuto qualcosa di inintellegibile o un dato non atteso: http://it.wikipedia.org/wiki/NaN

A tipi di dati siamo a posto? Cioè accetti il dato in una variabile capace di riceverlo?

scusa ho cancellato il vecchio post per errore.

cmq ho messo in piedi uno sketch solo per leggere la seriale ed effettivamente se invio M e poi \n mi leggo in processin 77 e poi va a capo

credo che il problema sia quello che dici tu, dallo sketch processing (anche se non lo usi lo stile e i concetti sono quelli arduinici) non noti nulla ? sara' la variabile MARKER messa ad int ? ho provato a dichiararla char ma ricevo sempre NaN

Secondo me il problema è qui:

brightness = float(port.readStringUntil(MARKER));

Tu converti la lettura in float. Ma che cosa ottieni da port.readStrinUntil(MNARKER)? Io credo una stringa, lo intuisco dal nome. Trova caratteri non validi e dà quell'errore. Cerchi cioè di convertire "M" in numero ;)

la cosa strana e' che cmq con \n funziona.

lasciando stare le altre variabili ed anche processing in se', parlando in generale per me sono equivalenti queste due cose

Serial.print("\n");
int MARKER =10;

con

Serial.print("M");
int MARKER =77;

cioe' i tipi di dati mica li cambio fra il primo e il secondo tipo. eppure se su arduino sparo il "\n" su processing lo intercetto cercando con una int il 10 tutto funge bene. Mentre se su arduino sparo "M" e su processing con una int cerco 77 non funge piu' :fearful:

p.s abbiamo scritto insieme, cmq come vedi anche "\n" e' un numero eppure funziona

Il carattere "\n" è un carattere particolare, che corrisponde al byte 10. In memoria non viene rappresentato con "\n", sta qui la differenza. Mentre invece se spedisci "M" e leggi con quella funzione, ti viene restituita una stringa "M". La la "stringa" per "\n" è uno di quei byte che quando stampi spesso appaiono come quadratini vuoti, ma che poi vengono convertiti in numero perché hanno già un valore. Son convinto che otterresti lo stesso risultato spedendo "\r", che corrisponde a 13.

hai colto nel segno, infatti avevo gia' provato con altri caratteri non stampabili, \r, \t, ecc e funzionano tutti. Non funziona invece con \0 che e' anch'esso non stampabile.

Volevo capire cosa c'e' sotto, parliamo di qualche pilastro informatico che viene dalle telescriventi credo. Hai qualche link per approfondire ? Perche' purtroppo io continuo a non cogliere il vero motivo, non riesco a comprendre appieno questa tua frase e mi piacerebbe approfondire:

La la "stringa" per "\n" è uno di quei byte che quando stampi spesso appaiono come quadratini vuoti, ma che poi vengono convertiti in numero perché hanno già un valore

Seconda questione, come posso modificare il codice in modo da farlo funzionare con la "M" ? Ho provato a dichiarare String il marker, ma al compilatore di processing non piace: String MARKER =77;

P.S. Ho aggiunto nel primo post il link completo al codice Arduino+Processing, magari approfitto per farti installare e conoscere processing :)

  1. state facendo confusione tra caratteri e stringhe. Se scrivete "\n" state creando una STRINGA di un carattere, mentre a voi interessa '\n', ovvero IL CARATTERE (questo lato arduino)

  2. perchè lato processing dai tu arbitrariamente il valore? non puoi fare come su arduino? int MARKER = '\n'; oppure int MARKER = 'M';

  3. non son sicuro ma bufferUntil scarta tutti i dati successivi... se nel momento in cui leggi il buffer, arriva la seconda parte di un dato otterrai un valore sballato perchè la prima parte è stata persa. NON limitare i buffer in alcun modo.

  4. port.readStringUntil(MARKER) è ok, dovrebbe bastare usare solo questa. Ma che succede se non è ancora stato letto un carattere di tipo MARKER? bhe che viene restituita un valore NULL, che se provi a convertire in numero è un NaN (not a number, non un numero... tra l'altro sto NaN te lo ritrovi con le divisioni per 0)

quindi: String ris = port.readStringUntil(MARKER); //leggo il buffer float a = 0; //inizializzo la variabile risultato if (ris != null){ //se ho letto qualcosa println(ris); //per debug a = Float.parseFloat(ris); //effettuo il parse da String a float, è l'equivalente del tuo float() ma precotto dal java println(a); //per debug println(); //lascia una riga vuota }

però io mi chiedo, cosa succede quando il valore del potenziometro è proprio 10?

i valori del potenziometro non sono spediti "raw", ma convertitti in stringa. Quindi leggerai 3 caratteri: '1', '0', e 'M' (o '\n', dipende da cosa usate)

se volessi leggere i dati RAW è più facile: NON serve il carattere di fine e sai che un int di arduino è 2 byte (attenzione, in java/processing è 4 byte), quindi basta leggere 2 byte e metterli in un int (attenzione al segno! dovete gestirlo voi in base al valore del primo byte letto, del bit più a SX) certo, se il processing lo fai partire quando arduino già rasmette, non sei in grado di capire qual'è il primo e quale il secondo byte e devi cmq usare il sistema del " valore tappo"

edit: notare la somiglianza della mia soluzione con quella di shorty... ora sa perchè funziona, e perchè otteneva tanti valori null (punto 3 + Serial.available(), cosa che mi son dimenticato )

Grazie Lesto, avevo aperto ieri un topic con i miei dubbi su questo, ma l'avevo richiuso perchè non mi era chiaro neanche ciò che avevo scritto. Quindi per far "parlare" Arduino e Processing alla fine conviene usare una stringa. Se devo mandare due numeri 'grandi' li mando cifra per cifra, magari intervallati da uno spazio e utilizzando un carattere di inizio tx e magari anche uno di fine. Per esempio se dovessi spedire: 478 e 2112 diventerebbe una stringa di 10 caratteri.. se dovessi mandarla in byte, però, potrei usare solo 6 byte, se ne utilizzo 2 per l'inizio trasmissione. dico 2 perchè uno solo non saprei come distinguerlo da uno dei valori da leggere. quindi se mando come inizio trasmissione una sequenza 255,255 sono sicuro che non rientra tra le doppiette di byte dati (in quanto limito il dato ad un numero tipo 10000. che viene: 00100111 00010000 -> quindi il byte alto non potrà mai essere 11111111. Può funzionare così?

p.s. scusa Testato per l'intromissione, ma magari completa un pò il discorso.

Davide.

grazie lesto dell'intervento, ma non funziona :)

lasciando perdere lo sketch in se', che non mi interessa piu' di tanto, sto' solo tentando di capire questa gestione dei caratteri

se uso Serial.print('\n'); in arduino e int MARKER = '\n'; in processing tutto funziona

se uso ('M') invece ricevo NaN

Prova tu stesso :)

si, ma cosa ottinei nella terminale di output? ho messo le println() apposta :-)

@dab77: il carattere tappo è un macello, varia dalla situazione.

te l'ho scritto, ricevo NaN :)

prendi lo sketch che ho indicato, vedrai che con '\n' funge, con 'M' ti restituisce NaN teniamoci sullo sketch pubblicato dal link che ho messo, e ragioniamo su quello, perche' la questione e' solo didattica ed e' sulla gestione di sti caratteri

ti diro' di piu', non tutti i caratteri non stampabili fuzionano, ad esempio con '\r' funziona, ma se usi '\a' non funziona.

io dico che ho scoperto un'altra magagna, possibile che le scopra tutte io ? devo cambiare nick da Testato a Buggato :)

nan vuol dire che hai già tentato di convertire la stringa in numero. ma io voglio sapere cosa hai nella stringa PRIMA della conversione.

quel codice è buggato:

void serialEvent (Serial port){
  brightness = float(port.readStringUntil('\n'));
  }

questa funzione è come un interrupt, viene chiamata ogni volta che succede qualcosa alla seriale. Eliminiamo il fatto che ci son mille motivi per cui potrebbe essere chiamato quel codice (in teoria anche quando invii... ma devo guardare la documentazione) quello che è sicuro è che probabilmente (dipende dal carico del PC) chiamata OGNI byte in entrata... quindi se invii 123'\n', le prime 3 concersioni (con 1, 2 e 3) vanno in errore perchè port.readStringUntil('\n') ritorna null (perchè nel buffer in ricezione non è ancora presente '\n'), che diventa NaN passando dalla conversione.

quindi:

void serialEvent (Serial port){
  String ris = port.readStringUntil('\n');
  if (ris!=null){
    println("Letto:"+ris);
    brightness = float(ris);
    println("convertito:"+brightness );
  }else{
    println("dati incompleti, non ho letto nulla" );
  }
  }

Tra l'altro non vorrei che la "ris" contega ANCHE il carattere terminatore: quindi se invii "123\n" è ok perchè la conversione si occupa del \n, stesso vale per \r e probabilmente \t, ma non lo fa per M il 99% degli altri caratteri.

Manda la stringa ris

236 e' il valore attuale del potenziometro:

con '\n'

Letto:236
convertito:236.0
236.0
236.0
236.0

con 'M'

Letto:236M
convertito:NaN
NaN
NaN
NaN

interessante che con '\a' non copila nemmeno:

processing.app.SketchException: unexpected char: 'a'
    at processing.mode.java.JavaBuild.preprocess(JavaBuild.java:353)
    at processing.mode.java.JavaBuild.preprocess(JavaBuild.java:197)
    at processing.mode.java.JavaBuild.build(JavaBuild.java:156)
    at processing.mode.java.JavaBuild.build(JavaBuild.java:135)
    at processing.mode.java.JavaMode.handleRun(JavaMode.java:176)
    at processing.mode.java.JavaEditor$20.run(JavaEditor.java:481)
    at java.lang.Thread.run(Thread.java:662)

come immaginavo, non viene eliminata dalla stringa il carattere terminatore. Nel caso di \n, \r e \t viene eliminato in automatico con una trim(), ma la M invece rimane, e devi toglierla a mano.

quindi prima della conversione

ris = ris.substring(0, ris.length-1); //elimina l'ultimo carattere

e vedrai che magicamente tutto si risolve

'\a' in java non esiste: http://docs.oracle.com/javase/tutorial/java/data/characters.html

cavolo, ora e' chiaro come la luce del sole :) c'e' da dire che Leo, nonostante abbia subito deto che non conosceva processing, gia' la pagina scorsa aveva "indovinato" che la M era difficile da convertire in numero :)

restano le finezze: ris = ris.substring(0, ris.length-1);

non compila, errore ris.length cannot be resolved or is not a field

ho provato a cercare in rete qualcosina ma non ne esco

thanks