sub t_left (){OnFwd(OUT_C);OnRev(OUT_A);} //左回転 sub t_right(){OnFwd(OUT_A);OnRev(OUT_C);} //右回転 sub left(){OnFwd(OUT_C);} //左前進回転 sub right(){OnFwd(OUT_A);} //右前進回転 sub go(){OnFwd(OUT_A+OUT_C);} //前進 sub back(){OnRev(OUT_A+OUT_C);} //後退 sub off(){Off(OUT_A+OUT_C); Wait(50);} //停止+待機 sub off2(){Off(OUT_A+OUT_C);} //停止 void go_off(){go();Wait(50);off();} //前進+停止 void jig(){left();Wait(30);off2();right();Wait(30);off2();} //ジグザグ前進
まずサブルーチンと関数を使って必要な動作を定義しておきます。 go_off();とjig();だけ関数なのは、これ自体にサブルーチンを含ませたいからです。つまり、サブルーチンの中にサブルーチンは使えません。(関数で使えるのは、コンパイル時に一度展開するからか?) こうする事によって複雑な動きを定義することができて便利です。(単にWait();を付けて繰り返すことができたりします。) jig();の中にいちいちoff2();があるのは、例えばleft();だとこれがWait(30);を過ぎても残ってしまい次のright();で直進になってしまうためです。
int level; //変数。何段階かを代入する int n; //ジグザグの回数を記録
ここでは2つの変数を使いました。それぞれ用途が違います。
level@変数 これは現在何段階の作業をしているかを0,1,2で表す変数です。最初に自分なりに子機がする作業を3つに分けました。ドラクエを意識したことは言うまでもありません。
実は、プログラムを繰り返して使いたいが為に考えた策です。(第0〜2段階を繰り返して何度もパックを持ってこれるように。)while{}で繰り返し、それぞれをまたwhile(true){}で繰り返します。プログラムの文章の特定の場所にジャンプできる方法があれば、こんな変数はあまり意味がありません。自分で考え出したので愛着はありますが。(それぞれの一定の動作を繰り返すことができるのはいいのかも。)
n@変数 ジグザグの回数を記録するための変数です。n = n + 1;を繰り返すことで、1ずつ増えていきます。(最初に0を代入しておきます。)「ジグザグの回数が多い=子機の行く先にパックがなかった」と判断し(ここでは20回)バックしてもう一度ジグザグでパックを探す。ということをif{}でプログラムしました。ちなみに黒いパックだとn = 5;で代入して残りの15回ジグザグをがんばってもらう。というようにしましたがあんまり意味がないかもしれません。
if(SENSOR_1>=49 && SENSOR_3>=49) //空の状態 49に変更。本番の状況で逐一変更 {jig(); n=n+1;} if(SENSOR_1>40 && SENSOR_1<49) //白い箱、緑の箱 {PlaySound(SOUND_UP);ClearMessage();level = 2;} if(SENSOR_3>40 && SENSOR_3<49) //白い箱、緑の箱 {PlaySound(SOUND_UP);ClearMessage();level = 2;} if(SENSOR_1<=35 || SENSOR_3<=35) //黒い箱 {back();Wait(100);off2() t_left();Wait(50);off2();go();Wait(50);off2(); t_right();Wait(50);off2();go();Wait(50);off2();n=5;} //黒い箱を抜いて再び探しに行く
アームの内側に付いているセンサーで「空の状態」「白、緑のパック」「黒のパック」を判別できるようにしました。初めはアームの先にセンサーを付けていたのですが、センサーとパックの距離でセンサーの値が変わってしまうので、結局アームの内側に付けました。これだとパックとの距離がほぼ一定なのでプログラムしやすいです。あと、互いにセンサーが向き合うので、互いの光によって、空の状態の時の光が高い値で安定します。これが無いと空の状態と緑のパックの値がかぶる為、判別が困難です。それぞれの場合の動作は以下の通り。
光は曖昧で苦労しました。タッチを使おうとも思ったのですが、パックがアーム内に入るだけでは、感知しなかったので諦めました。あと白と緑を判別したかったのですが、そこまでレベルの高い試合にはならないだろうと思い、やめました。
go(); until(Message() == 64); //64を受け取ればバックに移る PlaySound(SOUND_UP); off();back();Wait(450); off(); //元の位置(左回転終えて直進前)へback t_left();Wait(100); off(); //90°左回転 PlaySound(SOUND_FAST_UP); level = 0;
実際のロボコンでは通信するところまで行けなかったのですが、一応通信して親機のMessage(64);を受け取るとパックを置いてバックします。(バックしたら置いてくるのですが。)うまいこと受け取るとちょうど親機のアームの位置にパックを置きます。練習の時点で何回も試せなかったのが痛かった。ちなみに、RCXが電波を出し始める瞬間はすごく広く飛ぶので、気をつけた方がいいです。あと、妨害電波対策は全くしなかったが会場では出ていたのだろうか?