2012-06-02

Mindstorms NXT 與 Arduino之間的藍芽通訊

過去幾次在NXTArduino之間無線通訊的應用,都是採Xbee方式,如:『以瀏覽器控制Mindstorms NXT』以及『以瀏覽器控制HTWay』。

而本次則是以NXT內建的藍芽功能來與Arduino進行另外一種無線通訊方式。
(photo)



藍芽通訊屬於較為嚴謹的session-based protocol,需要先透過:配對、識別並建立連結(connection)之後才能開始進行資料交換。至於Xbee通訊則屬於較為彈性的message-based,只需指定好目標位址,就可以開始傳送訊號,並能夠隨時變更對象甚至使用廣播方式,而缺點則是可靠性較低,無法確認接收端的收信狀態。
實作上, 當以XBEE通訊時,NXT是使用S4Hi-Speed portArduino則使用Serial port
而當藍芽通訊時,NXT使用的是COMM Module功能,Arduino的藍芽模組(BluetoothBee)雖然也是透過Serial port,但必須符合NXT的封包交換規範。(DFRobot Bluetooth)

LEGO MINDSTORMS NXT Communication Protocol
LEGO對於NXT通訊建立有NXT Communication protocol來定義它的功能,在階層(layer)上適用於有線(USB)與無線(Bluetooth)兩種方式,而主要的用途類型有:
System Command:用於上傳/下載檔案以及刪除內存於NXT Flash的檔案。

Direct Command:直接執行與控制NXT InputOutput module功能,以及透過信箱傳送與接收信息(Message command)
對於上述這些通訊類型,在protocol中制訂有各個功能的封包格式,使用時,需要遵循定義的規範才能正確執行。
詳細規格可以參考官方的技術文件(Lego Bluetooth Developer Kit)


配對 建立連結
由於本次Arduino所使用的藍芽模組其Bluetooth stack功能很陽春,因此,在與NXT通訊時只能作為Slave,而由NXT擔任Master來起始連結。
首先須進行的是NXTArduino藍芽裝置的配對與認證,完成之後會在NXTBluetoothMy contacts中建立名單:

(NXT My contacts)


配對之後,即可以由NXTBluetoothMy contactsSelectConnect再選擇13 Connection來進行連結。
而若NXT有安裝NBCNXC enhanced firmware,就可直接由NXC程式來建立連結。
(
參考『使NXC程式建立
)

NXT Message Command訊息交換指令
NXT Communication ProtocolDirect command中,Message Command是定義交換字串資料的指令,含:MessageWriteMessageRead兩個指令,都是以NXT信箱作為傳送與接收訊息的標的。
接下來,即會使用MessageWrite來分別進行:
(1)
NXT傳送字串資料給Arduino 以及
(2)
反向由NXT接收來自Arduino所傳送資料等雙向的藍芽通訊。

對於NXT,無論(1)傳送或(2)接收,都有現成的NXC API可以使用。但對於Arduino,則在(1)接收時,需要自行解析封包內容,(2)傳送時,則需建構指令封包。至於MessageWrite指令的封包格式為:
Byte 0 (Command Type)
0x80 (Direct command,且不須回覆訊息)Byte 1  (Command byte)0x09 (指令碼)
Byte 2  (Inbox number):信箱代號(0 – 9)Byte 3  (Message size):傳送的字串長度,含結尾null code
Byte 4 – N  (Message data)
:傳送的字串資料,結尾須加上null code此外,為了改善NXT藍芽通訊的效率,在指令封包前還須加上兩個byte的封包長度資料,其中Low byte在前,High byte在後。

(1)NXT傳送至Arduino
NXCMessageWrite API為:
SendRemoteString (connection, mailBoxNo, sendStringValue)
NXT呼叫上述的API傳送〝(99)_Hello_Arduino〞字串至Arduino時,Arduino會以Serial.read()接收並解析讀取的封包內容如下:
(Msg_Fm_NXT)

(NXT_SendTo_Arduino_BT_01)


