Go Down

Topic: [Risolto] Connessione seriale non va sotto gli 800ms (Read 860 times) previous topic - next topic

mikelefree

Apr 16, 2019, 07:44 pm Last Edit: Apr 18, 2019, 01:15 pm by mikelefree
Salve a tutti!

Ho realizzato un progetto che risponde a degli input da seriale. Nello specifico, Arduino riceve un valore inviato con Java tramite seriale e attiva uno dei due relay presenti nel circuito e tutto funziona senza problemi.

L'unico limite e problema che non riesco a risolvere è la velocità di acquisizione del dato, non riesco a scendere sotto gli ~800 ms. Se invio più velocemente i dati, Arduino non reagisce.

Arduino è collegato tramite la porta USB presente sulla board stessa che utilizzo per alimentare, scrivere il codice e inviare i dati.

Il software Java potrebbe inviare i valori con intervalli di circa 50ms ma per renderlo funzionante con Arduino devo impostare un timeout di attesa di 800ms (max 790ms) scendendo di più non succede nulla.

È possibile che non si possa scendere sotto questa velocità? Cosa sbaglio?

Se servono altri dati o informazioni vi prego di chiedere, non so cosa potrebbe essere utile per permettervi di aiutarmi, grazie.

Standardoil

Mah..
Non saprei cosa chiederti...
Forse è troppo chiedere sorgente e schema?
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

-zef-

La mia sfera di cristallo dice che nel codice ci sono troppi delay che bloccano l'esecuzione del programma.... se non ci becca nemmeno stavolta la butto (la sfera intendo)   :smiley-mr-green:

mikelefree

Mah..
Non saprei cosa chiederti...
Forse è troppo chiedere sorgente e schema?

Assolutamente no, basta chiedere. ;)
Sotto la parte software che invia i dati in Java e il codice su Arduino.
Per lo schema, beh, non ho la versione digitale da mostrarvi, ma è molto semplice, ho collegato il modulo a due relay ai pin digitali 6 e 7 e nulla più.



La mia sfera di cristallo dice che nel codice ci sono troppi delay che bloccano l'esecuzione del programma.... se non ci becca nemmeno stavolta la butto (la sfera intendo)   :smiley-mr-green:
E mi sa che è arrivato il momento di buttarla!! Aahahahaha ma dai sarà servita in altre occasioni. ;)
Comunque nessun delay su Arduino come puoi vedere sotto.


Nel codice Java c'è il delay di 800ms perché come detto se scendo sotto questo intervallo di tempo Arduino non reagisce.

Grazie per le risposte


Questo il codice su Arduino
Code: [Select]

int r1 = 7;
int r2 = 6;
long intervallo,now;
String v = "";
int V;

void setup() {
  Serial.begin(9600);
  pinMode(r1, OUTPUT);
  pinMode(r2, OUTPUT);
  digitalWrite(r1, HIGH);
  digitalWrite(r2, HIGH);
}

void loop() {
  now = millis();
  if (Serial.available() > 0) {
    v = Serial.readString();
    V = v.toInt();
    if(V > 0 ){
      if(V > 12 ){
        digitalWrite(r1,HIGH);
        digitalWrite(r2,LOW);
        intervallo = now;
      } else{
        if(V > 3 ){
          digitalWrite(r1,LOW);
          digitalWrite(r2,HIGH);
          intervallo = now;
        } else {
          digitalWrite(r1,HIGH);
          digitalWrite(r2,HIGH);
        }
      }
    }  
  }
}


Questa la parte di Java che invia il dato
Code: [Select]
String velocita=Float.toString(speed);
            
            arduino.serialWrite(velocita);
            System.out.println(velocita);
            TimeUnit.MILLISECONDS.sleep(800);

fabpolli

Magari non è questo il problema ma visto che trasmetti un solo valore alla volta potresti provare a sostituire la lettura da seriale dentro alla Stringa (classe String bleah!) e la successiva conversione con questo codice:
Code: [Select]

