Graficare un dato ricevuto da seriale in real-time

di il
8 risposte

Graficare un dato ricevuto da seriale in real-time

Salve a tutti.
Sto cercando di mostrare a grafico il dato che riceve da una porta seriale. Tramite il compilatore Atollic True Studio ho programmato un sensore (VL53L0X) di prossimità che invia il dato della distanza rilevata (data) tramite porta seriale al compilare Qt per creare l'interfaccia e quindi il grafico.

void MainWindow::readData()
{
    const QByteArray data = m_serial->readAll();
  //  qDebug()<<data;
    inviaData(data);
}
Facendo il qDebug si vede però che il dato non è pulito:
"200
0\n"
"1"
"999\n"
Quando il dato dovrebbe essere: "2000\n"
così mi hanno suggerito di farlo passare per una stringa e successivamente ripuirlo in modo da avere solo il numero

Nella funzione:

QByteArray charBuffer;

void MainWindow::inviaData(const QByteArray &data)
{
 QStringList List;
        QString ran;

        charBuffer.append(data);
        if (data.contains("\n"))
            {
                QString myString(charBuffer);
                List = myString.split(':');
                qDebug() << List <<sizeof (List) << endl;
                charBuffer = "";

                ran = (double)List[1];

            } else {
                return;
            }
           
            rand = ran.toDouble();
]
Ho creato List che stampa: ("2000 \n").
Qui viene il mio problema, come faccio a ripulirlo delle parentesi, virgolette ed \n per avere solo il dato puro?
Come faccio ad associare (usando qcustomplot, una estensione di Qt) data e il tempo come coordinate del grafico?
In realtà la coordinata x, con

 QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
        m_plot->xAxis->setTicker(timeTicker);
        timeTicker->setTimeFormat("%s");
gli associo il tempo come valore, solo non riesco ad associare entrambi i valori.
Chiedo scusa se sono stato prolisso ma spero di essere stato abbastanza chiaro.

