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?


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

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ć.


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


1

Użyj .readlinezamiast.read

Miałem ten sam problem i to natychmiast go rozwiązało. Mam nadzieję, że to pomogł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 = "";
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.