結局,プログラミングを続けさせるのは,「うごいたぞー!」という喜びである。自分の作ったプログラムで実際にロボットが動くマインドストームは,そういう意味で優れた教材である。プログラミングは論理的な思考能力を育むので,子供のときから体験できたらよいと筆者は思う。

 そんなマインドストームを販売しているLEGO社がAndroidケータイでマインドストームNXTを操作するMINDdroidというアプリを提供していることはご存じだろうか。BluetoothでNXTと通信し,加速度センサーを使うことで,Androidケータイを傾けるアクションで,ロボットを動かすことができるアプリだ。

 また,LEGO社のサイトから,リンクをたどるとMINDdroidのソースをダウンロードすることができる。このソースコードはGNU GPLで提供されているため,プログラムの動作を調べたり,改変することができる(GPLはコピーレフトなので,改変して自分が作成したものもGPLにしなくていけない)。

 いい時代になったと思う。すごいなと思ったプログラムのソースをダウンロードして,いじって動かしてみることができるのだから。自分より,力や情報を持っているプログラマがどんな方法を使っているのかを無料で学ぶことが可能なのだ。

 MINDdroidは起動するとスプラッシュ画面を表示し,加速度センサーの値により,Androidケータイの動きをグラフィカルに表示し,NXTにコマンドを発行していくのだが,より重要なのはNXTとBluetooth通信を確立し,ダイレクトコマンドをAndroidケータイから発行する部分だ。今回はグラフィク処理と加速度センサーを除き,BlueToothでNXTに接続し,ダイレクトコマンドを発行する処理だけを作ってみようと思う。と言ってもBlueTooth通信の部分は,MINDdroidのソースをそのまま拝借したものだ。良くできているソースをわざわざ改悪する必要はないだろう。

 作成したプロジェクト(BtMindNxt)は,4本のソース・プログラムで構成される。メイン画面であるBtMindNxtActivity.javaと発見したBlueTooth機器を一覧表示するDeviceListActivity.java,それから,BlueTooth通信を担うBTCommunicator.javaとマインドストームNXTに送るダイレクトコマンドを作成するLCPMessage.javaである。BtMindNxtActivity.java以外のソースは,ほぼMINDdroidのソースと同じなので,全体についてはMINDdroidのダウンロードしたソースを参照してほしい。

 今回作成したソースコードについては、その一部をこちらから別ウィンドウやタブで開いて参照してほしい。

 まず,メイン画面であるBtMindNxtActivityのライフサイクルメソッドonStart()で自機(ケータイ)のBluetoothアダプタが有効かどうかを調べる。無効だったら,list1のようにACTION_REQUEST_ENABLEを指定して,システムアクティビティを呼び出す。すると,次のようなダイアログが表示されるので,ONにする。

 システムアクティビティの戻り値をlist2のように,onActivityResultメソッドで待ち受ける。リクエストコードが先ほどのREQUEST_ENABLE_BTと一致し,結果コードがRESULT_OKのときに,selectNXTメソッド(list3)を実行する。 selectNXTメソッドは,DeviceListActivityを呼び出す。DeviceListActivityは,通信相手の機器をダイアログボックス上でListViewに表示するクラスである。

 なぜ,このアクティビティがダイアログボックスのように表示されているかと言うと,AndroidManifest.xml(list4)に,android:theme="@android:style/Theme.Dialog" と指定してあるからだ。

 ちなみにBlueTooth機器を見つけ,ペアにして使うにはlist5のようにパーミッションを設定しなくてはならない。マニフェストに記述するパーミッションについてはこのページに詳しく書いてある。

 さて,上記のダイアログボックスに改めて注目してほしい。一度,ケータイとペアリングをしてしまったので,Paired LEGO DevicesとしてNXTが表示されている。NXTの下に表示されているのはBlueToothアダプタのアドレスである。ちなみに,NXTには,00:16:53ではじまるアドレスが割り当てられているようだ。また,ペアリング時にPasskeyの入力を求められるが,NXTには通常1234が設定されているので,1234と入力すればペアリングできる。

 この画面でScan for deviceボタンをクリックすると,他のBlueToothデバイスをスキャンする。ListView上のNXTデバイスをクリックすると接続処理をする。DeviceListActivityのソースを見ていこう(list6)。すべてのコードを解説しているときりがないので,説明しない部分はコメントを参考にしてほしい。

 Scan for deviceボタンが押されたらdoDiscoveryメソッド(list7)を実行する。mBtAdapterは先に,private BluetoothAdapter mBtAdapter;と宣言している。mBtAdapter.startDiscovery();でリモートデバイスを発見する。他のメソッドはこのページを参考にしてもらうと良いが,メソッド名がそのものズバリだから,わかりやすいだろう。

 さて,list6に戻ろう。pairedListViewとnewDevicesListViewというListViewを作る。前者には,ペアリング済みのデバイスを表示し,後者には新たに見つかったデバイスを表示する。setOnItemClickListenerでListView上のデバイスがクリックされたときのリスナーを仕掛けている。その中身が,list8だ。 onItemClick時にはアドレスとペアリング済みのデバイスであるかどうかを返す。

 もう一度,list6に戻ろう。BluetoothDevice.ACTION_FOUND(Bluetoothデバイスが見つかったとき)と,BluetoothAdapter.ACTION_DISCOVERY_FINISHED(Bluetoothデバイスの検索を終える)ときにブロードキャストを受信できるようにregisterReceiverでmReceiverを登録する。mReceiverの内容は,list9だ。見つかったデバイスをリストに登録したり,アクティビティのタイトルを変えたりしている。R.string.select_deviceは「Select a device to connect」という文字列を指す。

 BluetoothデバイスのアドレスをもらったBtMindNxtActivityクラスはlist10のstartBTCommunicatorメソッドを呼び出す。startBTCommunicatorメソッドでは,BTCommunicatorクラスのオブジェクトであるmyBTCommunicatorにsetMACAddressでアドレスをセットし,startメソッド呼び出している。

 すると,Threadクラスを継承しているBTCommunicatorクラスの,runメソッドが動作する(list11)。runメソッドは,まずcreateNXTconnectionメソッド(list12)を呼び出して,通信を確立する。

 createNXTconnectionメソッドではソケットを作成し,connectする。リスナーを仕掛けたり,レシーバーでブロードキャストを受け取るので,ソースコードが行ったり来たりする。BlueTooth接続までの処理を一直線に図解すると以下のようになる。接続後は,入出力ストリームでデータをやりとりする。

 さて,list10の最後にupdateButtonsAndMenu();とある。updateButtonsAndMenuという名前が示すように,先に何かボタンやメニューを作っているのである。それがlist13だ。次に示すように、ConnectとQuitのオプションメニューを作っている。

