Как получить всю строку, а не 1 символ за раз на Arduino?

11

Я успешно следовал инструкциям на этом сайте:

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

и я смог получить связь между пи и моей мега-арудино точно так, как указано на сайте.

Однако вместо отправки целого числа, представляющего количество миганий светодиода, я хочу отправить текст ASCII, например:

«ПЕРЕМЕСТИТЬ 5 МЕТРОВ ВПЕРЕД», «ПОВЕРНУТЬ ВЛЕВО», «ПЕРЕМЕСТИТЬ 10 ​​МЕТРОВ ВПЕРЕД» к ардуино от пи.

Я написал следующий код:

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

Я успешно прошил код выше моего Arduino Mega 2560.

Я переключился на свой терминал Python на Raspberry Pi и в консоли набрал:

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

На моем последовательном мониторе Arduino отображается следующее:

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

Но то, что я хочу, это:

Arduino Received: MOVE

Как изменить приведенный выше код, чтобы получить все символы в буфере inData?

user1068636
источник
Вы уверены, что правильно скопировали свой код? Как я вижу ваш код, независимо от того, что находится в inData, строка «Arduino Received» будет напечатана только один раз. Вы уверены, что это все в вашей функции setup ()?
Ник Халден
Ты прав. Я исправил это сейчас. Но проблема все еще остается.
user1068636 26.10.12

Ответы:

23

Проблема в том, что Arduino зацикливается так быстро, что будет выполнять if (numBytesAvailable > 0)линию несколько раз между каждым символом, поступающим через последовательный порт. Поэтому, как только персонаж действительно появляется, он захватывает его, зацикливается с нуля на один и печатает один символ.

Что вы должны сделать, это послать символ конца строки ('\ n') после каждой команды из вашей программы Python. Затем пусть ваш код Arduino буферизует каждый полученный символ и воздействует на сообщение только после получения символа конца строки.

Поэтому, если вы измените свой код Python, отправьте символ конца строки, например, так:

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

Тогда ваш код Arduino может быть примерно таким:

// 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
Кроме того, потенциальный поворот в этом для более общего использования (как в прямом C, где у вас нет удобного класса String) заключается в том, что вы смотрите на то, что находится в буфере, чтобы увидеть, получили ли вы еще \ n. Таким образом, вы сохраняете все во внутреннем буфере, прежде чем сделать его копию. Недостатком здесь является то, что внутренний буфер должен быть достаточно большим, чтобы позволить вам захватить самую длинную строку. В противном случае вы потенциально выигрываете в скорости обработки, так как избегаете таких, как String (предположительно, то есть), повторного вычисления и выделения памяти для расширения.
Тоби Лоуренс
Ваш код сработал! Мне пришлось изменить пару строк, таких как inData = "" и inData + = получили. Я не думаю, что это понравилось компилятору.
user1068636 26.10.12
6

Ваш Python скрипт отправляет четыре байта, M, O, V, и E. Как Arduino должен знать, что это одна строка? Учтите, что код Python:

ser.write("MOVE")

является полностью идентичным с

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

с точки зрения Arduino. Последовательные порты передают символы, а не строки.

В вашем коде Arduino работает быстро (по сравнению со скоростью 9600 бод), поэтому при каждом вызове Serial.available()он видит только один из этих четырех символов. Вот почему вы получили результат, который вы сделали.

Что вам нужно сделать, так это придумать какой-то способ разграничения строк, то есть пометить их каким-либо образом из Python, чтобы Arduino мог добавлять отдельные символы, которые он получает, в ваше высокоуровневое понятие строки .

Использовать строки просто: отправьте каждую строку, оканчивающуюся символом новой строки ( '\n'). На Arduino читайте символы и добавляйте их в строку. Когда вы видите '\n', строка заканчивается, и вы можете напечатать ее.

Джим Пэрис
источник
Не добавляет отдельные символы в строку медленнее, чем просто ожидание символа новой строки, и не читает всю последовательность символов за один раз, когда символ новой строки получен.
The Vivandiere
2
Не уверен, что вы предлагаете - вы не можете «ждать» символа новой строки, за исключением того, что читаете его, и к тому моменту, когда вы его прочитаете, вы обязательно прочитаете также все предыдущие символы (что означает, что они должны были сохранены каким-либо образом - будь то «добавление в строку» или какой-либо другой способ их сохранения, зависит от вас).
Джим Париж
2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

Приведенный выше код прекрасно работает на моей связи между Pi и Arduino

Дуглас
источник
1

Используйте .readlineвместо.read

У меня была та же проблема, и это сразу же исправило. Надеюсь, это помогло!

sam_trudgian
источник
Это немного тонко для ответа на EE.SE. Особенно учитывая, что это 2-летняя тема. Пожалуйста, дополните.
Ник Алексеев
Добро пожаловать в стек, Сэм. Мы рады, что вы на борту. Это не так, как на многих других форумах, поскольку мы стараемся быть как можно более четкими и подробными, чтобы каждый человек, нашедший наше письмо в будущем, мог получить максимальную пользу от этих знаний. У вас была точно такая же проблема? С этими точными компонентами? И этот точный код? Какие условия в этой настройке заставили ваш код работать, и почему он не работал раньше? Сообщество хочет вашей помощи и вашего понимания.
Шон Бодди
0

Вот как я это сделал из первого примера:

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
источник