[[2015b/MemberOnly]] *課題3 ロボコン [#z6612d40] 課題:ボールを離れた場所から缶に当てるロボットとボールを回収するロボット 以下のルールに沿ってタイムレースを行う。 -競技時間はロボットAがSTART A地点のスタートラインを横切って、ロボットBがGOAL B地点のゴールラインに達するまで、あるいは審判が続行不能と判断するまで。 -ロボットAはSTART A地点から出発し、P地点におかれた赤いボールを拾って350mlのアルミ缶に当てる。その後、ロボットBがボールを回収する。引き続き青いボールについても同様の動作を繰り返す。ロボットBはボールを回収した後、最終的にGOAL Bまでボールを運ぶ。 -アルミ缶は中身が入っているものを使う。 -RISのチームはアルミ缶の上に灯台としてランタンを置く。 -ボールがアルミ缶に当たる前にロボットBがボールに触ってはいけない。 -ロボットAはセンターラインを超えては行けない。 -アルミ缶を5cm以上動かした場合は減点 #ref(2015b/Member/kaito012534/Mission3/2015b-mission3.png,50%) 私達はボールを放つロボットAを作成した **製作したロボット [#z77940c5] 課題2で使用したライントレースのロボットにいくつかパーツを追加した&br; #ref(2015b/Member/kaito012534/Mission3/ue.jpg,20%) #ref(2015b/Member/kaito012534/Mission3/left.jpg,20%) モーターA,Cで車輪を、モーターBでボールを掴み射出するためのアームを操作する&br; ボールを掴むとこのようになる&br; ボールを掴むとこのようになる #ref(2015b/Member/kaito012534/Mission3/left_ball.jpg,10%) ボールを打ち出すときはアームを逆回転させることでボールを蹴り出すような要領で行う。&br;&br; ライントレースのための光センサーとボールや缶を認識するための超音波センサーは前部に取り付けた #ref(2015b/Member/kaito012534/Mission3/front.jpg,20%) **全体の流れ [#kd429794] 起動するとまずP点のボールを探して掴みに行く。&br;次に缶の前まで移動、缶の方を向いてロボットBへ信号を発して返信があるまで待つ。&br;返信が来たところでボールを発射、Q点のボールを掴みに行く。&br;ボールを掴んで少し移動したところでプログラム終了。 **発生した問題点 [#u78b0cd7] -searchDirectionを複数回使用した際に2回目以降正常に動作しなくなっていた -主にRotateMotorを使用した直後、一瞬モーターがこちらの意図しない動作をした -主にRotateMotorのコマンドを使用した直後、一瞬モーターがこちらの意図しない動作をした -P点のボールを探す際、超音波センサーが反応しないことが多かった **対応策 [#d0e0ba59] -searchDirectionが正常に動作しない問題に対して、恐らくタコメーターのリセットが私たちの思う通りに出来ていないのだろうと予想されたが、修整方法がわからなかったため、別途searchDirection2を作成した。 -一瞬モーターがこちらの意図しない動作をする問題は次の動作に移る前にOnFwd(OUT_AC,1);Wait(1);という処理を加えることで回避できることがわかった -超音波センサーがボールに対して反応しないことについては確実な解決策を講じることが出来なかった。 -超音波センサーがボールに対して反応しないことについては確実な解決策を講じることが出来なかった。きちんとボールに反応することもあったので本番では運任せにする事になってしまった **製作したプログラム [#i11ea2a9] #define SPEED 50 #define SPEED_SLOW 30 const float diameter = 5.45; const float track = 10.35; const float pi = 3.1415; void fwdDist (float d){ // dセンチ前進させる処理 long angle; angle = d / (diameter * pi) * 360.0; RotateMotorEx(OUT_AC,SPEED_SLOW,angle,0,true,true); } void turnAng(long ang){ // ang度旋回させる処理 long angle ; angle = track/diameter*ang; RotateMotorEx(OUT_AC,SPEED_SLOW,angle,100,true,true); } int searchDirection(long ang){ // 近くにある障害物を探してその方向を向き、ボールまでの距離を返す long angle, tacho_min; int d_min; d_min = 300; tacho_min = 0; angle = (track / diameter) * ang; turnAng(ang / 2); ResetTachoCount(OUT_A); OnFwdSync(OUT_AC,SPEED_SLOW,-100); while(MotorTachoCount(OUT_A) <= angle){ if(SensorUS(S3) < d_min){ d_min = SensorUS(S3); tacho_min = MotorTachoCount(OUT_A); } } OnFwdSyncEx(OUT_AC,SPEED_SLOW,100,RESET_NONE); until(MotorTachoCount(OUT_A) <= tacho_min || SensorUS(S3) <= d_min); Wait(15); Off(OUT_AC); Wait(500); return d_min; } void searchDirection2(long ang){ // 近くの障害物を探してその方向を向く処理。距離は返さない long angle, tacho_min; // 何故か searchDirection を2回利用できなかったため急遽作成 int d_min; d_min = 300; tacho_min = 0; angle = (track / diameter) * ang; turnAng(ang/2); ResetTachoCount(OUT_C); OnFwdSync(OUT_AC,SPEED_SLOW,-100); while(MotorTachoCount(OUT_C) >= angle*-1){ if(SensorUS(S3) < d_min){ d_min = SensorUS(S3); tacho_min = MotorTachoCount(OUT_C); } } OnFwdSyncEx(OUT_AC,SPEED_SLOW,100,RESET_NONE); until(MotorTachoCount(OUT_C) >= tacho_min || SensorUS(S3) <= d_min); Wait(15); Off(OUT_AC); Wait(500); } void line () { // ライントレースの処理 float d; int S = 0; SetSensorLight(S2); long t_L = CurrentTick(); while(S<3){ while(CurrentTick() - t_L <= 170) { if (SENSOR_2 < 30) { OnFwd(OUT_C,30); OnRev(OUT_A,25); } else if (SENSOR_2 < 38) { OnFwd(OUT_C,30); Off(OUT_A); } else if (SENSOR_2 < 52) { OnFwd(OUT_AC,30); t_L = CurrentTick(); } else if (SENSOR_2 < 60) { OnFwd(OUT_A,30); Off(OUT_C); t_L = CurrentTick(); } else { OnFwd(OUT_A,30); OnRev(OUT_C,25); t_L = CurrentTick(); } Wait(1); } S++; if(S==1){ // 交差点1回目(点P)を左折してからQ点のボールを狙う Off(OUT_AC); Wait(1000); RotateMotor(OUT_A,SPEED,210); OnFwdSync(OUT_AC,SPEED_SLOW,0); Wait(1000); d = searchDirection(120); fwdDist(d - 8.0); RotateMotor(OUT_C,SPEED_SLOW,150); // 拾う前微調整 RotateMotor(OUT_B,33,80); // 1回目にボールを放ったためにアームが開きすぎているため少し閉じる OnFwdSync(OUT_AC,SPEED,0); // ボール拾い Wait(450); RotateMotor(OUT_B,33,80); Off(OUT_AC); t_L = CurrentTick(); } else if(S==2){ // 交差点2回目(どこかわからない)ではライントレースの処理を終了 break; } } } task main(){ SetSensorLowspeed(S3); SetSensorLight(S2); int mail = 0; int d = searchDirection(120); // ボール探し fwdDist(d - 8.0); RotateMotor(OUT_C,SPEED_SLOW,125); // 拾う前微調整 OnFwdSync(OUT_AC,SPEED,0); // ボール拾い Wait(450); RotateMotor(OUT_B,33,80); Off(OUT_AC); fwdDist(-5); // つかんだ後5cm後ろへ進む RotateMotor(OUT_C,SPEED_SLOW,-300); // 缶付近に移動 OnFwdSync(OUT_AC,SPEED,0); Wait(1800); searchDirection2(90); // 角度合わせ RotateMotor(OUT_C,SPEED_SLOW,90); // 発射前微調整 SendRemoteNumber(1,MAILBOX1,10); // キャッチ側を移動させる為に発信 while(mail != 20){ // キャッチ準備完了待ち Off(OUT_ABC); Wait(1); ReceiveRemoteNumber(MAILBOX1,false,mail); } OnFwd(OUT_B,-70); // ボール発射 Wait(800); Off(OUT_B); turnAng(210); // 後ろを向いてライントレース準備のための移動 OnFwd(OUT_AC,1); Wait(1); OnFwd(OUT_A,SPEED_SLOW); OnFwd(OUT_C,SPEED_SLOW - 3); until(SENSOR_2 < 40); Off(OUT_A); line(); // ライントレース RotateMotor(OUT_A,SPEED_SLOW,220); // 処理を終了する前に適当に移動させる OnFwd(OUT_AC,1); Wait(1); fwdDist(15.0); Off(OUT_ABC); } **反省点・感想 [#ud1a6a42] 調整の時間があまりとれなかったという事もあるが、有効な解決策を見つけられないまま問題の放置をしてしまったことが一番の反省点であると思う。&br; 特に超音波センサーによるボールの検知に関して、スタート地点からすぐにボールを探すのではなく、今回の課題の場合にはボールの位置が固定されているから、ある程度ボールに近づいてからボールの探索を行うようにするという方法もあっただろう。&br; 2つ目のボールに関してはsearchDirectionを複数回使用できない問題もあり、「とりあえず追加した」というような形になってしまった。これに関しても事前の調整の時間をきちんととれていればP点のボールや缶を発見するときとは違った方法で発見して拾うことが出来たのではないかと思う。