8 Risposte

  • Re: Graficare un dato ricevuto da seriale in real-time

    Buongiorno,
    continuando a lavorarci sono riuscito a far plottare il dato che ricevo da seriale e a far scorrere l'asse x nel tempo. Il problema ora è che il dato che arriva è sporco, quindi mi sarebbe utile un suggerimento per ripulirlo e avere solo un double.
    
    void MainWindow::readData()
    {
       const QByteArray data = m_serial->readAll();
        double dada = data.toDouble();
        qDebug()<<data;
       // qDebug()<<dada;
        timerSlot(dada);
    }
    
    Facendo riferimento ai codici pubblicati in precedenza, ho in pratica eliminato tutta la funzione inviaData() creando un double dada a cui ho associato il mio dato sporco.
    Ho fatto questo perché avevo bisogno di riuscire a plottare il dato, anche se sporco, e assicurarmi che non andasse in crash il programma. Fatto questo, come posso fare per estrarre solo il numero dal QByteArray?
    Grazie in anticipo per l'attenzione e spero che qualcuno possa aiutarmi
  • Re: Graficare un dato ricevuto da seriale in real-time

    Leggiti la tabella dei codici ASCII e creati un altro array copiandoci dentro solo le cifre. Ti serve davvero un double?

    Ma comunque il codice di prima era giusto. Non è che i dati ti arrivano "sporchi", ma banalmente ogni tanto ti arrivano a spezzoni come in tutte le seriali asincrone. Devi unirli tu i pezzi, ti mettono il carattere di newline in mezzo proprio per quello
  • Re: Graficare un dato ricevuto da seriale in real-time

    Ciao Weierstrass, grazie per il tuo suggerimento.
    Riguardo il double, avevo pensato di usare quello perché sizeof(data) mi mostrava che il range è di 8 bytes perciò pensavo che int non fosse abbastanza per contenerlo ma alla fine avevi ragione tu, bastava un int.
    Nel mentre ho continuato a lavorare sul codice ed ho scritto questo:
    
    void MainWindow::readData()
    {
       const QByteArray data = m_serial->readAll();
        //qDebug()<<data<<endl;
        QByteArray x(data);
        QByteArray y = x.mid(0, x.size()-1);
        int result = y.toInt();
        qDebug()<< result<<endl;
       // qDebug()<<dada;
        timerSlot(result);
    }
    
    In questo modo la variabile 'result' è "pulita" nel senso che ho sempre e solo il numero, però il problema del valore a spezzettoni, come dicevi tu, rimane, perché adesso mi stampa il valore corretto (2000 o giù di lì) e 0 quando il valore non lo è. Sapresti dirmi più nel dettaglio come potrei fare per risolvere questo problema? Dici che quel codice con QString e QstringList posso riadattarlo anche adesso per eliminare gli spezzettoni?
  • Re: Graficare un dato ricevuto da seriale in real-time

    Fai il read un byte alla volta e aggiungi solo se è una cifra, se arriva il newline leggi tutto il numero. Era giusto il codice iniziale, solo che lo devi impostare a byte, oppure con un readline se previsto dalla libreria, sicuramente non con readAll.

    Esistono anche i long a 64 bit ovviamente
  • Re: Graficare un dato ricevuto da seriale in real-time

    Ciao Weierstrass,
    purtroppo, almeno nelle librerie che ho controllato di Qt non ce n'è uno adatto al mio caso e purtroppo quelle che ci sono non posso modificarle.
    Quindi non è che potresti aiutarmi a capire come fare per fare la lettura un byte per volta di questo codice?
    
    QByteArray charBuffer;
    
    void MainWindow::inviaData(const QByteArray &data)
    {
     QStringList List;
            QString ran;
    
            charBuffer.append(data);
            if (data.contains("\n"))
                {
                    QString myString(charBuffer);
                    List = myString.split(':');
                    qDebug() << List <<myString << endl;
                    charBuffer = "";
    
                    ran = List[1];
    
                } else {
                    return;
                }
               
                rand = ran.toLong();
    }
    
    il qDebug di List e myString mostra "2000 \n" e ("2000 \n") e non ci sono spezzoni, ho controllato. la variabile ran invece non riceve nulla, quindi come modifico questa parte per fargli leggere solo il numero?

    Scusami se ti richiedo più volte questa cosa, ma questa parte di programmazione non ci è stata spiegata in università quindi, quello che riesco a capire leggendo e provando, riesco a modificarlo o a scriverlo ma il resto per me è buio pesto. Grazie ancora.
  • Re: Graficare un dato ricevuto da seriale in real-time

    List = myString.split(':');
    Se non trova i ':' nella stringa, ritorna tutto nel primo elemento della QStringList, che ha indice 0.
    Per estrarre i dati da dentro la stringa, puoi provare con una regexp:
    QRegularExpression re("([0-9]+)");
    QRegularExpressionMatch match = re.match(charBuffer);
    if (match.hasMatch()) {
        ran = match.captured(1);		// Se c'è un solo numero nella stringa metti 1, se c'è più di un numero qui ti mette il primo trovato, il secondo avrà indice 2, etc.
    }
  • Re: Graficare un dato ricevuto da seriale in real-time

    Scusa, ma hai fatto l'università e non sei in grado di fare una atoi()
    personalizzata?
    long __atoi(char *p) {
        long k = 0;
        while (*p && (*p != '\n')) {
            if((*p >= '0') && (*p <= '9'))
                 k = k * 10 + (*p) - '0';
            p++;
         }
         return k;
    }
    
    
    In alternativa fai come dice Andrea. In ogni caso controlla bene la questione degli spezzoni, perché se arriva un pezzo della stringa seguente la cancelli, se scrivi così
  • Re: Graficare un dato ricevuto da seriale in real-time

    Grazie a tutti per l'aiuto, sono finalmente riuscito a risolvere il problema.
Devi accedere o registrarti per scrivere nel forum
8 risposte