Como recebo uma string inteira em oposição a 1 caractere por vez no arduino?

11

Segui as instruções deste site com sucesso:

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

e pude obter comunicação entre o pi e o meu arudino mega exatamente como o site especifica.

No entanto, em vez de enviar um número inteiro representando o número de vezes que o LED pisca, desejo enviar texto ASCII como:

"Mova 5 metros para a frente", "Vire à esquerda", "Mova 10 metros para trás" para o arduino a partir do pi.

Eu escrevi o seguinte 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);
    }
}

Pisquei o código acima com êxito no meu Arduino Mega 2560.

Mudei para o meu terminal python no Raspberry Pi e no console digitei:

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

O que é exibido no monitor serial do meu Arduino é o seguinte:

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

Mas o que eu quero é:

Arduino Received: MOVE

Como altero o código acima para obter todos os caracteres no buffer inData?

user1068636
fonte
Tem certeza de que copiou seu código corretamente? Da maneira como vejo seu código, independentemente do conteúdo do inData, a linha "Arduino Recebido" seria impressa apenas uma vez. Você tem certeza de que está tudo na sua função setup ()?
21412 NickHalden
Você está certo. Eu consertei agora. Mas o problema ainda permanece.
user1068636

Respostas:

23

O problema é que o Arduino está rodando tão rápido que executa a if (numBytesAvailable > 0)linha várias vezes entre cada caractere que chega pela porta serial. Assim que um personagem chega, ele o agarra, passa de zero a um e imprime um único caractere.

O que você deve fazer é enviar um caractere de fim de linha ('\ n') após cada comando do seu programa Python. Em seguida, peça ao seu código do Arduino que armazene em buffer cada caractere que receber e atue somente na mensagem quando receber o caractere de fim de linha.

Portanto, se você alterar seu código Python, envie um caractere de fim de linha, assim:

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

Então seu código Arduino pode ser algo como isto:

// 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
fonte
11
Além disso, uma possível reviravolta nisso para usos mais genéricos (como em C direto, onde você não tem uma classe String conveniente) é que você espia o que está no buffer para ver se já recebeu um \ n. Dessa forma, você mantém tudo no buffer interno antes de fazer uma cópia dele. A queda aqui é que o buffer interno precisa ser grande o suficiente para permitir que você capture sua linha única mais longa. Caso contrário, você potencialmente ganhará na velocidade de processamento, pois evita curtidas como String (presumivelmente, isto é), recalculando e alocando memória para se expandir.
Toby Lawrence
Seu código funcionou! Eu tive que mudar algumas linhas como inData = "" e inData + = recebido. Eu não acho que o compilador tenha gostado.
user1068636
6

Seu script Python está enviando quatro bytes, M, O, V, e E. Como o Arduino deve saber que essa é uma única string? Considere que o código Python:

ser.write("MOVE")

é completamente idêntico ao

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

do ponto de vista do Arduino. Portas seriais transferem caracteres, não cadeias.

No seu código, o Arduino é rápido (comparado à taxa de 9600 bauds); portanto, toda vez que ele chama Serial.available(), ele vê apenas um desses quatro caracteres. É por isso que você obteve a saída que obteve.

O que você precisa fazer é criar uma maneira de delimitar as strings, ou seja, marcá-las de alguma forma no Python, para que o Arduino possa acrescentar os caracteres individuais que recebe ao seu conceito de alto nível de string .

O uso de linhas é simples: envie cada sequência terminada com um caractere de nova linha ( '\n'). No Arduino, leia os caracteres e adicione-os à sua string. Quando você vê um '\n', a sequência acabou e você pode imprimi-la.

Jim Paris
fonte
Não é mais anexar caracteres individuais a uma sequência mais devagar do que esperar pelo caractere de nova linha e ler toda a sequência de caracteres de uma só vez quando o caractere de nova linha é recebido.
The Vivandiere
2
Não sabe ao certo o que está propondo - você não pode "esperar" por um caractere de nova linha, exceto lendo-o e, quando o lê, você necessariamente lê todos os caracteres anteriores também (o que significa que eles precisam foram salvos de alguma maneira - depende de você "anexar a uma string" ou de algum outro método para salvá-los.
Jim Paris
2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

O código acima funciona perfeitamente na minha conexão entre Pi e Arduino

Douglas
fonte
1

Use em .readlinevez de.read

Eu tive o mesmo problema e isso foi corrigido imediatamente. Espero que isso tenha ajudado!

sam_trudgian
fonte
Isso é um pouco fino para uma resposta no EE.SE. Especialmente considerando que este é um tópico de 2 anos. Por favor elabore.
Nick Alexeev
Bem-vindo à pilha, sam. Estamos felizes em ter você a bordo. Isso não é como muitos outros fóruns, na medida em que tentamos ser o mais claros e detalhados possível, para que todas as pessoas que encontrarem nossa redação no futuro possam obter o máximo benefício desse conhecimento. Você teve exatamente o mesmo problema? Com esses componentes exatos ? E esse código exato ? Quais condições nessa configuração fizeram seu código funcionar e por que não funcionou antes? A comunidade quer sua ajuda e sua visão.
Sean Boddy
0

Foi assim que fiz no primeiro exemplo:

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
fonte