2016a/Member 目次
今回の課題でコップを運ぶために使った方法は、コップを持ち上げて運び重ねていく方法です。 ロボットのコップを掴む動作は、先生が授業で話していた一つのモータで掴んで持ち上げる仕組みを使いました。
基本的に一台でコップを運び、もう一台はQ地点で待機して壁にして、コップが倒れないようにしました。
左の写真がコップを運ぶロボットで、右の写真が壁になるロボットです。
コップを運ぶロボットでは、コップを認識するためにセンサが必要なので、そのために光センサを使いました。最初はタッチセンサを使おうとしましたが、コップが軽すぎてうまく反応しなかったので 光センサにしました。
下の写真のように組み合わせることで光センサを両方真ん中の位置に合わせた。
コップを運ぶロボットのアームと当たらないように、アームを紙コップの下の方を軽く抑えられるような位置にした。
アームを下したときに、下の写真の赤丸の部分でアームをこれ以上下がらないようにしているが、センサを取り付けている部分の固定が弱いため、下すときの衝撃でとれてしまうことがある。
固定の仕方を試行錯誤したが、良い方法が見つからず時間も足りないと考え、このまま進めることにした。
ライントレースのプログラムは、私の課題2のプログラムのマクロとサブルーチンをそのまま使いました。intersection()はサブルーチンの個数が8個を超えてしまうのでmain()に直接書きました。他の部分は変更が無いので説明は課題2で見てください。
二台のロボットの通信をするための数値をSIGNALONとして定義した。
紙コップにある程度近づいた時の光センサの値をWHITEとして定義した。
回収したコップを数える変数cup_countは後で説明するcup_down()でも使用したかったのでグローバル変数にした。
#define SIGNALON 121 //通信用 #define WHITE 50 //紙コップ認識用の値
int cup_count=0; //コップのカウント
紙コップの位置と番号を下の図のように決め、番号ごとに掴む動作cup1(),cup2(),cup3()と定義した。
光センサの値がWHITEより大きくなるまでゆっくり直進するようにした。
SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC);
sub cup1() //CとDのそれぞれの1番のコップ { turn_right2; //紙コップまで方向調整 Wait(25); SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC); OnRev(OUT_B); //紙コップをつかむ Wait(150); Off(OUT_B); turn_right2; //ラインまで移動 Wait(180); go_forward; Wait(20); }
sub cup2() //2番のコップ { SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC); OnRev(OUT_B); //紙コップをつかむ Wait(150); Off(OUT_B); turn_right2; //ラインまで移動 Wait(180); go_forward; Wait(120); }
sub cup3() //3番のコップ { turn_right2; //紙コップまで方向調整 Wait(45); SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC); OnRev(OUT_B); //紙コップをつかむ Wait(150); Off(OUT_B); turn_right2; //ラインまで移動 Wait(170); go_forward; Wait(100); }
細かい移動は旋回や前後進を使い、時間で指定した。
最初のコップを置くときは、壁になるロボットと通信して動作をさせるようにした。さらにコップを前に押すことで、次のコップを重ねるときにコップがうまく重なる位置に調整するようにした。
sub cup_down() //コップを下すときの動作 { turn_left2; //コップを下す位置まで移動 Wait(5); OnRev(OUT_AC); Wait(5); Off(OUT_AC); if(cup_count == 1) //最初のコップを置くとき { SendMessage(SIGNALON); //もう一台の動作を再開する } OnFwd(OUT_B); Wait(50); Off(OUT_B); if(cup_count == 1) //最初のコップを置いたとき { OnFwd(OUT_AC); //コップを少し前に押す Wait(10); } OnRev(OUT_AC); //ラインまで移動 Wait(60); turn_left2; Wait(120); go_forward; Wait(50); }
switch文を使い、交差点判別をするたびに変数cの値を増やしていき順番に動作するようにした。順番にすべて書いていくとcaseがとても多くなってしまうので、cの値をリセットしてcase2に戻ってくるようにし、変数course_checkを使うことでC地点に行くか、D地点に行くかを交互にできるようにし、変数cup_countを使うことでどのコップを回収する動作をするのか判断できるようにすることで無駄を省いた。
すべてのコップを回収し終わったら、変数dを1にすることでwhile文を抜け、動作を停止するようにした。
task main() { SetSensor(SENSOR_2, SENSOR_LIGHT); SetSensor(SENSOR_3, SENSOR_LIGHT); int c=1; //交差点の確認 int d=0; //1になったら動作停止 int course_check=0; //0ならC地点へ、1ならD地点へ SetPower(OUT_B,1); //コップをつかむときのモータをできるだけ弱くする go_forward; //ラインまで直進 Wait(80); while(d == 0) { ClearTimer(0); trace(); //ライントレース Off(OUT_AC); //交差点確認 PlaySound(SOUND_UP); Wait(100); switch(c) { case 1: //最初の交差点 i_left(); //S地点へ break; case 2: //S地点の交差点 if(course_check == 0) { i_right(); //C地点へ } else { i_left(); //D地点へ } break; case 3: //C地点かD地点 if(cup_count < 2) //集めたコップが2つより少ないなら { cup1(); } else if(cup_count < 4) //集めたコップが4つより少ないなら { cup2(); } else //集めたコップが4つ以上なら { cup3(); } cup_count++; break; case 4: if(course_check == 0) //C地点から戻ってきたら { i_left(); //P地点へ course_check = 1; //次はD地点へ } else //D地点から戻ってきたら { i_right(); //P地点へ course_check = 0; //次はC地点へ } break; case 5: //P地点の交差点 i_left(); //Q地点へ break; case 6: //Q地点の交差点 cup_down(); if(cup_count == 6) //コップを集め終わったら { d = 1; //動作停止 } break; case 7: //P地点の交差点 i_right(); //S地点へ c = 1; //case 2に戻る break; } c++; } Off(OUT_ABC); }
ライントレースも含めたすべてのプログラムは以下のようになる。
#define SIGNALON 121 //通信用 #define MIDDLE 50 //ライントレース用の中間値 #define WHITE 50 //紙コップ認識用の値 #define turn_left1 SetPower(OUT_AC,2); Off(OUT_A); OnFwd(OUT_C); //左 #define turn_left2 SetPower(OUT_A,1); OnRev(OUT_A); OnFwd(OUT_C); //左旋回 #define turn_right1 SetPower(OUT_AC,2); OnFwd(OUT_A); Off(OUT_C); //右 #define turn_right2 SetPower(OUT_C,1); OnFwd(OUT_A); OnRev(OUT_C); //右旋回 #define go_forward SetPower(OUT_AC,7); OnFwd(OUT_AC); //前進 int cup_count=0; //コップのカウント sub trace() //ライントレース { while(FastTimer(0) < 26) //左旋回が一定時間続くまでループ { if(SENSOR_2 < MIDDLE-5) //黒 { turn_left2; //左旋回 } else { if(SENSOR_2 < MIDDLE-2) //中間に近い黒 { turn_left1; //左曲がり } else if(SENSOR_2 < MIDDLE+3) //中間 { go_forward; //直進 } else if(SENSOR_2 < MIDDLE+6) //中間に近い白 { turn_right1; //右曲がり } else //白 { turn_right2; //右旋回 } ClearTimer(0); } } } sub i_forward() //直進 { turn_right2; Wait(30); go_forward; Wait(50); Off(OUT_AC); } sub i_left() //左折 { turn_left2; Wait(45); Off(OUT_AC); } sub i_right() //右折 { turn_right2; Wait(30); go_forward; Wait(30); turn_right2; Wait(80); Off(OUT_AC); } sub cup1() //CとDのそれぞれの1つ目のコップ { turn_right2; //紙コップまで方向調整 Wait(25); SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC); OnRev(OUT_B); //紙コップをつかむ Wait(150); Off(OUT_B); turn_right2; //ラインまで移動 Wait(180); go_forward; Wait(20); } sub cup2() //2つ目のコップ { SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC); OnRev(OUT_B); //紙コップをつかむ Wait(150); Off(OUT_B); turn_right2; //ラインまで移動 Wait(180); go_forward; Wait(120); } sub cup3() //3つ目のコップ { turn_right2; //紙コップまで方向調整 Wait(45); SetPower(OUT_AC,1); //紙コップまで移動 OnFwd(OUT_AC); while(SENSOR_3 <= WHITE); Off(OUT_AC); OnRev(OUT_B); //紙コップをつかむ Wait(150); Off(OUT_B); turn_right2; //ラインまで移動 Wait(170); go_forward; Wait(100); } sub cup_down() //コップを下すときの動作 { turn_left2; //コップを下す位置まで移動 Wait(5); OnRev(OUT_AC); Wait(5); Off(OUT_AC); if(cup_count == 1) //最初のコップを置くとき { SendMessage(SIGNALON); //もう一台の動作を再開する } OnFwd(OUT_B); Wait(50); Off(OUT_B); if(cup_count == 1) //最初のコップを置いたとき { OnFwd(OUT_AC); //コップを少し前に押す Wait(10); } OnRev(OUT_AC); //ラインまで移動 Wait(60); turn_left2; Wait(120); go_forward; Wait(50); } task main() { SetSensor(SENSOR_2, SENSOR_LIGHT); SetSensor(SENSOR_3, SENSOR_LIGHT); int c=1; //交差点の確認 int d=0; //1になったら動作停止 int course_check=0; //0ならC地点へ、1ならD地点へ SetPower(OUT_B,1); //コップをつかむときのモータをできるだけ弱くする go_forward; //ラインまで直進 Wait(80); while(d == 0) { ClearTimer(0); trace(); //ライントレース Off(OUT_AC); //交差点確認 PlaySound(SOUND_UP); Wait(100); switch(c) { case 1: //最初の交差点 i_left(); //S地点へ break; case 2: //S地点の交差点 if(course_check == 0) { i_right(); //C地点へ } else { i_left(); //D地点へ } break; case 3: //C地点かD地点 if(cup_count < 2) //集めたコップが2つより少ないなら { cup1(); } else if(cup_count < 4) //集めたコップが4つより少ないなら { cup2(); } else //集めたコップが4つ以上なら { cup3(); } cup_count++; break; case 4: if(course_check == 0) //C地点から戻ってきたら { i_left(); //P地点へ course_check = 1; //次はD地点へ } else //D地点から戻ってきたら { i_right(); //P地点へ course_check = 0; //次はC地点へ } break; case 5: //P地点の交差点 i_left(); //Q地点へ break; case 6: //Q地点の交差点 cup_down(); if(cup_count == 6) //コップを集め終わったら { d = 1; //動作停止 } break; case 7: //P地点の交差点 i_right(); //S地点へ c = 1; //case 2に戻る break; } c++; } Off(OUT_ABC); }
壁用のロボットは光センサがないので、すべて時間指定の動作になってしまった。
動作はコメント文の通りです。
#define SIGNALON 121 //通信用 task main() { ClearMessage(); ClearTimer(0); OnRev(OUT_AC); //Q地点まで移動 Wait(450); Off(OUT_AC); OnRev(OUT_A); //向き調整 OnFwd(OUT_C); Wait(5); Off(OUT_AC); while(Message() != SIGNALON); //通信するまで動作停止 Wait(150); //紙コップが置かれたらアームで調整 OnFwd(OUT_B); Wait(10); Off(OUT_B); Wait(30000); //紙コップが確実に集め終わるまで動作停止(あまりよくない) OnRev(OUT_B); //アームを広げる Wait(20); Off(OUT_B); OnRev(OUT_AC); //紙コップから離れる Wait(30); Off(OUT_AC); }
1回目は、壁ロボットが想定より進まず、紙コップを下したときに壁ロボットの上に当たってしまい1つも置くことができなかった。2回目は、紙コップを1つ置くことができたが、そのあとラインに戻れず続行不能となった。
結果は1つ置くことができたおかげで2位でした。
なかなかロボットを組み立てることができず、時間もあまりとれなかったため、私がほとんどプログラムを組むようになってしまった。もっとみんなでプログラムを考えていきたかった。
ロボコン前まではうまくいっていたが、電池の微妙な減りによって、本番では動作が変わってしまいラインに戻ることができず残念だった。
アームの力が強すぎたので、ギアを変えたりして弱くした方がよかったと思いました。
優勝したグループがひっくり返して重ねていくような方法をしていたのを見て、持ち上げて重ねるといった形に縛られ過ぎていたと思いました。