7月19日 近頃は,夏休みのはじまりが早い。小学6年のかず,中学3年のこうしろう,そして幼稚園年中のほのちゃんは今日から,もう夏休みである。例年なら,家でゴロゴロしているはずのかずは市の水泳大会に出るそうで,毎日プールに通って練習をしている。こうしろうは私がまだ寝ているうちから,封切を待ちわびていた「踊る大捜査線THE MOVIE2」をみようと映画館に出かけていった。

 私はというと,納期の迫った仕事から「現実逃避しよ」とMindStormsで遊んでいる。今まで,いくつかのプログラム開発環境を使い,MINDSTORMS ROBOTICS INVENTION SYSTEM(RIS)で作ったロボットを動かしてきた。まず,最初はRIS標準の開発環境でブロックをつなぐようにして,プログラムを作成した。ループやセンサーウォッチャーを使ってロボットをコントロールするプログラムをMINDSTORMSの本体RCXにダウンロードして実行した。次にC言語に似た文法を持つプログラム言語NQCを使って,こうしろうは本格的なプログラムに取り組んだ。

 それから,LejOSというRCX用のJavaVM(Javaプログラムの実行環境)でRCXの標準ファームウエアを置き換え,Javaでプログラムを書いてみたりもした。この頃,こうしろうがあまりMINDSTORMSをしなくなったので,Javaはちょっとのぞいてみただけで終わってしまった。

 1つやっていないことがある。RIS1.0,1.5にはSpirit.ocxというActiveXコントロールが付属している。このコントロールを使えば,VB(Visual Basic)やVBA(Visual Basic for Applications)などでMINDSTORMSで作ったロボットを動かすことができるのである。Visual Basicでプログラムを作る方法は日経ソフトウエアの2000年5月号に特集されていた。

 ここでは,手軽にExcelのVBAでSpirit.ocxを使ってMINDSTROSMを動かす方法を紹介したい。VBAでプログラミングする場合でも,RCXにダウンロードして実行するプログラムを作成することができる。でも,今回はロボットをリモートコントロールするプログラムを作ってみたい。

 MINDSTORMSをリモートコントロールするには,アクセサリーキットのリモコン(かずがこのリモコンで遊ぶのが大好きだったので,我が家では「かずのリモコン」と呼ばれている)を使う方法と,



 NQCの統合開発環境であるRCXCC(Command Center)やBrickCCに付属するリモートコントロール・ツールを使う方法がある。しかし,本当に作成したロボットの機能,特性を生かそうとしたら,専用のリモコンソフトが必要になる。

 今回,リモートコントロールするのは,作りかけのお掃除ロボット。



何の変哲もない車だ。

 Spirit.ocxを使うと簡単にリモコンプログラムを作成できる。まずはExcelでVisual Basic Editorを選び,ユーザーフォームを作成する。Spirit.ocxを使うために,ツール(T)-その他のコントロール(A)で,利用可能なコントロールにSpirit Control(Spirit.ocx)を追加する。ツールボックスに赤くLEGOと表示されるコントロールが追加されるので,それをユーザーフォームに貼り付ける。



 車を自在に走らせるリモコンを作るので,現在の速度を表示するラベルを配置する。このテキストボックスの下に,YUIHJKBNMとキーボードの配列をメモ書きしてあるように,キー押下でロボットをコントロールするのである。

 コマンドボタンを配置して,マウスでクリックすることにより,車を前進,後退,右折,左折させる方法も考えたのだが,マウスでクリックするには,パソコンの画面と動いている車を交互に見て操作しなくてはならない。ゆっくり動くロボットならそれでも構わないのだが,機敏な動作をコントロールするには,ロボットの動きだけに集中できたほうがよい。キーボードで操作できるようにプログラミングして,キー位置を手が覚えてしまえば,パソコンの画面を見る必要がなくなる。

 停止キーであるJを中心にU:前進,N:後退,K:右旋回,…と手の位置を移動させなくても操作できるようにユーザーフォームに以下のプログラムを記述した。
------------------------------------------
Dim intSpeed As Integer
Dim intRet As Integer

―――――――――――――――――――――
 上記が変数の宣言である。intSpeedには,現在の車のスピードを記憶する。intRetには関数からの戻り値を代入する。
-----------------------------------------
Private Sub UserForm_Activate()
  Spirit1.InitComm
  intSpeed = 4
  Call SpeedSet
