LEGO Marioをセンサとして利用したい(4) - Let's start talking to LEGO Mario
今回は、いよいよ実際にLEGO Wireless Protocol(LWP)を通じてレゴマリオがもつセンサ等のデータを読み取っていきたいと思います。
この記事の内容は未完です。BLE予備知識ゼロ、もちろんLEGO Wireless Protocolの知識もゼロ、電子工作は趣味レベルの自分が、レゴマリオでセンサの値を読み取るまでの現在進行系のログです。
前回のおさらい
前回の記事までで、レゴマリオがLWPでデータをやり取りしていることを明らかにした上で、
BLEとPC(Mac)の接続テストから、実際にレゴマリオのもつ内部情報やバッテリー情報を取得するという一連の流れを通じたLWP理解、
更には命令とレスポンスのデコードを行ってきました。
LWPにおけるセンサデータのやり取り
LWPにおいて、Hub(デバイス)のもつセンサデータはPortを通じてやりとりされます。ドキュメントを読む限り、例えばモータなどの状態もPortを通じて行われるようです。
ただし、レゴマリオが発売した直後ということもあり、ドキュメントにはレゴマリオに関する情報はありません。
幸いなことに、レゴマリオ周りのPort情報については、このシリーズ中何度も言及させて頂いている@oobaさんが真っ先にまとめ上げて公表してくださっています。
初見でこの資料を見ても何がなんだか…という方も多いかもしれません(私もそうでした)。ですので、まずはこの資料を読むことができるようになるまで、段階を踏んで理解を進めていきましょう。
LEGO MarioのPortを調べる
レゴマリオには5つのPortがあります。先述した@oobaさんの資料によると各ポートは次のような値と対応しています。
Port 0: 0x47 Accelerometer, Gesture?
Port 1: 0x49 Color Barcode, RGB Color
Port 2: 0x4a Pants
Port 3: 0x46 Events, Debug, and something
Port 6: 0x14 Voltage
……とポートと値の対応はレゴマリオを動かしながら値の変化を追えばなんとなく解読はできそうですが、そもそもこの5つがあるということがなぜ分かるのか?それにポートの横の0x47って何?という疑問を持たれる方もいらっしゃると思いますので、まずはそこからお話しましょう。
Notifyしたら実は飛んできたデータ
Bluetooth ExplorerなどでキャラクタリスティックをReg Norify(Subscribe)し、何もWriteしないでおくと、
0f 00 04 06 01 14 00 01 00 00 00 00 00 00 20
Valueが上のような値に変わっていることにお気づきでしょうか。
Portの解読には、このメッセージの内容が大きく関わってきますので、このメッセージをLWPのドキュメントの通りに解読してみましょう。
例にもれず、先頭の1byteはメッセージの長さ(=15byte)、2byteは0x00固定です。3byte目の0x04はHub Attached I/Oのメッセージであることを示しています。
Hub Attached I/Oのメッセージについて更に詳細をみます。メッセージの長さで、メッセージの内容が判断できるようです。今回は先述の通り0x0f=15Byteなので、Attached I/Oであることがわかります。
さらに詳細をみます。Attached I/Oのメッセージは、4byte目がPort ID、5byte目がEvent、6,7byte目はIO Type ID、8,9,10,11byteでHardware Revision、12,13,14,15byteでSoftware Revisionとのことです。
順に見ていきます。改めて、メッセージをみます。
0f 00 04 06 01 14 00 01 00 00 00 00 00 00 20
まずPort IDは0x06であることが確定しました。Eventは0x01で、表からAttached I/Oであることがわかりました。ここまでで、Port 6をアタッチしたよ!というメッセージであることがわかります。
IO Typeは【0x14 00】になります。ここで、LWPはリトルエンディアンっぽいのでデータを取り出すと、0x0014になります。この値、ドキュメント中にすでに定義/説明されており、Voltageであることがわかります。
残りはハードウェアとソフトウェアのバージョン情報です。これもドキュメントでエンコードの方法が説明されています。(あまり関係のない話なので興味がない人はスルーで大丈夫です)
ハードウェアは【0x01 00 00 00】、ソフトウェアは【0x00 00 00 20】ですので、一度バイナリに直します。理解のため、ドキュメント中の例も併せてデコードします。このとき、リトルエンディアンのため取り出したバイト列は逆順になります。
0b 0000 0000 0000 0000 0000 0000 0000 0001 <=> 0x00000001
0b 0010 0000 0000 0000 0000 0000 0000 0000 <=> 0x20000000
0b 0001 0111 0011 0111 0001 0101 0001 0000 <=> 0x17371510
バージョンの表記は、0MMM mmmm BBBB BBBB bbbb bbbbで、Bug fixing numberとBuild NumberはBCD(2進化10進表示)なので、99.9999が最大値となります。つまり、先頭4bit,4bit,16bit,32bitを何も考えずピリオドで繋げばバージョン情報になるということになります。(特にマイナー以下は数字をBCDなのでそのまま出す)
これを元にバージョン情報をデコードすると、それぞれ、
ver. 0.0.00.0001
ver. 2.0.00.0000
ver. 1.7.37.1510
ということがわかります。
以上で、Notifyされたデータの解読は完了です。まとめると、飛んできたデータは『Voltageに関して利用するPort 6のアタッチ(各種バージョン値を添えて)』というメッセージであることがわかりました。
他にもあったAttached I/O
Buletooth Explorerでは一瞬で書き換わるため見逃してしまいますが、Notifyした瞬間に飛んでくるデータは実は5個ありました。(自分で実装をすると実際にこのデータをキャプチャできます)
<Buffer 0f 00 04 00 01 47 00 00 00 00 20 01 00 00 00>
<Buffer 0f 00 04 01 01 49 00 00 00 00 20 01 00 00 00>
<Buffer 0f 00 04 02 01 4a 00 00 00 00 20 01 00 00 00>
<Buffer 0f 00 04 03 01 46 00 00 00 00 20 01 00 00 00>
<Buffer 0f 00 04 06 01 14 00 01 00 00 00 00 00 00 20>
最後のデータは先程デコードした通り、Voltageになります。同様にデコードし、表にまとめてみます。
レゴマリオでAttachされるIO TypeのほとんどがドキュメントにはないIO Typeであることがわかります。※バージョンのデコード見直してないので間違いあれば指摘ください
以上のことから、レゴマリオにはPortが5つあることがわかりました。
各Portがどういう何のデータを意味するか
ここまでで、レゴマリオが5つのポートを持つこと、さらに内一つは電池に関する情報のためのポートであることがわかりました。
ドキュメントで説明のないIO Typeについては、自分でレゴマリオを動かしながら対応づける必要があります。もちろん、@oobaさんが既に公開してくれている資料の通りかと思うので、この工程は割愛可能です。ただ、LWPへの理解を深めるために、答え合わせをするイメージで調査を進めていきましょう。
ここで、Portに関して重要な事実をお伝えします。実は、Portの中でさらにModeという概念があり、レゴマリオから値を取得するにはPortだけでなくその中のModeも指定する必要があります。
次回予告
ということで、次回は、各Portの対応を実験する前に、Portの中のModeについても調べていきましょう!
メッセージタイプの表に「Port Information Request」「Port Mode Information Request」というものがあります。恐らく、この2つを用いればPortの詳細について迫っていくことが可能かと思われます!