#define forwards(t) OnFwd(OUT_A+OUT_C);Wait(t); #define backwards(t) OnRev(OUT_A+OUT_C);Wait(t); #define turn_right(t) OnFwd(OUT_A);OnRev(OUT_C);Wait(t); #define turn_left(t) OnRev(OUT_A);OnFwd(OUT_C);Wait(t); task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_2,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_TOUCH); start wall; forwards(200); //台から降りる動作 PlayTone(523,50); start search; }
task search() { while(true) { if(SENSOR_1 > 37) //緑又は白のパックが見つかるまで { repeat(3) { forwards(200); turn_left(50); turn_right(100); turn_left(50); } turn_left(100); //パックを探しながら往復 } if(SENSOR_1 < 37) //パックを見つけた場合 { forwards(400); //パックに向かって前進 start check_sensors; } if(SENSOR_1 < 29) { PlaySound(4);Wait(50); backwards(200); turn_left(60); } } }
task check_sensors() { Off(OUT_A+OUT_C); while(true) { if(SENSOR_1 < 30) //黒の場合 { PlaySound(4);Wait(50); backwards(200); turn_left(80); stop check_sensors; //パックを放して45度旋回 } else //緑の場合 { PlayTone(587,50); turn_left(60); forwards(100); OnFwd(OUT_A+OUT_C);until(SENSOR_2 < 35); PlayTone(659,50); start comeback; } } }
task comeback() { ClearTimer(0); do { stop search; ClearMessage(); SendMessage(188); until(Message() != 0); if(Message() == 189) {PlaySound(1);Wait(100);SendMessage(190);Wait(100);} if(Message() == 191) {PlaySound(5);Wait(100);forwards(500);backwards(200);turn_left(120);} Off(OUT_A+OUT_C); } until (Timer(0) < 150); turn_left(40); start search; }
task wall() { while(true) { if(SENSOR_3 == 1) { stop search;stop check_sensors;stop comeback; PlaySound(4);Wait(50); backwards(250); OnRev(OUT_A);Off(OUT_C);Wait(120); start search; } } }
このプログラムは基本的には左右に首(ってゆーか全身)を振って牛乳パックを探しながら往復し、白か黄緑のパックを見つけると回収(黒は回避する)、3号のもとへ運ぶというものです。この際、3号との通信を利用してもとの場所へ帰ってくるようにする・・・つもりだったのですが、当日の終盤になってプログラムに不備があったことが発覚。まあどちらにせよ、本番ではうまく動いてくれなかったので、意味は無かったのですが。
このロボットは牛乳パックを1つずつ運ぶことが目的なので、パックをしっかりホールドできるように長いアームを装備しています。2つのアームの付け根をゴムで留めてあり、パックを持ったまま旋回してもパックを放さないようにしました。(放すときは、パックに対して真っ直ぐ後退します。)
アームの下にあるタイヤは一見前輪のように見えますが、これは台から降りるための補助輪であり、通常は床から浮くようになっています。
真の前輪はこちら↑。最初の写真のものにはついていないのですが、後輪と補助輪の中間あたりについています。最初は普通にタイヤを使っていたのですが、旋回するときに強い抵抗がかかるため、キャスター風のパーツに変更しました。走っている途中で外れないように、強度の確保にかなり気を使いました。
こちらは最終バージョン。上のものは左右1つずつキャスターがついていたのに対して、これは機体中央に1つだけ装備しています。これにより旋回性能をさらに高めることを狙いました。
その上についている光センサーは、パックの存在の感知と色の判断を行うためのものです。
左補助輪の付け根に取り付けたタッチセンサー。壁にぶつかると反応し、気体が180度旋回するようにしました(プログラムのtask wallの部分)。これで壁も大丈夫・・・のハズだった・・・のです・・・が
えーと・・・これは予選2回戦だったかな?ステージの袋小路に入り込んでしまい、旋回しようとしてもアームが引っかかって抜け出せない罠。
この反省を活かし、旋回する前に少し後退するようにプログラムを書き直しました。
このロボは、モーターの動力をギアで後輪に伝達して移動を行っているのですが、このギアが案外うまく噛み合ってくれず、この部分の製作だけでもかなりの労力を使いました。
それに全体の剛性をいかに獲得するかも大きな壁となりました。ただ牛乳パックを運ぶだけの競技ならこの点は問題にはならないのですが、ルール上「高さ11cmの台の上からスタート」しなくてはならず、ましてやロボの部品は基本的にレゴブロックなので、普通に組んでもスタート時にバラバラになるのがオチです。そのためロボの構造はかなり複雑化し、改善点が見つかってパーツを交換するときなど、分解が大変でした。
まず、チーム全体のコンセプトを考えたのは僕なのですが、ロボ3台すべてをスタート地点の台に載せようとするとかなり無理があることに、本番になってから気づきました。(実際、スタートに失敗して3号機を倒してしまうことも何度かありました。)事前によく確認しておけば、それぞれをコンパクトに作ることも出来た筈です。
僕の製作した2号については、なんか結局役に立たなかったような(汗)。具体的には、1つずつ運ぶことを考えて作ったため、「牛乳パックの山」を相手にしたときにうまく機能してくれないのが最大の問題点でした。もっとまとめて運べるようにするべきだったろうなあ・・・。
移動に関しても、前進と旋回を繰り返す単純なものだったのですが、本番ではうまく動いてくれなかったので、光センサーを使ってライントレースで動きを制御するようにすれば、正確にパックを運べたのではないかと思います。(2号機には既に床に向けた光センサーがあったのですが、ライントレースといえるほど完璧なプログラムを積んでいなかったので。)
2月12日夜。約半日に亘る激戦を終えて仲間と分かれた俺は、自らも帰途に着こうとしていた。しかし今思えば、俺にとってはここからが真の戦いだったのである。
俺は諏訪の実家から大学に通っていて、通学には電車・バス等を乗り継いで片道約1時間半かけている。しかも夜になれば松本駅から諏訪へ向かう電車の本数は極端に減ってしまう。そのために出来るだけ早く下校する必要があったのだが、以前新入生ゼミのコンパで9時以降まで松本にいたことのある俺は、10時までに大学を出れば大丈夫だろうとタカをくくっていた。
西門のバス停に行くと、次のバスは数分後とあった。そのとき夕食をとっていなかった俺は、バスの到着までに何か買っておこうと思い、すぐそばのロー●ンに入った。しかし深夜ゆえ手ごろな物が無かったので、すぐ店を出、再びバス停の前に立った。その時である。俺は驚くべき事実を知ってしまったのだ。
「土日・・・最終は9時46分!?」(時刻はうろ覚えなので、本当は微妙に違うかもしれない。)俺はその日が土曜日だということ、平日と土日ではダイヤが異なることをすっかり忘れていた。なんと最終のバスは、俺が大学を出る数分前に出てしまっていたのだ。大学から松本駅まではバスで20分弱。そして次の電車は20数分後。俺はこのとき、自宅から通っている自分の境遇を恨むと共に、戦いの始まりを実感した。
俺は歩いた、冬の寒空の下を。大学の近くには予備校時代の友人宅があり、泊めてもらおうかとも思った。しかし友人本人は現在埼玉で一人暮らしをしており、加えて俺が友人の実家へ行ったのは2回。家族の方と会ったことがあるのは1回だけである。いきなり行って泊めてくれというのはあまりに忍びなかった。
幸い、駅までは徒歩40分程度と歩いて行けない距離ではなかったので、どうにか歩き通し、何とか最終の電車で帰ることが出来た。その代償として、翌日は(スキー実習の前日にもかかわらず)風邪をひいてしまったのだが。
風邪はスキー実習初日のうちに完治したので、問題はありませんでした。