(2)接收來自Arduino傳送的字串
Arduino要先建構傳送至NXTMessageWrite封包:
char replyMsg[16]={'H','e','l','l','o',' ','N','X','T',' ','(',' ',' ',' ',')','\0'};
int  sendCountIndex, sendPacketSize;
void build_MESSAGEWRITE_packet()
{
  for(int xii=0; xii
  replyBuf[0] = 0x14;
// Length byte LSB, total packet is 20 bytes
  replyBuf[1] = 0x00; // Length byte MSB
  replyBuf[2] = 0x80; // Byte 0: command type
  replyBuf[3] = 0x09; // Byte 1: command
  replyBuf[4] = 0x00; // Byte 2: Inbox number(0 - 9)
  replyBuf[5] = 0x10; // Byte 3: Message Size, includes the null termination byte
  for(int xii=0; xii<16; xii++) replyBuf[xii+6] = replyMsg[xii];
  sendCountIndex = 18;
  sendPacketSize = word(replyBuf[1], replyBuf[0]);
}
再以Serial.write()逐個字元透過藍芽傳送至NXT
至於NXT則呼叫以下API接收資料:
ReceiveRemoteString (mailBoxNo, isRemove, receiveStringValue)

(Msg_Fm_Arduino)

(NXT_ReceiveFrom_Arduino_BT_01)


NXCArduino程式碼:()

4 則留言:

  1. 你好,想請教有關NXT(NXC)及Arduino利用藍芽做資料傳輸的問題。
    若我Arduino端使用HC-05做資料傳輸,NXT成功傳輸資料給Arduino,現在我希望Arduino回傳資料給NXT。請問就NXT藍芽端需要哪種資料型態及方法他才能讀取?

    回覆刪除
    回覆
    1. 你好,
      由 Arduino 透過 藍芽傳輸給 NXT 的資料需要符合 NXT MessageWrite 的封包格式, 格式內容如下:
      Byte 0 與 byte 1 為封包總長度 LSB+MSB
      Byte 2 為 0x80 (Direct command)
      Byte 3 為 0x09 (MessageWrite)
      Byte 4 為 Mail box number(0 - 9)
      Byte 5 為 訊息長度, 含最後的 null code
      Byte 6 - N 為訊息(最後要加 Null code)

      NXC 使用 :
      ReceiveRemoteString(Mail box number, TRUE, 訊息字串) 函式 接收, 資料會存放在 訊息字串中

      刪除
    2. 你好,不好意思有幾個問題想再請教您...

      問題一:

      就Arduino而言若我要傳MessageWrite的格式封包我是否能依序利用write()來將封包格式傳送出去?比如說:

      I2CBT.begin(9600);
      I2CBT.write(Byte 0);
      I2CBT.write(byte 1);
      I2CBT.write(byte 2);
      I2CBT.write(byte 3);
      I2CBT.write(byte 4); …

      問題二:

      在NXT MessageWrite 的格式中…

      Byte 0 與 byte 1 為封包總長度 LSB+MSB

      LSB及MSB的大小定義意取決於程式中的哪?還是說他就和Byte 5的訊息長度一致?

      Byte 2 為 0x80 (Direct command)

      Direct command 指的是指令碼?在這0x80是指?

      Byte 3 為 0x09 (MessageWrite)

      這也是指令碼嗎?還是有另外的功能?

      Byte 4 為 Mail box number(0 - 9)

      Mail box是需要有特定的位置,還是說不需要?
      還是說需要再NXC中的ReceiveRemoteString (mailBoxNo, I sRemove, receiveStringValue)中的mailBoxNo一致?

      刪除
    3. 你好, 以下是關於所提問題的回覆:
      問題一:
      Arduino是透過 Serial.write() 函式, 一次一個byte將封包資料傳送給 藍芽模組再傳送出去, 你所舉的例子中, 是否使用
      #define Serial I2CBT 重新定義過, 若是的話就沒錯

      問題二:
      NXT 的通訊協定中為了解決它本身藍芽模組與ARM處理器之間時間差延誤的問題,所以規範了資料封包的格式:
      Byte 0, Byte 1: 總封包長度, 但不包含 Byte0 與 Byte1

      Byte 2: Command type, 代表指令類型,
      其中 0x80 是指Direct command 且不需要回覆的指令類型, 像MessageWrite 就是屬於這種類型的指令

      Byte 3: 0x09 是MessgaeWrite 的指令碼, 當NXT收到並解析後才會知道這個資料封包是一個郵件, 也才能夠使用 ReceiveRemoteString() 函式去讀取信箱內容

      Byte 4: 是指此封郵件是傳送到NXT那一個信箱號碼(0 - 9)

      Byte 5: 是指整個郵件內容的長度, 包含最後一個byte 的 null

      Byte 6 - Byte N: 傳送的郵件內容, 最後一個 byte 必須是 null(0x00)

      所以,
      Byte 5 的值就是 N-6+1
      Byte 0 與 Byte 1 的總封包長度是: N-1

      至於 ReceiveRemoteString(Mail box number, TRUE, 訊息字串) 函式中的 Mail Box number 引數需要與 Byte4 指定的值一樣

      你可以再測試看看, 若還有問題, 歡迎提出討論

      刪除