Programma non funziona senza Serial.print()

Ciao a tutti,

sto lavorando ad un progetto abbastanza ambizioso che richiede anche un codice di path finding.

Ho elaborato una prima versione del programma che sembrerebbe funzionare (per ora l'ho provata solo su una mappa piccola). Il problema è che dal momento che disattivo i vari Serial.print() impostando la variabile debug su false, il programma non funziona più, secondo voi cosa sto sbagliando?

Sto utilizzando due SRAM esterne 23K256 per memorizzare la mappa e le informazioni necessarie per il path finding, nessun altro componente è collegato all'Arduino UNO per ora.

Lascio il file col codice completo, cosi chi volesse può prendere spunto.
Lascio anche gli screenshot delle schermate del monitor seriale e la libreria che sto usando.

navigation_test.ino (11.1 KB)

SRAM.zip (6.89 KB)

Credo dovrai dare più dettagli sul cosa non funziona perché la tua variabile debug non fa altro che disattivare alcuni messaggi e attivarne altri, se escludiamo il delay di 100ms nella funzione findLowestF il resto non può (in teoria) impattare sul funzionamento del programma, ma devi chiarire meglio cosa non funziona

TimoFran:
Il problema è che dal momento che disattivo i vari Serial.print() impostando la variabile debug su false, il programma non funziona più, secondo voi cosa sto sbagliando?

Come già detto da fabpolli, non ci è chiaro cosa tu intenda con "non funziona" ma guardando gli screenshot (se ti capita puoi anche fare copia/incolla del testo contenuto...) sembra che con debug off vada in loop mostrando X e Y, che mostra solo se debug è off, ma non si capisce più sotto cosa succeda: è in un loop infinito o succede altro? Non dà il risultato? Dà un risultato sbagliato? Altro?
E comunque anche io non vedo alcun punto in cui la presenza del debug possa fare cose diverse da qualche Serial.print().

In ogni caso non capisco bene alcune cose del tuo codice.
Intanto perché una costante e non una #define che poi userai per NON compilare affatto il codice di debug con #ifdef?
Ossia invece di:

const bool PROGMEM debug = true;
...
   if(debug==true){
     Serial.print(F("lowestFID: "));
     Serial.println(lowestFID);
   }
...

fai:

#define DEBUG
...
#ifdef DEBUG
      Serial.print(F("lowestFID: "));
      Serial.println(lowestFID);
#endif

a quel punto se lasci la #define ti compilerà il codice con le print di debug, se la commenti non includerà il codice, che sarà anche più compatto. E comunque una bool, che è solo 1 byte, in PROGMEM mi pare sparare col cannone su una mosca.. :wink:

Poi se la navigazione la devi eseguire solo una volta, perché metterla nel loop() facendola poi finire con una "while(1)", invece di metterla nella setup() (o, meglio, metterla in una funzione "naviga()" che richiami nella setup)???

Ed infine io in genere preferisco impostare la Serial a 115200 soprattutto se devo mostrare varie cose, almeno le print influiscono poco sulle tempistiche generali.

docdoc:
... E comunque una bool, che è solo 1 byte, in PROGMEM mi pare sparare col cannone su una mosca.. :wink:

Non solo, le variabili (... non ho però verificato cosa avviene con le const, probabilmente ignora proprio la cosa) messe in PROGMEM NON le puoi usare così direttamente ma le devi andare a recuperare con le apposite funzioni che leggono i valori da PROGMEM (es. pgm_read_byte())!!!

Credo comumque che il fatto di aver messo "const" già dica al compilatore come comportarsi e credo ignori il PROGMEM, ma tratti la cosa in altro modo ... ::slight_smile:

Guglielmo

docdoc:
Intanto perché una costante e non una #define che poi userai per NON compilare affatto il codice di debug con #ifdef?

Grazie del consiglio, lo faccio subito.

Comunque per essere più preciso:
Con debug messo su true, il percorso viene calcolato correttamente (file true.txt), mentre se imposto la variabile su false (false.txt)il codice entra in un loop infinito e non riesce a dare un risultato.

false.txt (24.4 KB)

true.txt (8.43 KB)

Non ho presente l'algoritmo di visita che stai implementando, ma oltre a cambiare la variabile debug in #define ti direi intanto leva tutti quei PROGMEM dalle const byte, abbastanza inutili (e forse dannosi se non gestiti correttamente).

Poi con il debug il tempo di elaborazione mi pare elevato considerato che la mappa è relativamente piccola (oltre 8 secondi!): dato che l'output è di circa 8k byte, a 9600 baud (che sono circa 960 byte al secondo) il solo l'output seriale richiede proprio circa 8 secondi! Porta a 115200 la seriale, evitiamo ritardi inutili e forse già questo dovrebbe aiutare.

Poi non ho analizzato il tuo algoritmo, ma prova a togliere tutta la if(debug==false) (quindi non far scrivere mai X ed Y su seriale) e vedi se anche senza debug trova il risultato.

EDIT: Aggiungo, se vuoi anche compattare il codice, puoi fare varie cosette, come ad esempio invece di:

  • while(trovato==false) {*
    basta fare:
  • while(!trovato) {*
    ed in generale in tutte le condizioni che riguardano valori booleani puoi evitare "==true", ad esempio in:

* *      if(checkCellForOpenList(adiacenti[i][1],adiacenti[i][2])==true) {* *

basta anche solo:

* *      if(checkCellForOpenList(adiacenti[i][1],adiacenti[i][2])) {* *

Poi dentro a quella while vedo che (a parte il dettaglio che le graffe sono inutili in questo caso) fai:

  • if(openX == goalX && openY == goalY) {trovato=true;}*
    ma poi non esci e prosegui: è voluto?
    Come detto, non so come sia l'algoritmo, ma se hai raggiunto il goal, perché non esci dalla while() ma continui ad eseguire fino alla fine, per poi uscire? O testare quella condizione solo dopo aver eseguito il resto?
    Potresti anche non usare affatto una variabile per uscire, puoi fare:
  • while(1) {*
    ...
  • if(openX == goalX && openY == goalY) break;*
    ...
  • }*

Ho apportato le modifiche che mi avete consigliato (lascio il file nuovo allegato), effettivamente adesso con il baud rate a 115200 fa tutto in poco più di un secondo.

Il codice non funziona neancora se il debug viene disattivato, non capisco proprio come sia possibile.

Provo a cambiare libreria e vediamo cosa succede.

EDIT:
Utilizzando una libreria diversa il codice non funziona comunque

navigation_test.ino (11.1 KB)

Analizzando l'output con debug=false noto una cosa interessante. Mi chiedevo come mai col debug a false la scrittura di X ed Y finisca prima a "bloccarsi" apparentemente su 2,4 senza passare a 2,5 (che è libero) e dopo parecchi cicli vada a "saltare" a 0,0 ossia fuori dal perimetro e subito dopo "bloccarsi" su 0,1!

Contando il numero di cicli dopo "Inizio navigazione" vedo che si "resetta" su 0,0 esattamente dopo 128 cicli! Ti suona familiare questo valore? :wink: C'è qualche valore intero che "sballa".

Vedo nel codice che oltre ai PROGMEM che non mi convincono, anche varie variabili loali definite "static" senza alcun motivo. Ad esempio:

int cellToAddress(byte X, byte Y) {

  static int indirizzo;
  
  indirizzo = (Y-1) * maxX;
  
  return(indirizzo + X);
  
}

Mi pare tutto inutile, basta fare:

int cellToAddress(byte X, byte Y) {
  
  return((Y-1) * maxX + X);
  
}

Ma non solo per il discorso dell'inutile variabile statica (variabili locali statiche occupano memoria come variabili globali, quindi se non è necessario che mantengano il valore tra una chiamata e l'altra, le si lascia non statiche ossia allocate di volta in volta): se Y può essere anche zero, questo mi pare sbagliato! Tu hai una mappa dove le coordinate vanno da 0 a 9, d'accordo che tu hai messo le "pareti" da (1,1), ma quando, per ragioni che ancora mi sfuggono, il codice passa a 0,0 (come si vede quando debug=false) questa cosa va a calcolare indirizzi del tutto sballati (quantomeno se Y=0)!!!

Vedi un poco di capire meglio questa cosa, verifica che da nessuna parte ci sia una coordinata a zero, e ti consiglierei di togliere tutte quelle inutili static dove possibile, e le altre lasciarle non statiche togliendo la keyword "static".

TimoFran:
Il codice non funziona neancora se il debug viene disattivato, non capisco proprio come sia possibile.

Ora vedo che hai lasciato le Serial.print() di X ed Y: con debug non attivo che succede?
Puoi allegare i nuovi output con e senza debug?

docdoc:
Ora vedo che hai lasciato le Serial.print() di X ed Y: con debug non attivo che succede?

Le ho lasciate per vedere se il codice va avanti.

Nei debug che ho allegato ho tolto anche quelle. Il codice continua ad andare in loop infinito bloccandosi sulla solita cella della mappa.

debug attivo.txt (7.13 KB)

debug spento.txt (176 Bytes)

>TimoFran: ... ti sconsiglio caldamente di utilizzare attributi che NON consci a fondo (es. PROGMEM, static, ecc.) senza avreli prima studiati, capiti ed aver compreso i casi di utilizzo.

Invece di migliorare le cose, le peggiori ed introduci problemi molto difficili da diagnosticare.

Guglielmo

Ho provato anche a non utilizzare quegli attributi, ma il problema si presenta comunque.

Adesso li ho tolti. Se necessari li rimetterò dopo aver approfondito l'argomento

docdoc:
Vedo nel codice che oltre ai PROGMEM che non mi convincono, anche varie variabili loali definite "static" senza alcun motivo. Ad esempio:

int cellToAddress(byte X, byte Y) {

static int indirizzo;
 
 indirizzo = (Y-1) * maxX;
 
 return(indirizzo + X);
 
}




Mi pare tutto inutile, basta fare:


int cellToAddress(byte X, byte Y) {
 
 return((Y-1) * maxX + X);
 
}

Avevo letto che dopo molti cicli si potrebbe avere un problema di overflow della RAM e che questo problema poteva essere limitato dichiarando come statiche alcune variabili, ancora una volta dovevo informarmi meglio.

Riguardo al fatto di andare fuori dalla mappa, probabilmente dipende dal fatto che quando volevo cancellare una cella dalla lista (clearOpenList(int ID)) le davo coordinate 0,0. Ho provato quindi a modificare questa parte del codice facendo si che dia coordinate 2,2 ma non funziona comunque con debug disattivato.

TimoFran:
Nei debug che ho allegato ho tolto anche quelle. Il codice continua ad andare in loop infinito bloccandosi sulla solita cella della mappa.

Se non vedi X e Y come puoi saperlo? Comunque sia, togli i PROGMEM e tutti gli static, poi fallo girare rimettendo la stampa di X e Y indipendentemente dal debug e posta i nuovi output e sketch così vediamo.

Ecco il nuovo codice e gli output

debug attivo.txt (10.7 KB)

debug spento.txt (55.7 KB)

navigation_test.ino (11.1 KB)

Ok, ho spostato ad inizio codice la dichiarazione di due variabili (closedX e closedY) che prima dichiaravo sopra la funzione che le utilizzava, adesso il codice funziona anche con debug disattivato.

Però succede una cosa abbastanza strana... quando metto il punto di partenza alle coordinate 2,2 tutto funziona normalmente. Ma se imposto come punto di partenza un'altra coordinata (ad esempio 7,2) succede una cosa strana che si vede nell'output seriale, ovvero parte da quella coordinata ma poi si sposta sulla vecchia coordinata 2,2.

Ho provato anche a scollegare la scheda o ricollegarla subito prima di far partire lo sketch cosi da "svuotare" le due sram ma il risultato non cambia.

Ho aggiunto anche un delay nel setup ed un sistema per interrompere la navigazione dopo 5 secondi (che comunque non entra in funzione perché il codice termina prima).

2-2.txt (860 Bytes)

7-2.txt (2.55 KB)

navigation_test.ino (11.8 KB)

TimoFran:
Ok, ho spostato ad inizio codice la dichiarazione di due variabili (closedX e closedY) che prima dichiaravo sopra la funzione che le utilizzava, adesso il codice funziona anche con debug disattivato.

Ti direi "e allora lascia le cose come stanno" :wink: ma, battute a parte, non mi convince lo stesso. O, meglio, mi convince ancora di più che c'è qualcosa che "pasticcia" con la memoria...

Ma tu hai usato quei PROGMEM perché avevi segnalazione di memoria quasi piena, o cosa? Puoi postare l'output di una compilazione (il contenuto del pannellino nero sotto al codice)?
E puoi dirmi esattamente quale libreria sram usi (in Gestione librerie ce ne sono svariate, e due che citano esplicitamente il 23K256)?

Però succede una cosa abbastanza strana... quando metto il punto di partenza alle coordinate 2,2 tutto funziona normalmente. Ma se imposto come punto di partenza un'altra coordinata (ad esempio 7,2) succede una cosa strana che si vede nell'output seriale, ovvero parte da quella coordinata ma poi si sposta sulla vecchia coordinata 2,2.

Non esattamente. Fa un percorso "strano" (assumo che i pesi dei percorsi siano tutti uguali) ossia prima si muove correttamente in basso:
X: 7 Y: 2
X: 7 Y: 3
X: 7 Y: 4
X: 7 Y: 5
poi però scende ancora mentre mi aspettavo che andasse a (6,5)
X: 7 Y: 6
poi va in diagonale (ma è ammesso?), andando per di più in direzione opposta al target:
X: 8 Y: 5
a questo punto non può far altro che salire (immagino che sia impostato per non passare due volte alle stesse coordinate):
X: 8 Y: 4
poi si "teletrasporta" a (7,7):
X: 7 Y: 7
cerca di nuovo di risalire ma nella direzione sbagliata:
X: 8 Y: 6
e da ora va completamente "in palla" con un altro "teletrasporto" a coordinata impossibile, tra l'altro già occupata all'inizio, dove resta per un centinaio di cicli (a fare cosa non è dato sapere, forse c'è una discoteca...):
X: 7 Y: 2
X: 7 Y: 2
...
X: 7 Y: 2
e finalmente qui ora "sbuca" nella posizione libera (7,2) come se avesse "viaggiato" ancora in orizzontale, finendo a (2,2):
X: 2 Y: 2
e da qui finalmente arriva a destinazione con un percorso stranamente regolare:
X: 2 Y: 3
X: 2 Y: 4
X: 2 Y: 5
X: 2 Y: 6
X: 3 Y: 6
X: 4 Y: 6
X: 5 Y: 6
X: 5 Y: 5

Insomma, qui "qualquadra non cosa". :slight_smile: Da un lato c'è qualcosa di molto strano a livello di codice compilato che sembra "sballare" ogni tanto i valori (puntatori? Libreria SRAM che fa cose strane? Uso non corretto della libreria?), dall'altro temo che sia l'implementazione dell'algoritmo che ha qualche cosa che non va (ma per questo devi per forza verificarlo tu, perché anche se mi intrigherebbe, non ho tempo per mettermi pure a studiare questa cosa, dopo aver cercato di capire anche se genericamente il tuo codice :wink: )

docdoc:
Ma tu hai usato quei PROGMEM perché avevi segnalazione di memoria quasi piena, o cosa? Puoi postare l'output di una compilazione (il contenuto del pannellino nero sotto al codice)?

[...]

E puoi dirmi esattamente quale libreria sram usi (in Gestione librerie ce ne sono svariate, e due che citano esplicitamente il 23K256)?

Ho usato i progmem perché questa è solo una parte del codice completo del robot (che ho separato per verificare solo la parte di path finding senza coinvolgere motori, sensori, etc.) e in quel codice completo avevo problemi di memoria (che comunque sto risolvendo rimuovendo i PROGMEM via via e passando a schede più performanti).

Lascio qui sotto le segnalazioni in rosso che da l'output della compilazione, l'output completo lo metto in allegato.

C:\Users\Timothy\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.17\cores\arduino\main.cpp: In function 'main':

C:\Users\Timothy\Desktop\navigation_test\navigation_test.ino:208:53: warning: iteration 3 invokes undefined behavior [-Waggressive-loop-optimizations]

       setAdiacente(adiacenti[i][1],adiacenti[i][2],i);

                                                     ^

C:\Users\Timothy\Desktop\navigation_test\navigation_test.ino:207:5: note: containing loop

     for(byte i = 1; i<=4;i++) {

     ^

C:\Users\Timothy\Desktop\navigation_test\navigation_test.ino:200:63: warning: iteration 3 invokes undefined behavior [-Waggressive-loop-optimizations]

       if(checkCellForOpenList(adiacenti[i][1],adiacenti[i][2])==true) {

                                                               ^

C:\Users\Timothy\Desktop\navigation_test\navigation_test.ino:199:5: note: containing loop

     for(byte i = 1; i<=4;i++) {

     ^

Per quanto riguarda la libreria, sto usando quella di panStamp (il primo risultato per "23K256" dal gestore librerie) (GitHub - panStamp/sram: Arduino library for SPI SRAM IC's).

P.S.

L'algoritmo di ricerca è l' A* PATH FINDING che ho rielaborato per renderlo utilizzabile su un Arduino ed in futuro su un AtMega.

debug output.txt (25 KB)

Negli errori ci sono due richiami al fatto che il codice produce un undefined behavior quindi non è determinabil cosa possa succedere credo perché tu hai definito

byte adiacenti[4][2];

e il for è definito fino a 4 che va oltre l'indice massimo la matrice che va da zero a tre

for(byte i = 1; i<=4;i++)

Ok ho risolto il problema, adesso il debug non da più errori.

Tuttavia continua a non lavorare come dovrebbe

debug output.txt (17.4 KB)

debug spento.txt (2.55 KB)

navigation_test.ino (11.8 KB)