Arduinoで一度に1文字ではなく文字列全体を受け取るにはどうすればよいですか?


11

私はこのウェブサイトの指示に成功しました:

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

そして、ウェブサイトで指定されているとおりに、piとarudino mega間の通信を得ることができました。

ただし、LEDが点滅する回数を表す整数を送信する代わりに、次のようなASCIIテキストを送信します。

「MOVE 5 METERS FORWARD」、「TURN LEFT」、「MOVE 10 METERS BACKWARD」は、piからarduinoに移動します。

次のコードを書きました。

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のpythonターミナルに切り替え、コンソールで次のように入力しました。

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 2012年

あなたが正しい。今直した。しかし、問題はまだ残っています。
user1068636 2012年

回答:


23

問題は、Arduinoが非常に高速にループしているためif (numBytesAvailable > 0)、シリアルポートを介して到着する各文字間でラインを数回実行することです。したがって、文字が到着するとすぐにそれを取得し、0から1にループして、1文字を出力します。

あなたがすべきことは、Pythonプログラムからの各コマンドの後に行末文字( '\ n')を送ることです。次に、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
また、より一般的な使用法(これには、便利なStringクラスがないまっすぐなCの場合など)の潜在的なひねりは、バッファーの内容を調べて、まだ\ nを受け取っているかどうかを確認することです。これにより、コピーを作成する前にすべてを内部バッファーに保持します。ここでの問題は、内部バッファーは、最長の単一行をキャプチャできるように十分大きくなければならないということです。それ以外の場合は、文字列(おそらく)のようなメモリを再計算してメモリを割り当て、それ自体を拡張することを避けることで、処理速度が向上する可能性があります。
Toby Lawrence

あなたのコードはうまくいきました!受信したinData = ""やinData + =のような数行を変更する必要がありました。コンパイラが気に入ったとは思いません。
user1068636 2012年

6

あなたのPythonスクリプトは、4つのバイトを送信しているMOV、とE。Arduinoは、それが単一の文字列であることをどのようにして知っているはずですか?次のPythonコードを考えてみます。

ser.write("MOVE")

完全に同一

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

Arduinoの観点から。シリアルポートは文字列ではなく文字を転送します。

コードでは、Arduinoは(9600ボーレートと比較して)高速であるためSerial.available()、を呼び出すたびに、4つの文字のうちの1つしか認識されません。それが、あなたがした出力を得た理由です。

あなたがする必要があるのは、文字列を区切るいくつかの方法を考え出すことです。つまり、Arduinoが受け取った個々の文字を高レベルの文字列の概念に追加できるように、Pythonから何らかの方法でそれらをマークします

行の使用は簡単です'\n'。改行文字()で終了するすべての文字列を送信します。Arduinoで、文字を読み取り、文字列に追加します。が表示されたら'\n'、文字列は終了しており、印刷できます。


文字列に個々の文字を追加するのは、改行文字を待つだけでなく、改行文字を受け取ったときに文字シーケンス全体を一度に読み取るよりも遅くはありません。
Vivandiere、2015

2
何を提案しているのかわからない-改行文字を読むことを除いて、それを「待つ」ことはできません。また、それを読んだときには、以前のすべての文字も必ず読み取る必要があります(つまり、何らかの方法で保存されている-それが「文字列に追加する」かどうか、またはそれらを保存する他の方法はあなた次第です。
ジム・パリ

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

上記のコードは、PiとArduinoの間の接続に最適です


1

.readline代わりに使用.read

私は同じ問題を抱えていましたが、これですぐに修正されました。これが役に立てば幸い!


これはEE.SEでの回答としては少し薄いです。これが2年前のスレッドであることを特に考慮してください。詳しく説明してください。
Nick Alexeev

スタックへようこそ、サム。よろしくお願いいたします。これは他の多くのフォーラムとは異なります。私たちはできるだけ明確かつ詳細になるように努力しているため、将来私たちの執筆を見つけたすべての人がその知識から最大の利益を得ることができます。あなたは持っていなかったまったく同じ問題が?これらの正確なコンポーネントを使用していますか?そして、その正確なコードは?このセットアップのどのような条件でコードが機能しましたか、また以前は機能しなかったのはなぜですか?コミュニティはあなたの助け洞察を求めています。
ショーンボディ

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 = "";
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.