End Sub

-----------------------------------------
 フォームのActivateイベントで,シリアルポートを初期化するInitCommを実行し,スピードを4にセットするためにSpeedSetサブプロシージャを呼び出している。

 Excelでは,フォームの表示,アンロード時に次のような順序でイベントが発生する。
initializeイベント(フォーム表示前)→Activateイベント(フォーム表示後)
QueryCloseイベント(アンロード前)→Terminate Queryイベント(アンロード後)

-----------------------------------------------------------------
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  Spirit1.CloseComm
End Sub

-----------------------------------------------------------------
 フォームのアンロード前に発生するQueryCloseイベントで,シリアルポートを閉じている。
-----------------------------------------------------------------
Private Sub SpeedSet()
  If (Spirit1.SetPower("02", 2, intSpeed)) Then
    lblspeed.Caption = intSpeed
  Else
    MsgBox "ロボットが見つかりません"
  End If
End Sub

-----------------------------------------------------------------
 SpeedSetサブプロシージャでは,SpiritコントロールのSetPowerメソッドでモーターA,Cのスピードをセット後,ラベルにスピードを表示している。ロボットと通信できずSetPowerがFalseを返した場合,つまり赤外線が届かないときやロボットのスイッチが入っていないときは"ロボットが見つかりません"とメッセージを表示する。

 SetPowerメソッドの第1引数はモーターを表す。出力ポートA,B,Cを"0","1","2"と指定する。第2引数は,第3引数であるスピードの設定の仕方を表す。2とした場合,スピードは0から7の範囲で指定する。

 次のKeyDownイベントの処理が,このプログラムの中心である。
-----------------------------------------------------------------
Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  Dim StartTime As Single
  
  With Spirit1
    Select Case KeyCode
      Case vbKeyU
        intSpeed = 4
        Call SpeedSet
        .SetFwd "02"
        .On "02"
      Case vbKeyN
        intSpeed = 4
        Call SpeedSet
        .SetRwd "02"
        .On "02"
      Case vbKeyK
        intSpeed = 1
        Call SpeedSet
        .SetFwd "2"
        .SetRwd "0"
        .On "02"
      Case vbKeyH
        intSpeed = 1
        Call SpeedSet
        .SetFwd "0"
        .SetRwd "2"
        .On "02"
      Case vbKeyJ
        .Off "02"
      Case vbKeyI
        .Off "0"
        StartTime = Timer
        Do While Timer < StartTime + 0.05
        Loop
        .On "0"
      Case vbKeyY
        .Off "2"
        StartTime = Timer
        Do While Timer < StartTime + 0.05
        Loop
        .On "2"
      Case vbKeyB  '加速
        If (intSpeed < 7) Then
          intSpeed = intSpeed + 1
        End If
        Call SpeedSet
      Case vbKeyM  '減速
        If (intSpeed > 1) Then
          intSpeed = intSpeed - 1
        End If
        Call SpeedSet
    End Select
  End With
End Sub

-----------------------------------------------------------------
 KeyDownイベントには押されたキー値がKeyCodeとして渡ってくるので,Select case文でキー値を判定し,処理を分岐している。

 たとえば,Uが押された場合,
――――――――――――――
Case vbKeyU
  intSpeed = 4
  Call SpeedSet
  .SetFwd "02"
  .On "02"

――――――――――――――
スピードを4に設定後,.SetFwd "02"でモーターA,Cの回転方向を順方向(Forward)に設定,.Onでモーターを回転させている。With Spirit1とWith修飾を行っているので,Spirit1を省略し.Onのように記述できる。

 K,Hキーで右左旋回させるときは,スピードを1に落としている。そうしないと,くるくる回ってしまうからだ。

 I,Yキーが押されたら,片方のモーターを少しの間止めて,進行方向を微調整する。リモートコントロールではWaitコマンドが使えないので,Timer関数で現在の時間を取得し,0.05秒間空のループを行うことでしばらくモーターを止めている。

 B,Mキーで加速,減速を行う。



 プログラムのテストは電池がもったいないので,ACアダプタをつないだ状態で行う。

 動作確認した後,「かず,やってみんか?」とリモコン好きのかずを誘う。



 キーと機能の対応が身に付くまで苦労して操作していたが,慣れてくるとパソコンの画面を見ないでスピーディに動かせるようになった。



 車庫入れだって高速だ。