list14のupdateButtonsAndMenuメソッドの中では,NXTに接続済みなら,最初のメニューをDisconnectにしている。ConnectとDisconnectはトグルなのである。そして,二番目のメニューとして,以下に示すようにMENU_RUN_ROBOTを追加している。

オプションメニューが選択されたときの処理がlist15である。MENU_RUN_ROBOTはモータを指定してsendBTCmessageメソッドを呼び出している。 ここで必要になるのがNXTに送るダイレクトコマンドに関する知識だが,LEGO_MINDSTORMS_NXT_Direct_commands.pdfというファイル名で資料が公開されているので,検索してダウンロードするとよいだろう。

上に示すのはモータを動かすsetoutputstateダイレクトコマンドだ。このようにbyte列を組み立てて,送信すればNXTロボットが動くわけだ。レスポンスが不要ならば80,04,モータBなら02と指定すればよい。パワーは100が最大で,-100が逆方向の最大だ。以降のバイトには,NXTなのでモータシンクロや,回転角度も指定することができる。

 sendBTCmessageのパラメータはBTCommunicator.NO_DELAY, motorLeft, 100, 0と BTCommunicator.NO_DELAY, motorRight, 100, 0である。今回使っているロボットはB,Cポートにモータが繋がっているので,左右モータを回して全速前進するわけだ。

 sendBTCmessageの処理内容は,list16のようにパラメータを指定してbtcHandlerのsendMessageを呼び出すことだ。sendBTCmessage に渡した最初のパラメータがBTCommunicator.NO_DELAYなのでdelayしないで処理は即実行される。2番目のパラメータがmessageに,三番目のパラメータがvalue1になったことに注意してほしい。

 btcHandler はBTCommunicator クラスにある(list17)。messageがMOTOR_Xだった場合, value1,つまり100をパラメータとして渡して,changeMotorSpeedメソッドを実行する。

 changeMotorSpeedでは(list18),モータのスピードが範囲外の値だったら,調整した上で,LCPMessage クラスのgetMotorMessageメソッドを呼び出している。パラメータはmotorとspeedだ。

 LCPMessage クラスのgetMotorMessage(list19)はバイト列を組み立てて返すので,list20のsendMessageメソッドで,出力ストリームに流し込む。 これでロボットがツーと前進を始める。

 list21はオプションメニューでQuitが選ばれたときの処理である。モータを止め,BlueTooth通信を閉じている。BlueToothはバッテリー食いなので,終わったらさっさとやめることも重要だ。