Jak mogę otrzymać cały ciąg zamiast arduino na raz?

11

Z powodzeniem postępowałem zgodnie z instrukcjami na tej stronie:

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

i udało mi się uzyskać komunikację między pi a moim arudino mega dokładnie tak, jak to określa strona internetowa.

Jednak zamiast wysyłać liczbę całkowitą reprezentującą liczbę mrugnięć diody LED, chcę wysłać tekst ASCII, taki jak:

„PRZESUŃ 5 METRÓW DO PRZODU”, „SKRÓCJ W LEWO”, „PRZESUŃ 10 METRÓW DO TYŁU” do arduino z pi.

Napisałem następujący kod:

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

Z powodzeniem sflashowałem powyższy kod do mojego Arduino Mega 2560.

Przełączyłem się na terminal Python na Raspberry Pi i w konsoli wpisałem:

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

To, co wyświetla się na monitorze szeregowym mojego Arduino, wygląda następująco:

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

Ale chcę to:

Arduino Received: MOVE

Jak zmienić powyższy kod, aby wszystkie znaki znalazły się w buforze inData?

użytkownik1068636
źródło
Czy na pewno poprawnie skopiowałeś swój kod? Sposób, w jaki widzę twój kod, bez względu na zawartość inData, wiersz „Otrzymano Arduino” zostanie wydrukowany tylko raz. Jesteś pewien, że to wszystko zależy od twojej funkcji setup ()?
NickHalden,
Masz rację. Naprawiłem to teraz. Ale problem nadal pozostaje.
user1068636,

Odpowiedzi:

23

Problem polega na tym, że Arduino tak szybko się zapętla, że ​​wykona if (numBytesAvailable > 0)linię kilka razy między każdym znakiem przybywającym przez port szeregowy. Gdy tylko postać przybywa, chwyta ją, zapętla od zera do jednej i drukuje pojedynczą postać.

Co powinieneś zrobić, to wysłać znak końca linii ('\ n') po każdej komendzie z twojego programu Python. Następnie miej bufor kodu Arduino dla każdego otrzymanego znaku i działaj na wiadomość dopiero po otrzymaniu znaku końca linii.

Jeśli więc zmienisz kod Pythona, wyślij znak końca wiersza, taki jak:

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

Zatem twój kod Arduino może być mniej więcej taki:

// 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
źródło
1
Ponadto potencjalnym zwrotem w przypadku bardziej ogólnych zastosowań (np. W prostej C, w której nie masz wygodnej klasy String) jest to, że zerkniesz na zawartość bufora, aby sprawdzić, czy otrzymałeś jeszcze \ n. W ten sposób przechowujesz wszystko w wewnętrznym buforze przed wykonaniem jego kopii. Wadą tego rozwiązania jest to, że wewnętrzny bufor musi być wystarczająco duży, aby umożliwić uchwycenie najdłuższej pojedynczej linii. W przeciwnym razie potencjalnie zwiększysz szybkość przetwarzania, ponieważ unikniesz polubień takich jak String (przypuszczalnie to znaczy) ponownego obliczania i przydzielania pamięci w celu rozszerzenia.
Toby Lawrence
Twój kod działał! Musiałem zmienić kilka wierszy, takich jak inData = "" i inData + = otrzymano. Nie sądzę, żeby kompilatorowi się podobało.
user1068636,
6

Twój Python skrypt wysyła cztery bajty, M, O, V, i E. Skąd Arduino ma wiedzieć, że to pojedynczy ciąg? Weź pod uwagę, że kod Python:

ser.write("MOVE")

jest całkowicie identyczny z

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

z punktu widzenia Arduino. Porty szeregowe przesyłają znaki, a nie ciągi znaków.

W twoim kodzie Arduino jest szybkie (w porównaniu do prędkości 9600 bodów), więc za każdym razem, gdy dzwoni Serial.available(), widzi tylko jeden z tych czterech znaków. Właśnie dlatego masz uzyskaną moc wyjściową.

Musisz wymyślić jakiś sposób rozgraniczenia ciągów, tj. Oznaczenie ich w jakiś sposób z Pythona, aby Arduino mógł dołączyć pojedyncze znaki, które otrzymuje, do twojej koncepcji wysokiego poziomu łańcucha .

Używanie linii jest proste: wysyłaj każdy ciąg zakończony znakiem nowej linii ( '\n'). Na Arduino czytaj znaki i dołączaj je do swojego ciągu. Gdy zobaczysz a '\n', łańcuch jest skończony i możesz go wydrukować.

Jim Paris
źródło
Nie dołącza pojedynczych znaków do ciągu wolniej niż tylko czeka na znak nowej linii i odczytuje całą sekwencję znaków za jednym razem, gdy znak nowej linii jest odbierany.
Vivandiere,
2
Nie jestem pewien, co proponujesz - nie możesz „czekać” na znak nowej linii, chyba że go przeczytasz, a zanim go przeczytasz, koniecznie przeczytasz również wszystkie poprzednie znaki (co oznacza, że ​​muszą zostały zapisane w jakiś sposób - niezależnie od tego, czy jest to „dołączanie do ciągu”, czy inna metoda ich zapisania).
Jim Paris,
2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

Powyższy kod działa idealnie na moim połączeniu między Pi a Arduino

Douglas
źródło
1

Użyj .readlinezamiast.read

Miałem ten sam problem i to natychmiast go rozwiązało. Mam nadzieję, że to pomogło!

sam_trudgian
źródło
To trochę za mało jak na odpowiedź na EE.SE. Zwłaszcza biorąc pod uwagę, że jest to dwuletni wątek. Proszę opracować.
Nick Alexeev
Witaj w stosie, Sam. Cieszymy się, że jesteś na pokładzie. To nie jest tak, jak wiele innych forów, ponieważ staramy się być tak klarowni i szczegółowi, jak to możliwe, aby każda osoba, która znajdzie nasze pismo w przyszłości, mogła maksymalnie wykorzystać tę wiedzę. Czy miałeś dokładnie ten sam problem? Z tymi dokładnymi komponentami? A dokładnie ten kod? Jakie warunki w tej konfiguracji spowodowały, że Twój kod działał i dlaczego nie działał wcześniej? Społeczność chce twojej pomocy i wglądu.
Sean Boddy
0

Tak zrobiłem z pierwszego przykładu:

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
źródło