ミニマイコンカービジュアルコントロールソフト ブロっくん1号

なぜ一号なのかは微妙にナゾだけど(Ver.1なのだよねきっと)、ミニマイコンカーキットにはこんな名前のプログラミングソフトがついてくる。表示こそ子供向けに平仮名だらけでちょっとばかり読みにくいんだけど、内容的にはなかなか凝っていてかなり細かいところまで調節できる。しかも(コンピュータ好きにとって)直感的でわかりやすい仕組みになっていて、ここは恐らくなんだけど、本番のマイコンカーラリーにも応用できるキットに仕上がっている。RSO(なのかな?)++

概要


メイン画面はこんな感じ。MindStormのプログラマみたいに、各機能ブロックを画面に配置していってプログラミングするビジュアルプログラミング環境。ブロックの種類は前進、後退、左右旋回(前・後方向)、ブレーキ、左右モータの直接制御、といった駆動系と、タイマーやループやウェイトなどの制御系、それとセンサーモジュールの各状態に対応した条件分岐系の三種類がある。プログラムは基本的にシングルタスクで、左上を先頭に、下、またはループや分岐で左、と順に実行されていくイメージ。イベントドリブンに書けるわけではない。まあ、この辺りは後ほど説明する仕組みから考えると仕方がないのかもしれないけど、教育的な意味で「初めてプログラミングに触れる子供達」にとってはどちらがわかりやすいのだろう? この辺りは事務局の方にでも聞いてみるのが正しいかな。
自分でスーパーバイザー層を書く気があれば何とでもなりそうだけど、応答速度が下がらないようにリアルタイムモニタみたいなのを実装しないといけなさそう。面倒くさそう。面白そう。

カスタマイズ

カスタマイズはオプションメニューから実行。変更できるのは以下の設定。

最大回転数
左右車輪の駆動パワーの最大値を%で指定(ここでの%は当然 PWM的にの意味)
パラメータ設定
前進、後退、旋回のパワーを%で指定(上記、最大回転数に対しての比率)。ここはかなり細かく指定できて面白い。

中央ラインの色指定
マイコンカーラリー本来の規定では黒い路面に白線でコースを作ってあって、これを認識するのだけれど、センサーの極性を逆にして白い路面に黒線でもできますよ設定。
COMポート
説明不要

内部構造

というほどのことは無いけど、何をどうやっているかとかのお話(もちろんすべて結果ファイルからの憶測)。結構単純で、流れとしては

  1. メインウィンドウの「てんそう」を選ぶとブロック配置を左上からたどってCのスニップル(部分断片)に変換する。同時に「カスタマイズ」で指定した、各種パラメータ数値のマクロをヘッダファイルsoft.hに書き出す。
  2. 上のスニップルを初期設定やメインループなどを入れたテンプレートに埋め込んでCコードを生成(ファイル名はmmcr.c)
  3. 出来上がったCコードをコンパイル(H38CC.EXE)してオブジェクト生成
  4. それとは別にリセットベクタとベクタテーブルを記述した初期化コードをアセンブル(mcrstart.SRC)。ベクタテーブルはリセットとタイマー割込みのみ。リセットハンドラは単にスタック設定(0xff80)してCのmain()を呼んでるだけ。
  5. Cのオブジェクトと初期化コードをライブラリ(C38HNE.LIB -- libc相当?)と一緒にリンク(HLNK.EXE)
  6. abs -> motファイル変換(HCNVS.EXE)
  7. 転送(wr3687.exe)

という一連の動作が実はバッチファイル c.bat というファイルに書いてある。「てんそう」を実行するとこれが素で実行されてるっぽい。このバッチファイル、引数が4つほどあって、

%1
cd %2
PATH=%3
:
wr3687 mmcr.mot %4

%1だけナゾだけど、なんか追加コマンドを入れるのかな。残りはまあパス関連とCOMポートの設定だね。

変換されたCコード断片

どんな感じに変換されるか、というとたとえば一番上の画像ファイルの例は、「白い机から落ちないように、黒を感知したら反対方向に逃げる」というつもりでくみ上げた(車体を会社においてきてしまったので確かめられない・・・)ものだけれど、要するに感知した黒領域が大きいほどハイパワーで曲がるというプログラム。後から考えてみると実は大きいほどゆっくり回ったほうが賢いような気もしてきた。まあそれは明日確かめるとして、このプログラムはこんな感じに変換される。

while (1) {
if (get_sensor()==0x07) {
speed(RFORWARD_L_3, RFORWARD_R_3);
}
if (get_sensor()==0x03) {
speed(RFORWARD_L_4, RFORWARD_R_4);
}
if (get_sensor()==0x01) {
speed(RFORWARD_L_5, RFORWARD_R_5);
}
if (get_sensor()==0x00) {
speed(BACK_L_5, BACK_R_5);
}
if (get_sensor()==0x0e) {
speed(LFORWARD_L_2, LFORWARD_R_2);
}
if (get_sensor()==0x0c) {
speed(LFORWARD_L_4, LFORWARD_R_4);
}
if (get_sensor()==0x08) {
speed(LFORWARD_L_5, LFORWARD_R_5);
}
speed(FORWARD_L_3, FORWARD_R_3);
}

なんと素直。センサ系ブロックはすべて if(get_sensor() == pattern)に変換され、駆動系はすべてspeed(左動作, 右動作)に変換されている。elseなんて入れてないし continueも入ってない! あれれ、ということはこのプログラムバグってんな、と今気がついた。だめじゃん。常に一番下のFORWARD_*_3が実行されてしまうよ。ついつい普段のプログラミングの癖でdefault: を作ってしまったけど、全条件網羅しないとダメみたい。気をつけよう。
ともかくまあ問題もあるんだけど、既存のものをフル活用して楽してうまいこと作ってると思う。ちょっとやる気のある子供ならハックしてくれまくりそうなこのユルユル感が良い。