Come posso ricevere un'intera stringa anziché 1 carattere alla volta sull'Arduino?


11

Ho seguito con successo le istruzioni su questo sito Web:

http://www.doctormonk.com/2012/04/raspberry-pi-and-arduino.html

e sono stato in grado di ottenere la comunicazione tra il pi e il mio arudino mega esattamente come specificato dal sito web.

Tuttavia, invece di inviare un numero intero che rappresenta il numero di volte in cui il LED lampeggia, voglio inviare un testo ASCII come:

"SPOSTARE 5 METRI AVANTI", "SPOSTARE A SINISTRA", "SPOSTARE 10 METRI INDIETRO" sull'arduino dal pi.

Ho scritto il seguente codice:

char inData[64];
char inChar=-1;

void setup(){
   Serial.begin(9600);
   Serial.begin("Waiting for Raspberry Pi to send a signal...\n");
}


void loop(){
    byte numBytesAvailable= Serial.available();

    // if there is something to read
    if (numBytesAvailable > 0){
        // store everything into "inData"
        int i;
        for (i=0;i<numBytesAvailable;i++){
            inChar= Serial.read();
            inData[i] = inChar;
        }

        inData[i] = '\0';


        Serial.print("Arduino Received: ");
        Serial.println(inData);
    }
}

Ho lampeggiato sopra il codice con successo sul mio Arduino Mega 2560.

Sono passato al mio terminale Python sul Raspberry Pi e nella console ho digitato:

import serial
ser = serial.Serial('/dev/ttyACM1',9600)
ser.write("MOVE")

Ciò che viene visualizzato sul mio monitor seriale Arduino è il seguente:

Arduino Received: M
Arduino Received: O
Arduino Received: V
Arduino Received: E

Ma quello che voglio è:

Arduino Received: MOVE

Come posso modificare il codice sopra per inserire tutti i caratteri nel buffer inData?


Sei sicuro di aver copiato il tuo codice correttamente? Per come vedo il tuo codice, indipendentemente da ciò che è inData, la riga "Arduino ricevuto" verrebbe stampata una sola volta. Sei sicuro che sia tutto nella tua funzione setup ()?
NickHalden,

Hai ragione. L'ho risolto ora. Ma il problema rimane ancora.
user1068636,

Risposte:


23

Il problema è che Arduino sta girando così velocemente, che eseguirà la if (numBytesAvailable > 0)linea più volte tra ogni personaggio che arriva attraverso la porta seriale. Quindi non appena arriva un personaggio, lo afferra, passa da zero a uno e stampa un singolo personaggio.

Quello che dovresti fare è inviare un carattere di fine riga ('\ n') dopo ogni comando dal tuo programma Python. Quindi fai in modo che il tuo codice Arduino buffer ogni carattere che riceve e agisce sul messaggio solo quando riceve il carattere di fine riga.

Quindi, se modifichi il codice Python, invia un carattere di fine riga, in questo modo:

import serial
ser = serial.Serial('/dev/ttyACM1',9600)
ser.write("MOVE\n")

Quindi il tuo codice Arduino può essere qualcosa del genere:

// Buffer to store incoming commands from serial port
String inData;

void setup() {
    Serial.begin(9600);
    Serial.println("Waiting for Raspberry Pi to send a signal...\n");
}

void loop() {
    while (Serial.available() > 0)
    {
        char recieved = Serial.read();
        inData += recieved; 

        // Process message when new line character is recieved
        if (recieved == '\n')
        {
            Serial.print("Arduino Received: ");
            Serial.print(inData);

            inData = ""; // Clear recieved buffer
        }
    }
}

1
Inoltre, una potenziale svolta su questo per usi più generici (come in C in alto dove non hai una comoda classe String) è che dai un'occhiata a cosa c'è nel buffer per vedere se hai ancora ricevuto un \ n. In questo modo conservi tutto nel buffer interno prima di crearne una copia. Il rovescio della medaglia qui è che il buffer interno deve essere abbastanza grande da consentire l'acquisizione della linea singola più lunga. Altrimenti, potresti potenzialmente aumentare la velocità di elaborazione evitando i Mi piace come String (presumibilmente, cioè) ricalcolare e allocare memoria per espandersi.
Toby Lawrence,

Il tuo codice ha funzionato! Ho dovuto cambiare un paio di righe come inData = "" e inData + = ricevute. Non credo che al compilatore sia piaciuto.
user1068636,

6

Lo script Python è l'invio di quattro byte, M, O, V, e E. In che modo Arduino dovrebbe sapere che si tratta di una singola stringa? Considera che il codice Python:

ser.write("MOVE")

è completamente identico a

ser.write("MO")
ser.write("VE")

dal punto di vista dell'Arduino. Le porte seriali trasferiscono caratteri, non stringhe.

Nel tuo codice, Arduino è veloce (rispetto alla velocità di trasmissione di 9600 baud), quindi ogni volta che chiama Serial.available(), vede solo uno di quei quattro caratteri. Ecco perché hai ottenuto l'output che hai fatto.

Ciò che dovrai fare è trovare un modo per delimitare le stringhe, ovvero contrassegnarle in qualche modo da Python in modo che Arduino possa aggiungere i singoli caratteri che riceve nel concetto di alto livello di una stringa .

L'uso delle linee è semplice: invia ogni stringa terminata con un carattere di nuova riga ( '\n'). Su Arduino, leggi i caratteri e aggiungili alla tua stringa. Quando vedi a '\n', la stringa è finita e puoi stamparla.


Non è più lento aggiungere singoli caratteri a una stringa piuttosto che aspettare il carattere di nuova riga e leggere l'intera sequenza di caratteri in una volta sola quando viene ricevuto il carattere di nuova riga.
Il Vivandiere,

2
Non sei sicuro di ciò che stai proponendo: non puoi "aspettare" un personaggio newline se non leggendolo, e quando lo leggi, leggi necessariamente anche tutti i personaggi precedenti (il che significa che devono sono stati salvati in qualche modo - dipende dal fatto che sia "aggiunta a una stringa" o qualche altro metodo per salvarli).
Jim Paris,

2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

Il codice sopra funziona perfettamente sulla mia connessione tra Pi e Arduino


1

Usa .readlineinvece di.read

Ho avuto lo stesso problema e questo è stato risolto immediatamente. Spero che questo abbia aiutato!


Questo è un po 'sottile per una risposta su EE.SE. Soprattutto se si considera che questa è una discussione di 2 anni. Per favore, elabora.
Nick Alexeev

Benvenuto nello stack, sam. Siamo felici di averti a bordo. Questo non è come molti altri forum, in quanto ci sforziamo di essere il più chiari e dettagliati possibile, in modo che ogni persona che trova la nostra scrittura in futuro possa ottenere il massimo beneficio da quella conoscenza. Hai avuto l' esatto stesso problema? Con quei componenti esatti ? E quel codice esatto ? Quali condizioni in questa configurazione hanno fatto funzionare il tuo codice e perché non ha funzionato prima? La community vuole il tuo aiuto e la tua intuizione.
Sean Boddy

0

Ecco come l'ho fatto dal primo esempio:

String readString;

void setup()
{
    Serial.begin(9600); // initialization
}

void loop()
{
    char incomingByte;
    while (Serial.available() > 0)
    {
        delay(10); // if the data came
        incomingByte = Serial.read(); // read byte
        //Serial.println(incomingByte);
        readString += incomingByte;
    }

    if(readString != "")
    {
        Serial.print("arduino recived this : ");
        Serial.println(readString);
    }
    readString = "";
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.