Rilievo velocità di passaggio con LiDAR - Problema!!

Buonasera,
sto cercando di sviluppare un sistema di cronometraggio automatico per l’allenamento nello sport del curling: il sistema sarà basato su tre stazioni, che rilevano il passaggio della stone e trasmettono il relativo impulso al sistema remoto di cronometraggio, tramite transponder radio Xbee.

Il primo prototipo di “stazione di rilevamento” è costituito da un Adafruit Trinket Pro 3V/12MHz, che legge (dovrebbe leggere…) la distanza misurata dal LiDAR Benewake TFo2 Pro, connesso tramite porta seriale al microcontrollore e, se la distanza è compresa tra due limiti, minimo e massimo), accende un led e pone in HIGH un pin che sarò collegato all’Xbee in DirectIO, per poi spegnere il led (e mettere in LOW il pin Xbee) quando l’oggetto non è più rilevato.

Il problema è che non riesco a far funzionare il codice: per debuggare il sistema ho collegato un display 7 segment al Trinket Pro (che non ha la possibilità di uscire sul monitor seriale della IDE Arduino), in modo che visualizzi a ogni ciclo while la lettura della distanza effettuata dal LiDAR; il risultato è che all’accensione vedo la prima lettura e poi il sistema si blocca…

Non riesco a capire perché… qualcuno riesce ad aiutarmi?!

Grazie mille
Fabrizio

/*
Gate1 cronometro automatico per il curling, basato LiDAR TF02Pro, microcontrollore Adafruit Trinket Pro e Xbee
*/

#include <SoftwareSerial.h>
#include <SevSegFloat.h>

int Pin_XBee1 = 4;                        // Pin collegato con il Pin Xbee DI0 per il DirectIO
int Pin_LedStart = A3;                    // Pin del Led che segnala il rilevamento

int dist;                                 // distanza misurata dal LiDAR
int strength;                             // forza del segnale LiDAR
int check;                                // check numerical value storage
int i;
int uart[9];                              // vettore dei dati misurati dal LiDAR
const int HEADER = 0x59;                  // data package frame header

const int LimiteMIN = 10;                 // distanza inferiore della porta di rilevamento
const int LimiteMAX = 30;                 // distanza superiore della porta di rilevamento

// apre una porta seriale virtuale per il display 7 segment, sui pin definiti per Tx e Rx
const int softwareTx = 11;
const int softwareRx = 12;
SoftwareSerial s7s(softwareRx, softwareTx);               

// crea un'istanza di SevSegFloat sullo stream sulla porta s7s, chiamato SevSeg
SevSegFloat SevSeg(s7s);

void setup() {

Serial.begin(115200);
s7s.begin(9600);
delay(100);                              // Give port time to initalize

pinMode(Pin_XBee1, OUTPUT);
pinMode(Pin_LedStart, OUTPUT);

clearDisplay();                         // Cancella il display
//setDecimals(0b00000100);                // Sets digit 3 decimal on
setBrightness(127);                     // Medium brightness
delay(1500);

s7s.print("----");
delay(800);

//SevSeg.send(0.0);

for (int i = 0; i < 5; i++) {
 digitalWrite(Pin_LedStart, HIGH);
 delay(100);
 digitalWrite(Pin_LedStart, LOW);
 delay(100);
}

digitalWrite(Pin_XBee1, LOW);

}

