競技時間は審判が続行不能と判断するまで、あるいはリタイアするまで。
図のA地点または(および)A'地点からスタートする。ただし接地している部分はそれぞれの領域内に
収まるものとする(線上はOK)。上空部分は領域からはみ出していてもよい。 Aタイプの空き缶を円Y内に、Bタイプの空き缶を円X内に運ぶ。
開始の合図から5秒以内にスタートボタンを押す作業を完了すること。
競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。
途中でうまく動かなくなった場合、1回限り再スタートすることができる(再スタートの際に別プロ
グラムで起動してよい)。
運んだ空き缶の数×3点
空き缶を積み重ねて置くことができば場合、2段目の空き缶一つにつき2点加算、3段目の空き缶一つにつき3点加算する。
円内からはみ出している場合、半分以下なら1点減点、半分以上なら2点減点。 間違った円内に空き缶を置いた場合は、1個につき1点減点。
以下の動作の精度・スピード・確実性などを含めた技術的な工夫や芸術性について他の全てのチーム(5チーム)が20点満点で採点し、その平均点を求める。
得点の目安:
空き缶を探し取りにいくまでの動作 (3点)
空き缶を掴む動作 (3点)
空き缶を運ぶ動作 (2点)
空き缶を置く動作 (2点)
空き缶を積む動作 (3点)
2台のRCXまたはNXT、EV3の連携の良さ(2点)
自立型のロボットとしての形や動作の美しさ、斬新さ(2点)
その他 (3点)
2体のロボットで協力して空き缶を運んでいく,という方針でロボットを作った.
1体目(大きい方)を"おやき",2体目(小さい方)を"こき"と名付けた.
おやき
こき
"こき"も"おやき"も,モーターA,モーターCでタイヤを動かし,モーターBでアームを動かす.
"おやき"は3段目の空き缶を掴むように,"こき"は2段目の空き缶を掴むように出来ている.
この合体した状態で,"こき"が空き缶を掴んだまま後ろに下がることで真ん中の空き缶だけを抜き取ることができる.
ここで,両方がアームを放すことで空き缶を地面に落とし,運べる状態にして運んでいく.
空き缶を所定の位置まで運ぶには,2体のコンビネーションが大事になってくる.
まずスタートは2体同時に("おやき"の方が少しだけ先に)スタートする.
黄色ライン:こき,緑色ライン:おやき
Yで"おやき","こき"が合体し,空き缶を分ける.その後,"こき"は空き缶をその場に置き,"おやき"は2個積まれた空き缶を下図の緑丸まで持っていく.途中,"こき"が通過するまで待つために,緑の□で待機する.
その後,"おやき"はFからXへ,"こき"はEからXへ行く.Xで合体し,空き缶を分ける.
"こき"は空き缶をA'へ運び,"おやき"は積んだ空き缶をXに置き,A'に向かう.
"こき"がA'に置いて行った空き缶を"おやき"が回収し,Xへ.その間,"こき"は"おやき"が置いて行った2個積まれた空き缶をEからYまで直進することで回収する.
Yに空き缶を置いたら,"こき"はCへ上がり,おやきが置いて行った緑丸にある空き缶を回収し,そのままライントレースし,Xに置く.
これですべての空き缶が分けられたことになる.
空き缶は作るのに結構苦労した.
積まれた空き缶を,真ん中をスライドさせることによって色分けしなければいけなかったためスライドできるような構造にしなければならなかった.
最初に紙を張ることでスライドできるようにしたが,摩擦係数が大きすぎてスライドさせると空き缶すべてくっついて行ってしまった.
そこで,買い物した時にくれるビニール袋を切って張ることにした.すると,摩擦係数が抑えられ,上手く滑ってくれて空き缶を分けることに成功した.
他にも,空き缶を落とした時に空き缶が倒れてしまってはいけないのであまり倒れないようにする必要があった.
最初はセブンアップの空き缶を使っていたが,ふるふるゼリーの空き缶に変えた.
後者の空き缶は前者のものより太さは同じだが高さが低くなっている.
そのため,倒れにくくなった.
後は,ロボットの改善などでできるだけ空き缶を落とした時に倒れないように努めた.
#define turn_left Off(OUT_AC);OnFwd(OUT_A);OnRev(OUT_C);Wait(2);Off(OUT_AC); #define turn_right Off(OUT_AC);OnFwd(OUT_C);OnRev(OUT_A);Wait(2);Off(OUT_AC); #define run_left Off(OUT_AC);OnFwd(OUT_A);Wait(2);Off(OUT_AC); #define run_right Off(OUT_AC);OnFwd(OUT_C);Wait(2);Off(OUT_AC); #define arm_open Off(OUT_B);OnRev(OUT_B);Wait(20);Off(OUT_B); #define arm_close Off(OUT_B);OnFwd(OUT_B); #define turn_left_free OnFwd(OUT_A);OnRev(OUT_C); #define turn_right_free OnFwd(OUT_C);OnRev(OUT_A); #define turn_left_small OnFwd(OUT_A); #define turn_right_small OnFwd(OUT_C);
turn_left,turn_left_freeは両方のタイヤを回転させて左へ曲がる.turn_leftはライントレースするサブルーチンの中でのみ機能し,turn_left_freeはどこでも使えるプログラムとなっている.
turn_left_small,run_leftはタイヤ1つだけ回転し回転の内側のタイヤは止まっている.そうすることで大きく旋回することができる.turn_left_smallはどこでも使えるプログラムであるが,run_leftはサブルーチンの中のみで機能するプログラムとなっている.
右に曲がる,turn_right,turn_right_free,turn_right_small,run_rightも上記と同様.
arm_openで空き缶を掴むためのアームを開き,arm_closeでアームを閉じ,空き缶を掴む.
sub follow_line_right(){ClearTimer(0); while(FastTimer(0)<18) if(SENSOR_2<38){ turn_right; // センサー2が黒を認識したら,右へ曲がる }else if(SENSOR_2<42){ run_right;ClearTimer(0); // センサー2がグレーっぽい黒を認識したら,大きく右へ曲がる }else if(SENSOR_2<47){ OnFwd(OUT_AC);ClearTimer(0); // センサー2がグレーを認識したら,まっすぐ進む }else if(SENSOR_2<50){ run_left;ClearTimer(0); // センサー2がグレーっぽい白を認識したら,大きく左へ曲がる }else if(SENSOR_2<55){ turn_left;ClearTimer(0); // センサー2が白を認識したら,左へ曲がる }}
上のサブルーチンは黒線の右側をライントレースするプログラムとなっている.センサー2が0.18秒以上黒を認識したら,上のサブルーチンから外れ,次のプログラムへと行く.
sub follow_line_left(){ClearTimer(0); while(FastTimer(0)<18) if(SENSOR_2<38){ turn_left; // センサー2が黒を認識したら,左へ曲がる }else if(SENSOR_2<42){ run_left;ClearTimer(0); // センサー2がグレーっぽい黒を認識したら,大きく左へ曲がる }else if(SENSOR_2<47){ OnFwd(OUT_AC);ClearTimer(0); // センサー2がグレーを認識したら,まっすぐ進む }else if(SENSOR_2<50){ run_right;ClearTimer(0); // センサー2がグレーっぽい白を認識したら,大きく右へ曲がる }else if(SENSOR_2<55){ turn_right;ClearTimer(0); // センサー2が白を認識したら,右へ曲がる }}
上のプログラムは黒線の左側をライントレースするプログラムとなっている.センサー2が0.18秒以上黒を認識したら,上のサブルーチンから外れ,次のプログラムへと行く.
task main() { OnFwd(OUT_AC); Wait(200); Off(OUT_AC); // A'からHに向かって進む(黒線まで)
SetSensor(SENSOR_2,SENSOR_LIGHT);
follow_line_left(); // Hまで黒線左側をライントレース
turn_right_small; Wait(90); turn_right_free; Wait(15); Off(OUT_AC); // HからIに方向転換 follow_line_left(); // HからIに進む 黒線左側をライントレース Off(OUT_AC); Wait(300); // "こき"の動きとの時間合わせ 少しIで待つ
turn_right_free; Wait(10); Off(OUT_AC); // Yに体が向くように少し方向転換 OnFwd(OUT_AC); Wait(40); // IからYまで直進 Off(OUT_AC);
arm_close; // 缶を掴む Wait(1000); // 相手が2段目の空き缶を抜くまで待機 arm_open; // 3段目の空き缶をアームを放すことで1段目の空き缶の上に乗せる
OnFwd(OUT_AC); Wait(25); Off(OUT_AC); // 缶をがっちり抱える turn_right_small; Wait(110); Off(OUT_AC); // Yで右に90°方向転換
OnFwd(OUT_AC); Wait(30); // 黒線左側をライントレースできるように円から抜ける Off(OUT_AC); follow_line_left(); // 黒線左側をライントレースし,Gまで進む
turn_left_small; Wait(30); turn_left_free; Wait(35); // Gで左へ曲がる Off(OUT_AC); Wait(1500); // "こき"が通り過ぎるまで待つ OnFwd(OUT_AC); Wait(120); Off(OUT_AC); // 缶をおいていく
OnRev(OUT_AC); Wait(120); // Gに戻る turn_right_free; Wait(70); Off(OUT_AC); // 右に回転して軌道に戻る
follow_line_left(); // ライントレース
Off(OUT_AC); Wait(300); // "こき"の動きとの時間合わせ
turn_right_free; Wait(10); Off(OUT_AC); // 少し右に曲がることでXに体を向ける.
OnFwd(OUT_AC); Wait(20); // 空き缶まで行く Off(OUT_AC); Wait(100); // "こき"との時間合わせ
arm_close; // 缶を掴む Wait(500); // 相手が2段目の空き缶を抜くまで待機 arm_open; // 3段目の空き缶をアームを放すことで1段目の上に乗せる
OnRev(OUT_AC); Wait(120); Off(OUT_AC); Wait(100); // XからG辺りまで後退
turn_right_free; Wait(75); Off(OUT_AC); Wait(200); // 右へ曲がる
OnFwd(OUT_AC); Wait(200); Off(OUT_AC); Wait(200); // 直進
turn_left_free; Wait(75); Off(OUT_AC); Wait(200); // 左へ曲がる
OnFwd(OUT_AC); Wait(260); Off(OUT_AC); Wait(200); // A'で空き缶を抱える
turn_left_free; Wait(85); Off(OUT_AC); Wait(200); // A'で左へ曲がる
OnFwd(OUT_AC); Wait(100); Off(OUT_AC); // 空き缶をXに置く
OnRev(OUT_AC); Wait(100); Off(OUT_AC); // Xで少し後退
Off(OUT_AC); //終了
}
#define THRESHOLD 48 //基準(中間値)となる光の値(定数) #define CROSSTIMER 6 //黒線を6回検知で止まるという値 #define GO OnFwd(OUT_AC); //まっすぐ進む #define BACK OnRev(OUT_AC); //後ろ #define turn_left OnFwd(OUT_A);Off(OUT_C); //左回り #define turn_right Off(OUT_A);OnFwd(OUT_C); //右回り #define turn_hleft OnFwd(OUT_A);OnRev(OUT_C); //右旋回 #define turn_hright OnRev(OUT_A);OnFwd(OUT_C); //左旋回 #define STEP 1 //0.01秒(if内で使用) #define tunoTIME 200 //アームを動かす時間
黒<THRESHOLD-7(41)<黒灰<THRESHOLD-3(45)<灰<THRESHOLD+3(51)<白灰<THRESHOLD+7(55)<白
sub traceLstop() //L(左)をトレースして黒灰を6回検知して止まる(白の時旋回をする) //左右回転,直進,右旋回の4方向 { int n=0; while(n<CROSSTIMER){ if(SENSOR_2<THRESHOLD-3){ turn_left;n++; }else{ if(SENSOR_2<THRESHOLD+3){ GO; }else if(SENSOR_2<THRESHOLD+7){ turn_right; }else{ turn_hright; }n=0; } Wait(STEP); } PlaySound(SOUND_DOWN); }
sub traceRstop() // R(右)をトレースして黒灰を6回検知して止まる(白の時旋回をする) // 左右回転,直進,左旋回の4方向 { int n=0; while(n<CROSSTIMER){ if(SENSOR_2<THRESHOLD-3){ turn_right;n++; }else{ if(SENSOR_2<THRESHOLD+3){ GO; }else if(SENSOR_2<THRESHOLD+7){ turn_left; }else{ turn_hleft; }n=0; } Wait(STEP); } PlaySound(SOUND_DOWN); }
sub traceSLstop() // L(左)をトレースして黒灰を6回検知して止まる(ただし白の時旋回をしない) // 左右回転,直進の3方向 { int n=0; while(n<6){ if(SENSOR_2<THRESHOLD-3){ turn_left;n++; }else{ if(SENSOR_2<THRESHOLD+3){ GO; }else{ turn_right; }n=0; } Wait(STEP); } PlaySound(SOUND_DOWN); }
STEPはif内の動作を1回あたり0.01秒行うための時間
黒の時旋回を入れないのは、交差点判断を正確にするため。
各if終了後に音楽を入れることで交差点の判断の有無を確認しやすくする
#define STOPGOr while(SENSOR_2<THRESHOLD+7){GO;} traceRstop(); //黒線を飛び越え黒線の右をたどる #define STOPGOl while(SENSOR_2<THRESHOLD+7){GO;} traceLstop(); //黒線を飛び越え黒線の左をたどる
task main()
{
SetPower(OUT_B,3); //モータBの力を3にする SetSensor(SENSOR_2,SENSOR_LIGHT); //センサーを2に設定
GO;Wait(80); //地点Aの抜け出し
traceLstop(); Off(OUT_AC);Wait(350); //C交差点止まる
GO;Wait(20); turn_hright;Wait(110); traceRstop(); Off(OUT_AC);Wait(10); //K交差点止まる
turn_hleft;Wait(15); //つかむため軌道修正 Off(OUT_AC);Wait(200);
GO;Wait(90);Off(OUT_AC); //X缶の位置まで進む
OnFwd(OUT_B);Wait(tunoTIME);Off(OUT_AC);Wait(100); //缶をつかむ
BACK;Wait(180); Off(OUT_AC);Wait(600); //後ろに下がる
OnRev(OUT_B);Wait(tunoTIME);Off(OUT_B); //缶をはなす
GO;Wait(180);Off(OUT_AC); //缶をはなす位置まで移動
while(SENSOR_2>THRESHOLD-7){BACK;}; //K地点の黒線まで下がる
turn_hleft;Wait(50);while(SENSOR_2>THRESHOLD-7){turn_hleft;}; //CKの右側をトレースできるように旋回
traceRstop(); //CKの右トレース
GO;Wait(30); turn_hright;Wait(100);
traceRstop(); //Cの右直線のトレース
turn_right;Wait(185); Off(OUT_AC);Wait(10);
while(SENSOR_2>THRESHOLD-7){GO;}; //Eの右直線の末端まで進む
GO;Wait(40); while(SENSOR_2>THRESHOLD-7){turn_hright;}; Off(OUT_AC);Wait(400);
GO;Wait(80);Off(OUT_AC);Wait(150); //Yの缶の位置まで進む
OnFwd(OUT_B);Wait(tunoTIME);Off(OUT_AC);Wait(200); //缶をつかむ
BACK;Wait(90); //缶を抜く
turn_hleft;Wait(85);Off(OUT_AC);Wait(100); //左旋回
OnRev(OUT_B);Wait(tunoTIME);Off(OUT_B);Wait(30); //缶をはなす
GO;Wait(165);
BACK;Wait(165);Off(OUT_AC);Wait(50); //缶をはなして後ろへいく
turn_hright;Wait(90);Off(OUT_AC);Wait(100); //右旋回
GO;Wait(180); traceSLstop(); //FG間の左トレース
turn_right(20);
traceLstop(); //GL間を左トレース
turn_hright;Wait(20);Off(OUT_AC);Wait(50); //缶を置く位置を調整
GO;Wait(50);Off(OUT_AC);Wait(100); //缶を置く
while(SENSOR_2>THRESHOLD-5){BACK;};Off(OUT_AC);Wait(100); OnFwd(OUT_B);Wait(20); turn_hright;Wait(45);
GO;Wait(110);while(SENSOR_2>THRESHOLD-7){GO;}; //KC間まで進む
GO;Wait(25); turn_hright;Wait(50);
traceRstop(); //Cまで右トレース
OnRev(OUT_B);Wait(30);Off(OUT_ABC);Wait(100);
STOPGOl; //C、直角(Dの上)間を左トレース
Wait(20);
STOPGOr; //直角、D間の右トレース
turn_hleft;Wait(20); //缶を置く位置を調整
GO;Wait(30); //缶を置く
Off(OUT_ABC);Wait(100);
}
本番前のリハーサルでは,"おやき"はきちんと動いてくれていたが,本番になって,光が変わったせいなのか,交差点を認識してくれなくなってしまったことがとても残念だった.
皆さんに"おやき"と"こき"が合体するところを見てほしかったが,そこを見せられなかったことが悔しかった.
本番までに何回かロボットを動かしてみたが,1回も成功しなかったのが残念だった.
本番は"こき"だけしか動かなかったが,今までの中で結構いい点数が出たので良かった.
3位を取ることができてよかった.
ロボット2機で動かすにあたって,缶に工夫をしたり,ロボット達の進むコースを考えたり,戦略を考えたり,ロボットの構造を考えたりと試行錯誤を繰り返した.
最初の方は成功のイメージがなかなか持てなかったが,試行錯誤していくにつれて成功のイメージが見えてきて面白かった.
今まで動かした中で一番よく動いてくれたロボットたちの動画はこちら https://youtu.be/Pok_ylCWW7A