Comment puis-je recevoir une chaîne entière par opposition à 1 caractère à la fois sur l'arduino?

11

J'ai suivi avec succès les instructions sur ce site:

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

et j'ai pu obtenir une communication entre le pi et mon méga arudino exactement comme le spécifie le site Web.

Cependant, au lieu d'envoyer un entier représentant le nombre de fois que la LED clignote, je veux envoyer du texte ASCII comme:

"DÉPLACEZ 5 MÈTRES EN AVANT", "TOURNEZ À GAUCHE", "DÉPLACEZ 10 MÈTRES EN ARRIÈRE" vers l'arduino depuis la pi.

J'ai écrit le code suivant:

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

J'ai flashé avec succès le code ci-dessus sur mon Arduino Mega 2560.

Je suis passé à mon terminal python sur le Raspberry Pi et dans la console j'ai tapé:

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

Ce qui s'affiche sur le moniteur série de mon Arduino est le suivant:

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

Mais ce que je veux c'est:

Arduino Received: MOVE

Comment puis-je changer le code ci-dessus pour obtenir tous les caractères dans le tampon inData?

user1068636
la source
Êtes-vous sûr d'avoir copié votre code correctement? De la façon dont je vois votre code, quel que soit le contenu de inData, la ligne "Arduino Received" ne serait imprimée qu'une seule fois. Vous êtes sûr que c'est tout dans votre fonction setup ()?
NickHalden
Vous avez raison. Je l'ai réparé maintenant. Mais le problème persiste.
user1068636

Réponses:

23

Le problème est que l'Arduino tourne si vite qu'il exécutera la if (numBytesAvailable > 0)ligne plusieurs fois entre chaque caractère arrivant via le port série. Ainsi, dès qu'un personnage arrive, il l'attrape, boucle de zéro à un et imprime un seul caractère.

Ce que vous devez faire est d'envoyer un caractère de fin de ligne ('\ n') après chaque commande de votre programme Python. Ensuite, demandez à votre code Arduino de tamponner chaque caractère qu'il reçoit et n'agissez sur le message qu'une fois qu'il reçoit le caractère de fin de ligne.

Donc, si vous changez votre code Python, envoyez un caractère de fin de ligne, comme ceci:

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

Ensuite, votre code Arduino peut ressembler à ceci:

// 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
la source
1
En outre, une torsion potentielle à ce sujet pour des utilisations plus génériques (comme dans C vers le haut où vous n'avez pas de classe String pratique) est que vous jetez un œil à ce qu'il y a dans le tampon pour voir si vous avez encore reçu un \ n. De cette façon, vous conservez tout dans le tampon interne avant d'en faire une copie. L'inconvénient ici est que le tampon interne doit être suffisamment grand pour vous permettre de capturer votre ligne unique la plus longue. Sinon, vous gagnez potentiellement en vitesse de traitement en évitant des goûts comme String (probablement, c'est-à-dire) en recalculant et en allouant de la mémoire pour se développer.
Toby Lawrence
Votre code a fonctionné! J'ai dû changer quelques lignes comme inData = "" et inData + = reçu. Je ne pense pas que le compilateur ait aimé.
user1068636
6

Votre script Python envoie quatre octets, M, O, Vet E. Comment l'Arduino est-il censé savoir qu'il s'agit d'une seule chaîne? Considérez que le code Python:

ser.write("MOVE")

est complètement identique à

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

du point de vue de l'Arduino. Les ports série transfèrent les caractères, pas les chaînes.

Dans votre code, l'Arduino est rapide (par rapport au débit de 9600 bauds), donc à chaque fois qu'il appelle Serial.available(), il ne voit qu'un de ces quatre caractères. C'est pourquoi vous avez obtenu le résultat que vous avez obtenu.

Ce que vous devrez faire est de trouver un moyen de délimiter les chaînes, c'est-à-dire de les marquer d'une manière quelconque à partir de Python afin que l'Arduino puisse ajouter les caractères individuels qu'il reçoit dans votre concept de haut niveau d'une chaîne .

L'utilisation des lignes est simple: envoyez chaque chaîne terminée par un caractère de nouvelle ligne ( '\n'). Sur l'Arduino, lisez les caractères et ajoutez-les à votre chaîne. Lorsque vous voyez un '\n', la chaîne est terminée et vous pouvez l'imprimer.

Jim Paris
la source
N'ajoute pas des caractères individuels à une chaîne plus lentement que d'attendre simplement le caractère de retour à la ligne et de lire la séquence de caractères en une seule fois lorsque le caractère de retour à la ligne est reçu.
The Vivandiere
2
Je ne sais pas ce que vous proposez - vous ne pouvez pas "attendre" un caractère de nouvelle ligne sauf en le lisant, et au moment où vous le lisez, vous lisez nécessairement tous les caractères précédents également (ce qui signifie qu'ils doivent ont été enregistrés d'une manière ou d'une autre - que ce soit "l'ajout à une chaîne" ou une autre méthode pour les enregistrer dépend de vous).
Jim Paris
2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

Le code ci-dessus fonctionne parfaitement sur ma connexion entre Pi et Arduino

Douglas
la source
1

Utiliser .readlineau lieu de.read

J'ai eu le même problème et cela l'a réglé immédiatement. J'espère que cela a aidé!

sam_trudgian
la source
C'est un peu mince pour une réponse sur EE.SE. Surtout si l'on considère qu'il s'agit d'un fil de 2 ans. Veuillez développer.
Nick Alexeev
Bienvenue dans la pile, sam. Nous sommes ravis de vous avoir à bord. Ce n'est pas comme beaucoup d'autres forums, dans la mesure où nous nous efforçons d'être aussi clairs et détaillés que possible, afin que chaque personne trouvant notre écriture à l'avenir puisse tirer le maximum d'avantages de ces connaissances. Avez-vous eu exactement le même problème? Avec ces composants exacts ? Et ce code exact ? Quelles conditions dans cette configuration ont fait fonctionner votre code, et pourquoi cela n'a-t-il pas fonctionné auparavant? La communauté veut votre aide et vos idées.
Sean Boddy
0

Voici comment je l'ai fait à partir du premier exemple:

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
la source