void loop() {

Serial.begin(115200);
delay(100);                              // Give port time to initalize

// Routine di lettura del rilevamento LiDAR sulla porta seriale

while (dist < LimiteMIN || dist > LimiteMAX) {

 if (Serial.read() == HEADER)         // determine data package frame header 0x59
 {
   uart[0] = HEADER;
   if (Serial.read() == HEADER)       //determine data package frame header 0x59
   {
     uart[1] = HEADER; for (i = 2; i < 9; i++)      // store data to array
     {
       uart[i] = Serial.read();
     }

     check = uart[0] + uart[1] + uart[2] + uart[3] + uart[4] + uart[5] + uart[6] + uart[7];

     if (uart[8] == (check & 0xff))                // check the received data as per protocols
     {
       dist = uart[2] + uart[3] * 256;             // calculate distance value
       // strength = uart[4] + uart[5] * 256;      // calculate signal strength value
       SevSeg.send(dist);                          //visualizza la distanza sul 7 segment
     }
   }
 }

}

digitalWrite(Pin_XBee1, HIGH);
digitalWrite(Pin_LedStart, HIGH);

while (dist >= LimiteMIN && dist <= LimiteMAX) {

 if (Serial.read() == HEADER)                      // determine data package frame header 0x59
 {
   uart[0] = HEADER;
   if (Serial.read() == HEADER)                    //determine data package frame header 0x59
   {
     uart[1] = HEADER; for (i = 2; i < 9; i++)     // store data to array
     {
       uart[i] = Serial.read();
     }

     check = uart[0] + uart[1] + uart[2] + uart[3] + uart[4] + uart[5] + uart[6] + uart[7];

     if (uart[8] == (check & 0xff))                // check the received data as per protocols
     {
       dist = uart[2] + uart[3] * 256;             // calculate distance value
       // strength = uart[4] + uart[5] * 256;      // calculate signal strength value
       SevSeg.send(dist);                          // visualizza la distanza sul 7 segment
     }
   }
 }

}

digitalWrite(Pin_XBee1, LOW);
digitalWrite(Pin_LedStart, LOW);

delay(3000);

Serial.flush();
Serial.end();

for (int i = 0; i < 3; i++) {
 digitalWrite(Pin_LedStart, HIGH);
 delay(50);
 digitalWrite(Pin_LedStart, LOW);
 delay(50);
}
}




//  Manda al display il commando (0x76) che cancella il display e resetta il cursore
void clearDisplay()
{
s7s.write(0x76);
}


//  Regola la luminosità del display. Deve ricevere un byte con il valore della luminosità
//  scuro = 0 ------- 127 -------> 255 = luminoso
void setBrightness(byte value)
{
s7s.write(0x7A);  // comando di regolazione della luminosità
s7s.write(value);  // byte con il valore di luminosità
}


//  Turn on any, none, or all of the decimals.
//  The six lowest bits in the decimals parameter sets a decimal
//  (or colon, or apostrophe) on or off. A 1 indicates on, 0 off.
//  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
void setDecimals(byte decimals)
{
s7s.write(0x77);
s7s.write(decimals);
}

Gate1_TF02Pro_Xbee.ino (4.83 KB)

Buonasera e benvenuto :slight_smile: ,
essendo il tuo primo post nella sezione Italiana del forum, nel rispetto del regolamento di detta sezione (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione … possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO

… poi, in conformità al suddetto regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More → Modify che si trova in basso a destra del tuo post) e racchiudere il codice all’interno dei tag CODE (… sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread e sistemato il codice come da regolamento, nessuno ti potrà rispondere, quindi ti consiglio di fare il tutto al più presto. :wink:
P.P.S.: … e dopo aver postato, rileggete SEMPRE i vostri post … così vi accorgete di ciò che succede!

Grazie dei suggerimenti, Guglielmo.
Spero di aver fatto tutto bene, coerentemente con il regolamento.

Un saluto
Fabrizio

Allora, un paio di cose che vedo dando un'occhiata "preliminare" (devo uscire tra poco..).

Primo, l'indentazione. Lo diciamo quasi sempre: per rendere più comodamente leggibile il codice a te ma anche a noi, indenta! Premi Ctrl-T nell'IDE e te lo fa lui.

Secondo, perché inizializzi la seriale nel loop?

Terzo, quando leggi dalla seriale non fare Serial.read() senza sapere prima se ci sono caratteri nel buffer usando Serial.available(), altrimenti ti torna -1.

Quarto, se nel loop fai un Serial.read() dentro ad una "if" il carattere letto lo perdi definitivamente. Ok che lo confronti con un valore, ma ti conviene sempre memorizzarlo in una variabile byte e poi farci quello che ti serve. Oppure, meglio, se quello che devi ricevere è in qualche modo "articolato", ti basta definire una variabile globale char come buffer, ed accumulare lì i caratteri ricevuti, e vedere se nel buffer hai ricevuto i caratteri iniziali del pacchetto ed almeno il numero di byte del pacchetto. Quando tutto è pronto, allora leggi i dati del pacchetto e ci fai quello che ti serve.

Quinto, non ti conviene in genere mettere cicli while nella loop, sia perché la loop è già lei un ciclo, sia perché la cosa migliore è sempre gestire in modo "asincrono" le cose, ossia nel loop avrai una prima if() che testa Serial.available() e se è diverso da zero leggi i caratteri dalla seriale al tuo buffer e termini la if. Poi un'altra if() verifica se il buffer contiene i due header ed è lungo almeno 8 byte, ed in caso affermativo significa che il pacchetto è completo e quindi fai quello che devi fare. Senza neanche aggiungere altri inutili delay().

Prova e fammi sapere...

Grazie della risposta,
appena riesco (ora sto scappando) cerco di capire bene i consigli che mi hai dato... purtroppo la mia esperienza con la programmazione è minima).
L'unica cosa che aggiungo è che la stessa struttura del codice, provato ieri su m5StickC Pro funziona perfettamente! Sembrerebbe esserci qualcosa nella lettura seriale del Trinket Pro che impedisce il corretto funzionamento.

