Як я можу отримувати цілу рядок на відміну від 1 символу одночасно на ардуїно?


11

Я успішно дотримувався інструкцій на цьому веб-сайті:

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

і мені вдалося налагодити зв’язок між пі та моїм медалом Arudino точно так, як вказує веб-сайт.

Однак замість того, щоб надсилати ціле число, яке відображає кількість разів блимає світлодіод, я хочу надіслати текст 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.

Я перейшов на свій пітон-термінал на 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?


Ви впевнені, що правильно скопіювали код? Те, як я бачу ваш код, незалежно від того, що в inData, рядок "Arduino Received" буде надруковано лише один раз. Ви впевнені, що це все у вашій функції setup ()?
NickHalden

Ти правий. Я зараз це виправив. Але проблема все ще залишається.
користувач1068636

Відповіді:


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 + = отримано. Я не думаю, що компілятору це сподобалось.
користувач1068636

6

Ваш Python скрипт відправляє чотири байти, M, O, V, і E. Як Arduino повинен знати, що це одна струна? Розглянемо, що код Python:

ser.write("MOVE")

є повністю ідентичним з

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

з точки зору Ардуїно. Послідовні порти передають символи, а не рядки.

У вашому коді Arduino швидкий (порівняно зі швидкістю передачі 9600 бод), тому щоразу, коли він дзвонить Serial.available(), він бачить лише одного з цих чотирьох символів. Ось чому ви отримали результат, який ви зробили.

Що вам потрібно зробити, - це придумати певний спосіб розмежування рядків, тобто позначити їх якимось чином від Python, щоб Arduino міг додавати окремі символи, які він отримує, у вашу високу концепцію рядка .

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


Не додає окремі символи до рядка повільніше, ніж просто очікування символу нової лінії та читання у всій послідовності символів за один раз при отриманні символу нового рядка.
The Vivandiere

2
Не впевнений, що ви пропонуєте - ви не можете "чекати" символу нового рядка, окрім того, як прочитати його, і до того моменту, коли ви його прочитали, ви обов'язково прочитаєте і всі попередні символи (а це означає, що їм потрібно були збережені якимось чином - залежить від того, чи "додавання до рядка" чи якийсь інший метод їх збереження).
Джим Парис

2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

Наведений вище код ідеально працює в моєму зв’язку між Пі та Ардуїно


1

Використовуйте .readlineзамість.read

У мене була така ж проблема, і це виправлено це відразу. Сподіваюся, це допомогло!


Це трохи тонко для відповіді на 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 = "";
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.