5

Bluetooth 経由で Android フォンを使用してロボットを制御するアプリを作成しています。すべてがうまくいき、データがエコーされて検証されますが、プロトコルに問題があります。具体的には、送信時にロボットのホイールを回転させたいs,10,100またはs,-30,-10...などのコマンド(パーセント単位の値)。

私の問題は、Arduino でホイール速度コマンドを解析したい場合、最大 4 つまで別々bytesに解析する必要があることintです。たとえばs,-100,-100、ロボットを全速力で後退させますが、これを解析してsetSpeed(left, right);withleftrightequalを呼び出すにはどうすればよいですか? -100に?

すべてのバイトを個別に分析し、それらをまとめて整数を取得できることはわかっていますが、それはあまりエレガントではなく、おそらくこれらすべてに対するより良い解決策がすでにありますが、残念ながらまだ見つけていません。

編集

コマンドを解析するためのArduino関数は次のとおりです。

void parseCommand(char* command, int* returnValues)
{
  // parsing state machine
  byte i = 2, j = 0, sign = 0;
  int temp = 0;
  while(*(command + i) != '\0')
  {
    switch(*(command + i))
    {
      case ',':
        returnValues[j++] = sign?-temp:temp;
        sign = 0;
        temp = 0;
        break;
      case '-':
        sign = 1;
        break;
      default:
        temp = temp * 10 + *(command + i) - 48;
    }
    i++;
  }
  // set last return value
  returnValues[j] = sign?-temp:temp;
}

次のようなものを解析するときは、次のように呼び出しますs,100,-100(終了する必要があり\0ます):

char serialData[16];
void loop()
{
  if(Serial.available() > 0)
  {
    Serial.readBytesUntil('\0', serialData, 15);
    switch(serialData[0])
    {
      case 's':
        int speed[2];
        parseCommand(serialData, speed);
        setSpeed(speed[0], speed[1]);
        break;
    }
    // always echo
    Serial.write(serialData);
    // end of message is maked with a \0
    Serial.print('\0');

    // clear serialData array
    memset(serialData, 0, sizeof(serialData));
  }
}
4

2 に答える 2

9

1 文字ずつステート マシンに読み込むだけです。シンプルで効率的です。

数値を 1 桁ずつ読み取るには、次のようにします。ゼロから始めます。数字ごとに、数字に 10 を掛け、その数字の値を加算します。たとえば、97 を読み取ると、次のようになります。

  1. 前の数字のない数字を読み取ると、0 から始まります。

  2. 9 を読み込み、(0*10)+9 -> 9 を計算します。

  3. 7 を読み込み、(9*10)+7 -> 97 を計算します。

  4. 数字以外を読み込むと、97 が出力されます。

より完全な例を次に示しs,10,100ます。

  1. 「コマンドを読み取る準備ができた状態」で開始します。

  2. 「s」と読みますが、「s」はコマンドです。「最初のコンマを読み取る準備ができている」状態に切り替えます。

  3. 最初のコンマを読むと、「最初のパラメータの符号を理解する準備ができた」状態に切り替わります。

  4. あなたは数字を読みました。これは「-」ではないため、最初のパラメーターは正です。最初の数字を数字の値 1 に設定します。これで、「最初の数字を読み取る」状態になります。

  5. 数字 0 を読み取ります。最初の数値を 1*10+0 -> 10 に設定します。まだ「最初の数値を読み取る」状態です。

  6. コンマを読みます。これで、「第 2 パラメーターの符号を理解する準備ができました」状態になりました。

  7. 1 と読みます。2 番目の数字は正です (これは "-" ではないため)。2 番目の数値を 1 に設定します。「2 番目の数値を読み込んでいる」状態になります。

  8. 0 を読みました。2 番目の数字は 1x10+0 -> 10 に設定されました。まだ「2 番目の数字を読んでいる」状態です。

  9. 0 を読みました。2 番目の数字は 10x10+0 -> 100 に設定されました。まだ「2 番目の数字を読んでいる」状態です。

  10. 行末を読みました。結果を実行します: コマンドは "s"、最初の数字は正、最初の数字は 10、2 番目の数字は正、2 番目の数字は 100 です。

  11. 「コマンドを読み取る準備ができた」状態に戻ります。

于 2012-08-28T14:47:48.887 に答える
4

私はDavid Swartzの答えが好きですが、私は悪魔の擁護者を演じると思いました.

データをバイナリとして読み取るのはエレガントな場合があります。それは、それをどうする必要があるかによって異なります。

次の例では、バイナリ区切り文字が検出されるまでシリアルからデータが読み取られ0X7Fます。読み取られたバイトはinDatachar 配列に格納されます。のドキュメントを見てくださいSerial.readBytesUntil()

char inData[16];
int bRead;
bRead = Serial.readBytesUntil(0x7F,inData,4);

このバイトは、整数にキャストするか、その他の方法で操作できます。これは符号付き文字であるため、最大値は +/-126 になることに注意してください (127 は区切り文字であり、値としては表示されません)。

次のような方法でこれらの値にアクセスできます。

Serial.print("Bytes Read: ");
Serial.println(bRead);
Serial.println("First Byte");
Serial.println((int)inData[0]);
Serial.println(
            map((int)inData[0],0,126,0,1024)
);
Serial.println("Second Byte");
Serial.println((int)inData[1]);

次のbashコマンドでこれをテストしました(シリアル速度が適切に設定されていることを確認した後):

echo -ne '\x01\x02\x7F' > /dev/ttyACM0

私が書いた大まかなサンプルコードはここにあります

于 2012-08-28T17:31:06.433 に答える