Grazie ancora dei consigli
Fabrizio

Provo a rispondere a ciò che hai evidenziato:

Primo, l'indentazione. Lo diciamo quasi sempre: per rendere più comodamente leggibile il codice a te ma anche a noi, indenta! Premi Ctrl-T nell'IDE e te lo fa lui.

In realtà nell'IDE ho usato la formattazione automatica, lo faccio sempre, ma questa è stata rimossa nell'operazione di copia e incolla (probabilmente perché non conoscevo l'uso dei tag CODE.

Secondo, perché inizializzi la seriale nel loop?

Da alcune prove che avevo fatto con un ESP32, utilizzando un'alta frequenza di campionamento per il Lidar (1000 Hz) avevo dedotto che fosse necessario chiudere e re-inizializzare la seriale od ogni ciclo, pena una sorta di "intasamento"

Terzo, quando leggi dalla seriale non fare Serial.read() senza sapere prima se ci sono caratteri nel buffer usando Serial.available(), altrimenti ti torna -1.

Inizialmente, sempre nelle prove con altro microcontrollore, avevo inserito un Serial.available() ma l'ho poi eliminato, vedendo che funzionava ugualmente, probabilmente perché dal sensore arriva un flusso continuo di dati, con un campionamento elevato. Dovendo fare un sistema di cronometraggio, nel quale anche il centesimo di secondo conta, pensavo che meno istruzioni uso meglio è...

Quarto, se nel loop fai un Serial.read() dentro ad una "if" il carattere letto lo perdi definitivamente. Ok che lo confronti con un valore, ma ti conviene sempre memorizzarlo in una variabile byte e poi farci quello che ti serve. Oppure, meglio, se quello che devi ricevere è in qualche modo "articolato", ti basta definire una variabile globale char come buffer, ed accumulare lì i caratteri ricevuti, e vedere se nel buffer hai ricevuto i caratteri iniziali del pacchetto ed almeno il numero di byte del pacchetto. Quando tutto è pronto, allora leggi i dati del pacchetto e ci fai quello che ti serve.

Come dicevo sopra, ho la necessità di far sì che il tutto si svolga senza perdite di tempo e pensavo fosse un bene che le istruzioni fossero il minor numero possibile. Ma non so se sia effettivamente necessario...

Quinto, non ti conviene in genere mettere cicli while nella loop, sia perché la loop è già lei un ciclo, sia perché la cosa migliore è sempre gestire in modo "asincrono" le cose, ossia nel loop avrai una prima if() che testa Serial.available() e se è diverso da zero leggi i caratteri dalla seriale al tuo buffer e termini la if. Poi un'altra if() verifica se il buffer contiene i due header ed è lungo almeno 8 byte, ed in caso affermativo significa che il pacchetto è completo e quindi fai quello che devi fare. Senza neanche aggiungere altri inutili delay().

Provo a strutturare la verifica del passaggio in questo modo :wink:

Grazie!

Come scrivevo sopra lo stesso codice ( o quasi, almeno mi sembra, lo allego) su un M5StickC Plus funziona, cioè legge correttamente le distanze rilevate dal LiDAR dalla seriale e mi consente quindi di rilevare il tempo e di stimare la velocità di passaggio… per quale motivo?!?

Prova_TF02_Pro_M5StickCPlus.ino (7.65 KB)

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.