上のようなマップ上でピッチャーロボットとバッターロボットで通信しながら野球盤ゲームをする 詳細なルールについては課題3を参照
作成は自分が担当した。
課題2の反省(光センサーが床面と近すぎると進むのが遅く負荷がかかる)を生かして、少しだけ高い位置に光センサーをつけた。
補強した部分が多くパーツが大きいが、NXTの箱にはしまいやすい
立幅は20cmぎりぎり、横幅は15cmない程度。基本ルール「スタート時はそれぞれA地点B地点の枠内に収まること(高さの制限はなし)」、「M地点、B地点では接地している部分が枠内に入っていること」をクリア。ボールをしっかりつかむ形のアームが大きく横についているので、本体やモーター、タイヤの部分はコンパクトになった。
アームの構造。モーターAで上半分を開閉させる。上半分はモーターに完全に固定され、連動して動く。下半分はぶら下がっているので閉じている時、半分開けている時は背面が床面に垂直を維持する。大きく開けたときは背面も持ち上がるので、下部の黒い棒に当ててボールを射出することができる。
このアームの形はバッターらしくはないが、理論上はボールを掴んでかなり正確にコントロールを効かせて射出できる。だが実際のロボコンでは、ピッチャーが投げてからとバッターが射出してから、床面のわずかな凹凸の影響を受けて直線的にボールが転がらず、掴めず入らず得点につながらなかった。なのでほかの多くの班の様に左右のフリッパーでとりあえずボールに当てて打つ構造のほうが、得点を多く得られたかもしれない。
詳しくはこちらのページを参照。
ななめのレールに球を一つ一つ落として、球の自重で転がる仕組みである。マウンドに入る位置はかなり正確だったが、この仕組み故球の威力が弱かったり、球が2つ同時に出たり詰まったりする問題があった。
ロボットがCからスタートしてBで向きを変える所までのプログラムを作った。 下のGIFにおおよその動きとその説明をまとめた。
#define go_straight(t) RotateMotor(OUT_BC,50,t); #define go_nonstop OnFwd(OUT_BC,50); #define SASETSU OnRev(OUT_BC,50); Wait(400); Off(OUT_BC); OnFwd(OUT_C,50); Wait(1500); Off(OUT_C);
決まった距離だけ直進するときはgo_straight(t)、光センサーでラインを認識するまで直進するときはgo_nonstopを使い分けるようにした。 また、SASETSUは課題2で使用したものを流用した。
sub BEGIN() { Wait(1500); turn(120); go_straight(1300); PlaySound(SOUND_CLICK); go_nonstop; until(SENSOR_3<=40); Off(OUT_BC); PlaySound(SOUND_CLICK); Wait(1000); SASETSU; }
#define turn_right OnFwd(OUT_B,40); #define turn_right_slow OnFwd(OUT_B,40); OnRev(OUT_C,30); #define turn_left OnFwd(OUT_C,40); #define turn_left_slow OnFwd(OUT_C,40); OnRev(OUT_B,30); #define go_line OnFwd(OUT_BC,40); #define FOLLOW_TIME 5000
sub FOLLOW_LINE() { long t0=CurrentTick(); while(CurrentTick()-t0<FOLLOW_TIME){ if(SENSOR_3<=38){ turn_right; }else if(SENSOR_3<=45){ turn_right_slow; }else if(SENSOR_3<=50){ go_line; }else if(SENSOR_3<=59){ turn_left_slow; }else{ turn_left; } } Off(OUT_BC); }
課題2で書いたライントレースを少し変えて、五秒の間だけ実行し、交差点認識はしないプログラムを作った。角度制御だけではズレが重なって大幅に方向が変わるので、一度ここで「必ず一定の方向(R-Bの線に平行)を向く」動作が必要だった。
また、時間以外の制御方法がわからなかったので何回か試走させて五秒に決めた。
初めはBの枠で交差点認識した時に停止させてから向きを調整する考えでいたが、
・交差点認識の誤差が大きい
・交差点認識した後の機体がマップの外に向き、そこから軌道修正が安定しない
等の理由で、交差点認識ではなく、R-Bの線に平行な向きのまま、前後移動のみでBの枠を内側から判断して、そこからの距離で機体の位置を決めるプログラムを作った(詳しくは上のGIFを参照)。
sub READY() { go_straight(500); OnRev(OUT_BC,50); until(SENSOR_3<=40); Off(OUT_BC); PlaySound(SOUND_CLICK); Wait(1000); turn(20); go_straight(400); turn(-70); PlaySound(SOUND_UP); }
ピッチャーに向き合うとき、超音波センサーを当初利用しようとしたが、プログラムでうまく使いこなせなかった。超音波センサーの周りに競走馬のブリンカーのようなものをつけたが、認識の感度は変わらなかった。
task main() { SetSensorLight(S3); BEGIN(); FOLLOW_LINE(); READY(); }
本課題ではピッチャーロボットがマスターである。より詳しい説明はこちらのページを参照
#define TURNR(A) RotateMotorEx(OUT_BC,40,A,100,true,true);Wait(1000); #define TURNL(L) RotateMotorEx(OUT_BC,40,L,-100,true,true);Wait(1000); #define TYOKUSIN OnFwdSync(OUT_BC,40,0); #define CM(K) RotateMotorEx(OUT_BC,40,20.47315*K,0,true,true);Wait(1000); #define HASSYA RotateMotor(OUT_A,-90,90);Wait(1000);RotateMotor(OUT_A,-90,-90);
ロボットがマウンドに入るまでのサブルーチン。
sub BASYO() { SetSensorLight(S1); TYOKUSIN; until(SENSOR_1<35); Off(OUT_BC); Wait(500); CM(5); Wait(500); }
task main() { int SIREI; TURNR(110); CM(36); TURNR(150); repeat(3){ BASYO(); } CM(-13); TURNR(130); until(BluetoothStatus(1)==NO_ERR); RemotePlayTone(1,440,1000); Wait(1000); RemoteStartProgram(1,"DAGEKI.rxe"); //バッターロボットにDAGEKIを実行させる命令 while(SIREI<12){ //SIREIが12未満の間繰り返し ReceiveRemoteNumber(MAILBOX1,true,SIREI); if(SIREI==11){ //SIREIが11のとき球を発射 PlaySound(SOUND_CLICK); Wait(200); HASSYA; SIREI=0; } } }
バッターロボットがスレイブである。より詳しい説明はこちらのページを参照
#define CATCH Wait(500);RotateMotor(OUT_A,70,45);Wait(1000); //球が来る時間に合わせてキャッチする #define UTU RotateMotor(OUT_A,-90,45);Wait(1000); //アームを大きく上げて球を打つ #define TURN(s,t) RotateMotorEx(OUT_BC,40,s,t,true,true);Wait(1000); //その場で機体が回転してゴールに向きを定める int x=1;
sub BATTING() { SendRemoteNumber(0,MAILBOX1,11); Wait(1500); CATCH; if(x==1){ //球によってゴールを変える TURN(80,100); //右側4点のゴール UTU; TURN(80,-100); x = x+1; } else if(x==2){ TURN(95,-100); //左側4点のゴール UTU; TURN(95,100); x = x+1; } else if(x==3){ TURN(40,100); //右側6点のゴール UTU; TURN(40,-100); x = x+1; } else if(x==4){ TURN(45,-100); //左側6点のゴール UTU; TURN(45,100); x = x+1; } else { TURN(45,-100); //左側6点のゴール UTU; TURN(45,100); x = x+1; } }
10点のゴールは遠く、ボールがピッチャーロボットにぶつかりやすいので断念した。またはピッチャーロボットの下部のレールに入り込み、次弾の障害になるケースもあった。
ピッチャーロボットからDAGEKIの命令が送られるたびに実行し、5回が終わったら12の値を送り返して終了する。
task main() { UTU; while(x<6){ BATTING(); } SendRemoteNumber(0,MAILBOX1,12); }
総合3位だった。点数が入ったのは二巡目の6点のみ。
気軽な興味で参加し、マインドストームもプログラミングも触れるのは初めてでしたが、すばらしい経験になったと思います。根気よくコンパイルエラーを見直したり、何度もレゴを組みなおしたりするのも楽しかったです。いえ、苦しかったです。実際のロボット作りならば、部品の制約がないのだからもっと難しいのでしょう。ゼミ生同士で課題解決に向けて相談・議論する過程という、ゼミならではの大きなメリットも得られました。今回もまた、一方的に教えてもらうことが多々ありました。協力者の方々には感謝しています。