¿Cómo recibo una cadena completa en lugar de 1 carácter a la vez en el arduino?

11

Seguí las instrucciones en este sitio web con éxito:

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

y pude obtener comunicación entre el pi y mi mega arudino exactamente como lo especifica el sitio web.

Sin embargo, en lugar de enviar un número entero que represente la cantidad de veces que parpadea el LED, quiero enviar un texto ASCII como:

"MOVER 5 METROS HACIA ADELANTE", "GIRAR A LA IZQUIERDA", "MOVER 10 METROS HACIA ATRÁS" hacia el arduino desde el pi.

Escribí el siguiente código:

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

Actualicé el código anterior con éxito a mi Arduino Mega 2560.

Cambié a mi terminal de Python en la Raspberry Pi y en la consola escribí:

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

Lo que se muestra en el monitor serie de mi Arduino es el siguiente:

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

Pero lo que quiero es:

Arduino Received: MOVE

¿Cómo cambio el código anterior para obtener todos los caracteres en el búfer inData?

usuario1068636
fuente
¿Estás seguro de que has copiado tu código correctamente? De la forma en que veo su código, independientemente de lo que contenga inData, la línea "Arduino Received" solo se imprimirá una vez. ¿Estás seguro de que todo está en tu función setup ()?
NickHalden
Tienes razón. Lo arreglé ahora. Pero el problema aún persiste.
user1068636

Respuestas:

23

El problema es que el Arduino está dando vueltas tan rápido que ejecutará la if (numBytesAvailable > 0)línea varias veces entre cada carácter que llegue a través del puerto serie. Entonces, tan pronto como llega un personaje, lo agarra, realiza un bucle de cero a uno e imprime un solo personaje.

Lo que debe hacer es enviar un carácter de final de línea ('\ n') después de cada comando desde su programa Python. Luego, haga que su código Arduino guarde cada carácter que recibe y solo actúe sobre el mensaje una vez que reciba el carácter de fin de línea.

Entonces, si cambia su código de Python, envíe un carácter de final de línea, así:

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

Entonces su código Arduino puede ser algo como esto:

// 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
fuente
1
Además, un giro potencial en esto para usos más genéricos (como en C directo donde no tiene una clase de cadena conveniente) es que eche un vistazo a lo que está en el búfer para ver si ha recibido un \ n todavía. De esta manera, mantiene todo en el búfer interno antes de hacer una copia. La desventaja aquí es que el búfer interno debe ser lo suficientemente grande como para permitirle capturar su línea más larga. De lo contrario, posiblemente ganes velocidad de procesamiento al evitar gustos como String (presumiblemente, eso es) recalculando y asignando memoria para expandirse.
Toby Lawrence
¡Tu código funcionó! Tuve que cambiar un par de líneas como inData = "" e inData + = recibido. No creo que al compilador le haya gustado.
user1068636
6

La secuencia de comandos de Python es el envío de cuatro bytes, M, O, V, y E. ¿Cómo se supone que Arduino sabe que es una sola cuerda? Considere que el código Python:

ser.write("MOVE")

es completamente idéntico a

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

desde el punto de vista de Arduino. Los puertos serie transfieren caracteres, no cadenas.

En su código, el Arduino es rápido (en comparación con la velocidad de 9600 baudios), por lo que cada vez que llama Serial.available(), solo ve uno de esos cuatro caracteres. Es por eso que obtuviste la salida que hiciste.

Lo que tendrá que hacer es idear alguna forma de delimitar cadenas, es decir, marcarlas de alguna manera desde Python para que el Arduino pueda agregar los caracteres individuales que recibe en su concepto de cadena de alto nivel .

El uso de líneas es sencillo: envíe cada cadena terminada con un carácter de nueva línea ( '\n'). En el Arduino, lee los caracteres y agrégalos a tu cadena. Cuando vea a '\n', la cadena ha terminado y puede imprimirla.

Jim Paris
fuente
No agrega caracteres individuales a una cadena más lentamente que solo esperar el carácter de nueva línea y leer toda la secuencia de caracteres de una vez cuando se recibe el carácter de nueva línea.
The Vivandiere
2
No estoy seguro de lo que está proponiendo: no puede "esperar" un carácter de nueva línea, excepto al leerlo, y para cuando lo haya leído, necesariamente debe leer también todos los caracteres anteriores (lo que significa que deben han sido guardados de alguna manera, ya sea "agregar a una cadena" o algún otro método para guardarlos, depende de usted).
Jim Paris
2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

El código anterior funciona perfecto en mi conexión entre Pi y Arduino

Douglas
fuente
1

Usar en .readlinelugar de.read

Tuve el mismo problema y esto lo solucionó de inmediato. Espero que esto haya ayudado!

sam_trudgian
fuente
Esto es un poco escaso para una respuesta en EE. UU. Especialmente teniendo en cuenta que este es un hilo de 2 años. Por favor elabora.
Nick Alexeev
Bienvenido a la pila, Sam. Nos alegra tenerte a bordo. Esto no es como muchos otros foros, ya que tratamos de ser lo más claros y detallados posible, para que cada persona que encuentre nuestros escritos en el futuro pueda obtener el máximo beneficio de ese conocimiento. ¿Tuviste exactamente el mismo problema? ¿Con esos componentes exactos ? ¿Y ese código exacto ? ¿Qué condiciones en esta configuración hicieron que su código funcionara y por qué no funcionó antes? La comunidad quiere su ayuda y su visión.
Sean Boddy,
0

Así es como lo hice desde el primer ejemplo:

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
fuente