2012-08-28 36 views
4

我正在寫一個應用程序與Android手機通過藍牙來控制我的機器人,一切都順利的話,數據是呼應和確認,但我有一些麻煩的協議,特別是我希望我的當我發送一個命令,如s,10,100s,-30,-10 ...(值以百分比表示)時,機器人的輪子會轉動。Arduino的串行數據分析

我的問題是,當我想在我的Arduino解析我的車輪轉速命令我必須從多達4單獨bytes解析int,例如s,-100,-100讓我的機器人全速後退去,但我該怎麼辦解析這個,所以我可以撥打setSpeed(left, right);leftright等於-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)); 
    } 
} 

回答

9

剛逐個字符地讀入狀態機。它簡單而高效。

要通過數字在數位閱讀,做到這一點:開始爲零。對於每個數字,將數字乘以十,並添加數字的值。因此,例如,閱讀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. 您閱讀了一個逗號。您現在處於「準備弄清楚第二個參數的狀態」狀態。

  7. 你讀1,第二個數字是正的(因爲這是不是一個「 - 」)。您將第二個數字設置爲1.您處於「讀取第二個數字」狀態。

  8. 你讀0。第二數目現在被設置到1×10 + 0 - > 10.您仍處於「讀取第二數目」狀態。

  9. 你讀0。第二數目現在被設置爲10×10 + 0 - > 100。您仍處於「讀取第二數目」狀態。

  10. 你讀線的一端。您執行結果:命令是「s」,第一個數字是正數,第一個數字是10,第二個數字是正數,第二個數字是100.

  11. 您切換回「準備讀取命令「狀態。

+0

你只是打敗了我,再一次:(一個char-by-char狀態機就像你可以得到的靈活性,可維護性和可擴展性一樣。隨着新命令的添加,涉及大量庫函數的解決方案會非常迅速地變得混亂。 –

+0

似乎有很多麻煩,我認爲這是一個相對常見的問題,所以也許現有的功能可以做到這一點...狀態機是時候。 – Solenoid

+0

一半的工作將處理錯誤條件。 –

4

我喜歡David Swartz的回答,但我想我會扮演魔鬼的擁護者。

在讀二進制可雅的數據,它只是取決於你需要用它做什麼。

在以下示例中,將數據從串行直到它看到二進制定界符0X7F讀取。讀取的字節存儲在inData char數組中。看看該文檔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 

一些rough我寫的樣本代碼可以找到Here

+0

那些避免二元操縱的人是魔鬼的擁護者,我的朋友 –

+0

@ Siidheesh有些人主張固執,而另一些人則無知。不幸的是,在這種情況下,我陷入後者。 :) – ZnArK