if (Serial.available() > 0) {
    V = Serial.parseInt();
    ...

Al momento now ed intervallo non vengono utilizzate ma visto che ci sono penso tu abbia idea di usarle in seguito, se non è così rimuovile, altrimenti il tipo è errato devi definirle unsigned long e non long.
Altra ottimizzazione le due variabili per i due pin puoi definirle come const oppure usare una #define

mikelefree

Magari non è questo il problema ma visto che trasmetti un solo valore alla volta potresti provare a sostituire la lettura da seriale dentro alla Stringa (classe String bleah!) e la successiva conversione con questo codice:
Code: [Select]

if (Serial.available() > 0) {
    V = Serial.parseInt();
    ...

Al momento now ed intervallo non vengono utilizzate ma visto che ci sono penso tu abbia idea di usarle in seguito, se non è così rimuovile, altrimenti il tipo è errato devi definirle unsigned long e non long.
Altra ottimizzazione le due variabili per i due pin puoi definirle come const oppure usare una #define
Grazie mille per la risposta.

Ho implementato l'utilizzo della funzione parseInt e lato PC ho convertito il valore da Float a Integer prima di inviarlo tramite seriale. Now e intervallo, ho dimenticato a toglierle, mi serviranno in futuro. Grazie per i consigli di ottimizzazione.

Il problema persiste purtroppo. Se scendo sotto gli 800ms non ho nessuna reazione da Arduino.


Arduino

Code: [Select]
const int r1 = 7;
const int r2 = 6;
int V;

void setup() {
  Serial.begin(9600);
  pinMode(r1, OUTPUT);
  pinMode(r2, OUTPUT);
  digitalWrite(r1, HIGH);
  digitalWrite(r2, HIGH);
}

void loop() {
  if (Serial.available() > 0) {
    V = Serial.parseInt();
    if(V > 0 ){
      if(V > 12 ){
        digitalWrite(r1,HIGH);
        digitalWrite(r2,LOW);
      } else{
        if(V > 2 ){
          digitalWrite(r1,LOW);
          digitalWrite(r2,HIGH);
        } else {
          digitalWrite(r1,HIGH);
          digitalWrite(r2,HIGH);
        }
      }
    } 
  }
}


Lato PC

Code: [Select]
int v;
v = Math.round(speed);
String velocita=Integer.toString((int)v);
arduino.serialWrite(velocita);

fabpolli

Qual' è il valore massimo e minimo che velocità può assumere?

mikelefree

Da 0 a 40 in casi estremi. Il valore durante l'utilizzo oscilla tra 8 e 25.

fabpolli

Ok, se da Java invii non due caratteri (Es. 2 e 5 per 25) ma invii il valore 25 e lato Arduino leggendo il singolo byte a questo punto lo casti come byte e lo uti tal quale dovresti ottenere la massima velocità possibile, anche perché inviado e ricevendo un singolo byte scendere sotto tale unità è praticamente impossibile, a quel punto lettura ed esecuzione codice non possono proprio impiegare così tanto tempo.

mikelefree

Ho appena provato da monitor seriale di Arduino ad inviare velocemente degli input numerici e Arduino risponde istantaneamente.

Provo subito!

docdoc

#10
Apr 17, 2019, 01:50 pm Last Edit: Apr 17, 2019, 01:51 pm by docdoc
Mah, scusate ma ho qualche perplessità su tutto ciò...

A 9600 baud sono circa 900 byte al secondo, d'accordo che non c'è handshake hardware ed il buffer lato Arduino è relativamente piccolo, ma non vedo proprio come mandare 2 caratteri possa essere limitato a 800 ms quindi circa 400ms a carattere, come se la seriale fosse a 25 baud!

Allora, a parte evitare le "String" lato Arduino come fosse kriptonite per Superman, non conosco Java (ma esiste una ".serialWrite()" o è una tua funzione?) ma quello che vedo è che ti MANCA UN TERMINATORE! Se tu mandi due valori, diciamo 6 e 8, come li distingui da "68"? Oppure se stai mandando 84 e nel buffer è arrivato solamente la prima cifra "8"?

Ad esempio diciamo mettendo il classico LF (ma il discorso va bene con qualsiasi carattere, anche "|") qualcosa del tipo:
Code: [Select]
String velocita=Integer.toString((int)v);
arduino.serialWrite(velocita + "\n");

e quindi in Arduino aspettare che ci sia il terminatore prima di acquisire il valore.
Se tu hai fatto prove con il Monitor Seriale attento che quello accumula i caratteri digitati e li manda tutti insieme (più il Line Feed...) per cui non è la stessa cosa.

Oppure puoi mandare sempre 2 caratteri (quindi non "8" ma "08") per cui basta attendere che Serial.available() sia uguale a 2, e leggere i caratteri e convertirli in intero.

Ma, meglio ancora, puoi farlo usando un byte visto che l'intervallo dei valori interi è compatibile con un char, e visto che si tratta di un dialogo tra macchine e non con un umano, è sempre meglio progettare i propri protocollini in modo che sia tutto più agevole per le macchine...

Quindi concordo con il suggerimento di fabpolli, che ti evita persino il discorso del terminatore in quanto il pacchetto è di lunghezza fissa (1 char ossia 1 unsigned byte)...

PS poi se la seriale la metti ad una velocità maggiore, diciamo anche "solo" 38400 hai tanta di quella banda che potresti usarla anche per ben altro... ;)
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

-zef-

Prova anche in setup a modificare il parametro Serial.setTimeout() che di default è un po' altino

mikelefree

Prova anche in setup a modificare il parametro Serial.setTimeout() che di default è un po' altino
EUREKA!!  :D  :D  :D  :D

Una cosa così semplice eppure fondamentale! Errore mio a non aver controllato le funzioni relative alla seriale, unica cosa che posso dire in mia discolpa è che non avrei mai pensato ad una configurazione standard da 1s di attesa per la seriale.

Grazie a tutti per le risposte comunque costruttive e utili!!  :smiley-wink:

Grazie specialmente a fabpolli e docdoc per le ottimizzazioni suggerite!

fabpolli

Permettimi di dissentire dal tuo eureka, e ti spiego il perché... quello che a te sembra la soluzione è un semplice workaround per mettere una pezza ad un malfunzionamento di base del software come ti ha descritto nel dettaglio @docdoc
E' chiaro che se esiste tale parametro c'è un perché ma non è quello di terminare la lettura al posto tuo, abbassando il timeout hai aggirato l'ostacolo, resta il fatto che c'è un bug di fondo, è un po' come usare il watchdog per sbloccare programmi che si bloccano per colpa di come sono scritti e non per quello per cui è nato (ovvero sopperire a anomalie non predicibili), per carità sembra che sia la soluzione ma in realtà non lo è, è solo un modo per "mettere la testa sotto la sabbia".
Per carità, non prenderla come un attacco personale rivolto a te, se funziona come vuoi e non ti interessa migliorare il programma... a posto felice tu e anche io ma la vera soluzione l'ha indicata @docdoc ovvero inseriere il terminatore (Es. CR+LF come fa il monito seriale se non differentemente configurato), leggere due caratteri ed uscire ecc..
E te ne dico anche un'altra, se il programma è destianto a girare per molto tempo l'uso della classe String ti porterà con buone probabilità a sperimentare blocchi imprevisti e casuali da cui difficilmente ne uscirai fuori (come più volte indicato sul forum) se non eliminando l'uso di tale classe e tornare a leggere un byte alla volta, che vada in un interno o in un array di char poco importa.
Questo pippone che ho scritto che potrebbe sembrare innutile, forse arrogante, non è rivolto a te (come già detto) ma pittosto per far capire a eventuali altri frequentatori che in futuro potrebbero imbattersi in questo topic segnato come risolto, che la "soluzione" adottata non è proprio la migliore, anzi.


ORSO2001

scusate se m'intrometto per dire la mia, sempre non per critica ma per, se possibile, aggiunger un concetto in più.
Premetto che sottoscrivo in toto quanto scritto da fabpolli e docdoc.
Come detto da fabpolli il ridurre il time out è un accrocchio per aggirare il problema e non una vera e buona soluzione; generalmente questo tipo di soluzioni, gli accrocchi, vengono prese quando a "realizzazione concettuale" del progetto non si verifica/valuta bene su cosa si sta lavorando e che device si utilizzeranno...per fare il classico degli esempi:
PC <-> PC classe String OK
PC<->Arduino  classe String NO
Arduino <-> Arduino classe String NO.
Se c'è necessità di scambio dati tra due device posso utilizzare protocolli standard, che sono conosciuti, collaudati solidi etc...oppure devo farmi io il mio...e se devo farmi il mio cosa devo considerare:
ci saranno più info nella stessa stringa?...se si come li distinguo?
come capisco che la stringa inizia e finisce?
come capisco se la stringa letta corrisponde a quella passata?
etc etc
La buona pianificazione di un progetto a volte ti evita la completa riscrittura del codice prodotto...ne migliora la manutentabilità...e magari lo rende tutto od in parte riutilizzabile per altri progetti.
Scusate il pippotto ma necessitavo di un po' di formaggio...dalle mie parti c'è un detto "xe rivà queo del formajo" (traduzione concettuale e contestualizzata -> ha parlato quello che sa tutto)...ciao

Go Up