Wie erhalte ich eine ganze Zeichenfolge im Gegensatz zu jeweils einem Zeichen auf dem Arduino?

11

Ich habe die Anweisungen auf dieser Website erfolgreich befolgt:

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

und ich konnte die Kommunikation zwischen dem pi und meinem Arudino Mega genau so herstellen, wie es auf der Website angegeben ist.

Anstatt jedoch eine Ganzzahl zu senden, die angibt, wie oft die LED blinkt, möchte ich ASCII-Text wie folgt senden:

"5 METER VORWÄRTS BEWEGEN", "LINKS DREHEN", "10 METER VORWÄRTS BEWEGEN" vom Pi zum Arduino.

Ich habe folgenden Code geschrieben:

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);
    }
}

Ich habe den obigen Code erfolgreich auf meinem Arduino Mega 2560 geflasht.

Ich wechselte zu meinem Python-Terminal auf dem Raspberry Pi und tippte in der Konsole Folgendes ein:

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

Auf dem seriellen Monitor meines Arduino wird Folgendes angezeigt:

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

Aber was ich will ist:

Arduino Received: MOVE

Wie ändere ich den obigen Code, um alle Zeichen in den inData-Puffer zu bekommen?

user1068636
quelle
Sind Sie sicher, dass Sie Ihren Code korrekt kopiert haben? So wie ich Ihren Code sehe, wird die Zeile "Arduino Received" unabhängig davon, was inData enthalten ist, immer nur einmal gedruckt. Bist du sicher, dass das alles in deiner setup () Funktion ist?
NickHalden
Du hast recht. Ich habe es jetzt behoben. Das Problem bleibt jedoch weiterhin bestehen.
user1068636

Antworten:

23

Das Problem ist, dass der Arduino so schnell eine Schleife if (numBytesAvailable > 0)durchläuft , dass er die Zeile zwischen jedem Zeichen, das über die serielle Schnittstelle ankommt, mehrmals ausführt . Sobald ein Charakter eintrifft, greift er nach ihm, durchläuft eine Schleife von null auf eins und druckt einen einzelnen Charakter aus.

Sie sollten nach jedem Befehl aus Ihrem Python-Programm ein Zeilenendezeichen ('\ n') senden. Lassen Sie dann Ihren Arduino-Code jedes empfangene Zeichen puffern und auf die Nachricht erst reagieren, wenn das Zeilenendezeichen empfangen wird.

Wenn Sie also Ihren Python-Code ändern, senden Sie ein Zeilenendezeichen wie folgt:

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

Dann kann Ihr Arduino-Code ungefähr so ​​aussehen:

// 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
        }
    }
}
Phil
quelle
1
Eine mögliche Wendung für allgemeinere Verwendungen (wie in Straight Up C, wo Sie keine geeignete String-Klasse haben) besteht darin, dass Sie einen Blick auf den Inhalt des Puffers werfen, um festzustellen, ob Sie noch ein \ n erhalten haben. Auf diese Weise behalten Sie alles im internen Puffer, bevor Sie eine Kopie davon erstellen. Der Nachteil hierbei ist, dass der interne Puffer groß genug sein muss, damit Sie Ihre längste einzelne Zeile erfassen können. Andernfalls gewinnen Sie möglicherweise an Verarbeitungsgeschwindigkeit, da Sie vermeiden, dass Likes wie String (vermutlich) Speicher neu berechnen und zuweisen, um sich selbst zu erweitern.
Toby Lawrence
Ihr Code hat funktioniert! Ich musste ein paar Zeilen wie inData = "" und inData + = empfangen ändern. Ich glaube nicht, dass es dem Compiler gefallen hat.
user1068636
6

Ihr Python - Skript vier Bytes sendet, M, O, V, und E. Woher soll der Arduino wissen, dass das eine einzelne Saite ist? Bedenken Sie, dass der Python-Code:

ser.write("MOVE")

ist völlig identisch mit

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

aus der Sicht des Arduino. Serielle Ports übertragen Zeichen, keine Zeichenfolgen.

In Ihrem Code ist der Arduino schnell (im Vergleich zur Baudrate von 9600), sodass bei jedem Aufruf Serial.available()nur eines dieser vier Zeichen angezeigt wird. Deshalb haben Sie die Ausgabe erhalten, die Sie gemacht haben.

Was Sie tun müssen, ist eine Möglichkeit zu finden, Zeichenfolgen abzugrenzen, dh sie auf irgendeine Weise aus Python zu markieren, damit der Arduino die einzelnen Zeichen , die er empfängt, an Ihr übergeordnetes Konzept einer Zeichenfolge anhängen kann .

Die Verwendung von Zeilen ist unkompliziert: Senden Sie jede Zeichenfolge, die mit einem Zeilenumbruchzeichen ( '\n') abgeschlossen ist. Lesen Sie auf dem Arduino Zeichen und hängen Sie sie an Ihre Zeichenfolge an. Wenn Sie a sehen '\n', ist die Zeichenfolge beendet und Sie können sie drucken.

Jim Paris
quelle
Hängt einzelne Zeichen nicht langsamer an eine Zeichenfolge an, als nur auf das Zeilenumbruchzeichen zu warten und die gesamte Zeichenfolge auf einmal einzulesen, wenn das Zeilenumbruchzeichen empfangen wird.
Die Vivandiere
2
Sie sind sich nicht sicher, was Sie vorschlagen - Sie können nicht auf ein Zeilenumbruchzeichen "warten", außer indem Sie es lesen, und wenn Sie es gelesen haben, müssen Sie notwendigerweise auch alle vorherigen Zeichen lesen (was bedeutet, dass sie es müssen auf irgendeine Weise gespeichert wurden - ob dies "an eine Zeichenfolge anhängen" oder eine andere Methode zum Speichern ist, liegt bei Ihnen).
Jim Paris
2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

Der obige Code funktioniert perfekt für meine Verbindung zwischen Pi und Arduino

Douglas
quelle
1

Verwenden Sie .readlineanstelle von.read

Ich hatte das gleiche Problem und das hat es sofort behoben. Hoffe das hat geholfen!

sam_trudgian
quelle
Dies ist etwas dünn für eine Antwort auf EE.SE. Besonders wenn man bedenkt, dass dies ein 2 Jahre alter Thread ist. Bitte erläutern Sie.
Nick Alexeev
Willkommen im Stapel, Sam. Wir freuen uns, Sie an Bord zu haben. Dies ist nicht wie in vielen anderen Foren, da wir uns bemühen, so klar und detailliert wie möglich zu sein, damit jede Person, die in Zukunft unser Schreiben findet, den größtmöglichen Nutzen aus diesem Wissen ziehen kann. Hattest du genau das gleiche Problem? Mit genau diesen Komponenten? Und genau dieser Code? Unter welchen Bedingungen in diesem Setup hat Ihr Code funktioniert, und warum hat er zuvor nicht funktioniert? Die Community möchte Ihre Hilfe und Ihren Einblick.
Sean Boddy
0

So habe ich es vom ersten Beispiel an gemacht:

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 = "";
}
Karim
quelle