Як я можу отримувати цілу рядок на відміну від 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.