#contents *メンバー [#j4b177c9] -j-abc -vocalist -Yuto *課題2の説明 [#c33ef1d9] **フィールドの説明 [#n020b8ff] &ref(2012b/Member/j-abc/Mission2/robocon2012b.png,50%,ロボコンのフィールド); --フィールドは課題1で使用した紙を2枚つなぎ合わせる (向きは自由) --白い紙パックと黒い紙パックがそれぞれ3個づつ対角のゴール(課題1のゴール)に置かれている (前1-個、後2個の2列に配置する) --2枚の紙のつなぎ目に断面が約3cm×4cmの角材を両面テープまたは押しピンで貼り付ける。 --黒い線の幅は20mmとする **基本ルール [#n4cb0367] --白い紙パックと黒い紙パックを入れ替える。 --競技時間は審判が続行不能と判断するまで、あるいはリタイアするまで。 --課題1のスタート地点からスタートする。 --スタート時のロボットは2個を越えないこと (スタート後はいくつに分裂してもかまわない)。 --開始の合図から5秒以内にスタートボタンを押す作業を完了すること。 --競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。 --途中でうまく動かなくなった場合、1回限り再スタートすることができる(再スタートの際に別プログラムで起動してよい)。 --最終的にゴールに運び込まれた紙パックの数で点数を計算する。 **基本得点の計算方法 [#xd7d2b1c] --運びこまれた紙パックに1個つき5点。ただし、紙パックを2段または3段に積み上げた場合は、2段目の紙パックを6点、3段目の紙パックを9点とする。 --紙パックが半分以上ゴールからはみ出している場合は、1個1点、はみ出している部分が半分未満の場合は1個3点とする --一部がゴールの外にはみ出た出た紙パックの上に積み上げられた紙パックは、何段目であっても各3点とする。 **技術点の計算方法 [#z3d23578] ***以下の動作の精度・スピード・確実性などを含めた技術的な工夫や芸術性について他の全てのチーム(5チーム)が20点満点で採点し、その平均点を求める。 得点の目安: [#sddd5f23] --紙パックまでたどり着く動作 (3点) --紙パックを運ぶ動作(2点) --障害物を越える動作 (4点) --2台以上のロボット、あるいは単体のロボットの場合は2台のRCX,NXTの連携の良さ(3点) --自立型のロボットとしての形や動作の美しさ、斬新さ(3点) --その他 (4点) *ロボット [#n2e3b50e] **ロボット1 [#d17cc6f8] #ls2(2012b/Member/Yuto/Mission2,link,こちらを参考) **ロボット2 [#z78677cd] CENTER:&ref(2012b/Member/j-abc/Mission2/robot2_1.jpg,100%,ロボットの全体図); ***紙パックを掴む [#p44814a6] &ref(2012b/Member/j-abc/Mission2/robot2_2.jpg,50%,矢印の方向に動いて);→ &ref(2012b/Member/j-abc/Mission2/robot2_3.jpg,50%,紙パックををロック); -青の矢印の方向に回ることで、アームが赤の矢印の方向に動き紙パックを掴む。 ***紙パックの受け渡し [#q9da8c11] &ref(2012b/Member/j-abc/Mission2/robot2_4.jpg,50%,矢印の方向に動いて);→ &ref(2012b/Member/j-abc/Mission2/robot2_5.jpg,50%,紙パックを押し出し);→ &ref(2012b/Member/j-abc/Mission2/robot2_6.jpg,50%,紙パックを渡す); -青い矢印の方向に進むことで、紙パックを押し出しロボット1のフィールド側に渡す。この逆の動きで紙パックを受け取る。 ***タッチセンサーについて [#n397d600] &ref(2012b/Member/j-abc/Mission2/robot2_7.jpg,50%,タッチセンサー); -赤い矢印のところがタッチセンサーとなっている。タッチセンサーの前にバンパーを設けることでタッチセンサーが反応しやすくなっている。 *プログラム [#a2737eab] **ロボット1のプログラムについて [#f99e3596] #ls2(2012b/Member/Yuto/Mission2,link,こちらを参考) **ロボット2のプログラムについて [#n0c338d3] ***ロボット2の流れ [#dd84cd1e] +ライントレースをし、壁側の交差点まで行く。 +前1個の紙パックを取りに行き、ロボット1と通信を行い渡す。 +残りの後ろ2個の紙パックを取りに行き、ロボット1と通信を行い渡す。 +ロボット1と通信を行い、2個の紙パックを受け取り、所定の場所に運ぶ。 +ロボット1と通信を行い、残り1個の紙パックを受け取り、所定の場所に運ぶ。 ***プログラムの定義 [#b61a0647] -モータAはアームの開閉、モータBは右側のタイヤ、モータCは左側のタイヤ に対応している -タッチセンサー1は左側、タッチセンサー2は右側 に対応している #define THRESHOLD 47 #define SPEED_H 50 //電池あって50 #define SPEED_L 30 //電池あって30 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); #define go_forward OnRL(SPEED_H, SPEED_H); #define turn_left1 OnRL(SPEED_L, -SPEED_L); // 左旋回 #define turn_right1 OnRL(-SPEED_L, SPEED_L); // 右旋回 #define STEP 1 // 1回の判断で動作させる時間 #define nMAX 200 //通常のブとして許容できる繰り返しの最大値 (調整する) #define short_break Off(OUT_BC); Wait(100); // 小休止 #define CROSS_TIME 600 // 交差点通過にかかる時間 ライトレースに使用する定義 #define go_forward2 OnFwdSync(OUT_BC,70,0) //早い速度で前進 #define go_forward3 OnFwdSync(OUT_BC,30,0) //遅い速度で前進 #define go_back OnRevSync(OUT_BC,50,0); //後ろに下がる #define short_break2 Off(OUT_BC);Wait(1500); //中休止 #define short_break3 Off(OUT_BC);Wait(3000); //大休止 #define ONRL(speed,angle) RotateMotor(OUT_BC,speed,angle);Off(OUT_BC);//速度と角度指定で前進or後退 移動に使用する定義(特にONRLは今回とても重要な定義である) #define simeru OnFwd(OUT_A,30); // アームを閉める(紙パックを掴む) #define simeru2 OnFwd(OUT_A,60); // 紙パックを整えるためにアームを閉める #define akeru OnRev(OUT_A,30); //アームを開ける #define akeru2 OnRev(OUT_A,60); //紙パックを整えるためにアームを開ける アームの開閉に使用する定義 #define CONN 1 通信に使用する定義 ***プログラムのサブルーチン [#he9a6129] sub line(){ SetSensorLight(S3); int nOnline=0; // 続けて黒になった回数 (カウンタ) while (nOnline < nMAX){ if (SENSOR_3 < THRESHOLD-12) { turn_right1; nOnline++; // カウンタを増やす } else { if (SENSOR_3 < THRESHOLD-7) { turn_right1; } else if (SENSOR_3 < THRESHOLD+7) { go_forward; } else if (SENSOR_3 < THRESHOLD+15) { turn_left1; } else { turn_left1; } nOnline=0; // カウンタをリセット } Wait(STEP); } turn_left1; Wait(nMAX*STEP); //進行方向修正 } ライントレースを行うサブルーチン sub kabedon(){ SetSensorTouch(S1); SetSensorTouch(S2); go_forward2; until((SENSOR_1 == 1)&&(SENSOR_2 == 1)) } タッチセンサー2個が反応するまで前進するサブルーチン sub okiniiku(){ SetSensorTouch(S1); SetSensorTouch(S2); akeru; Wait(2000); // アームを開ける kabedon(); // 1個目をもらうために壁まで前進 simeru; Wait(2000); // 1個目をつかむ(アームを閉める) short_break3; repeat(3){ // 紙パックを整えるためにアームを3回開閉する akeru2; Wait(500); simeru2; Wait(500); } Off(OUT_A); short_break2; RotateMotor(OUT_A,30,-9); // アームを少し閉め直す short_break2; ONRL(30,-430); // 紙パックを自分のフィールドに持ってくるために後退 short_break2; akeru; Wait(2000); // 一旦アームを開ける short_break2; ONRL(30,180); // 位置調整のために少し前進する short_break2; simeru; Wait(2000); // もう一度アームを閉め、紙パックを掴む short_break3; RotateMotor(OUT_C,50,-400); // 90度曲がり、所定の位置の方向に向く short_break3; akeru; Wait(4000); //アームを開く short_break; } 紙パックを受け取り、置きに行くまでのサブルーチン sub okiniiku2(){ ONRL(50,-195); // 受け取りの位置まで下がる short_break; RotateMotor(OUT_B,50,-430); // 壁に垂直になるように90度曲がる short_break; akeru; Wait(2000); // 受け取りのためにアームを開けておく short_break2; } 紙パックを置いた後、もう一度取りにいけるまでの態勢にし待機するまでのサブルーチン sub master1(){ SetSensorTouch(S1); int msg=0; // 受け取った数値を格納するための変数 int flag=0; // 処理を終了してwhile文を抜けるための変数 while(flag!=1){ SendRemoteNumber(CONN,MAILBOX1,1); // MAILBOX1に1を送る(ロボット2が渡す準備ができた) ReceiveRemoteNumber(MAILBOX2,true,msg); // MAILBOX2の値を読み込む if(msg==1){ // 読み込んだ数値が1なら(ロボット1が受け取り準備ができていたら)以下の動作を行う go_forward3; // 壁まで前進する until(SENSOR_1 == 1); short_break; akeru; Wait(2000); // アームを開ける short_break; go_back; Wait(1500); // 紙パックをアームで押せる距離まで下がる short_break2; simeru; Wait(500); // アームを閉める short_break3; go_forward3; // 紙パックを渡す until(SENSOR_1 == 1); akeru; Wait(2000); // アームを開ける ONRL(50,-360); //2個目を取りにいくために下がる short_break; do{ SendRemoteNumber(CONN,MAILBOX1,2); // MAILBOX1に2を送る(紙パックを渡し終わったことを通知する) ReceiveRemoteNumber(MAILBOX2,true,msg); // MAILBOX2の数値を読み込む(ロボット1が受け取り終わったかどうか) }while(msg!=2); flag=1; // whileを抜けるための数値をいれる SendRemoteNumber(CONN,MAILBOX1,1); SendRemoteNumber(CONN,MAILBOX2,1); } } } ロボット1と通信をし前1個の紙パックを渡すサブルーチン sub master2(){ int msg=0; // 受け取った数値を格納するための変数 int flag=0; // 処理を終了してwhile文を抜けるための変数 while(flag!=1){ SendRemoteNumber(CONN,MAILBOX3,1); // MAILBOX3に1を送る(ロボット2が渡す準備ができた) ReceiveRemoteNumber(MAILBOX4,true,msg); // MAILBOX4の値を読み込む if(msg==1){ do{ SendRemoteNumber(CONN,MAILBOX3,2); // MAILBOX3に2を送る(紙パックを渡し終わったことを通知する) ReceiveRemoteNumber(MAILBOX4,true,msg); // MAILBOX4の数値を読み込む(ロボット1が受け取り終わったかどうか) }while(msg!=2); flag=1; // whileを抜けるための数値をいれる SendRemoteNumber(CONN,MAILBOX3,1); SendRemoteNumber(CONN,MAILBOX4,1); } } } ロボット1と通信をし後ろ2個の紙パックを渡すサブルーチン sub master3(){ int msg=0; // 受け取った数値を格納するための変数 int flag=0; // 処理を終了してwhile文を抜けるための変数 while(flag!=1){ SendRemoteNumber(CONN,MAILBOX5,1); // MAILBOX5に1を送る(ロボット2が受け取る準備ができた) ReceiveRemoteNumber(MAILBOX6,true,msg); // MAILBOX6の値を読み込む if(msg==1){ do{ SendRemoteNumber(CONN,MAILBOX5,2); // MAILBOX5に2を送る(紙パックを受け取り終わったことを通知する) ReceiveRemoteNumber(MAILBOX6,true,msg); // MAILBOX6の数値を読み込む(ロボット1に通知されたかどうか) }while(msg!=2); flag=1; // whileを抜けるための数値をいれる SendRemoteNumber(CONN,MAILBOX5,1); SendRemoteNumber(CONN,MAILBOX6,1); } } } sub master4(){ int msg=0; // 受け取った数値を格納するための変数 int flag=0; // 処理を終了してwhile文を抜けるための変数 while(flag!=1){ SendRemoteNumber(CONN,MAILBOX7,1); // MAILBOX7に1を送る(ロボット2が受け取る準備ができた) ReceiveRemoteNumber(MAILBOX8,true,msg); // MAILBOX8の値を読み込む if(msg==1){ do{ SendRemoteNumber(CONN,MAILBOX7,2); // MAILBOX7に2を送る(紙パックを受け取り終わったことを通知する) ReceiveRemoteNumber(MAILBOX8,true,msg); // MAILBOX8の数値を読み込む(ロボット1に通知されたかどうか) }while(msg!=2); flag=1; // whileを抜けるための数値をいれる SendRemoteNumber(CONN,MAILBOX7,1); SendRemoteNumber(CONN,MAILBOX8,1); } } } ロボット1と通信を行うためのサブルーチン 複数用意されているのは、1つのプログラムをうまく使用できなかったためである。 ***メインプログラム [#k20751ab] task main(){ SetSensorLight(S3); SetSensorTouch(S1); SetSensorTouch(S2); ONRL(50,270); // ラインに行くまでの動き RotateMotor(OUT_C,50,420); line(); // ライントレース short_break; RotateMotor(OUT_B,50,-290); // 壁に垂直になるように曲がる short_break; kabedon(); // 壁まで前進する go_back; Wait(900); // 紙パックを取りに行くためにすこし下がる short_break; RotateMotor(OUT_C,50,-357); // 紙パックをとりにくために90度曲がる short_break; ONRL(50,500); // 紙パックの場所まで前進 short_break; simeru; Wait(4000); // 紙パックを掴む short_break; ONRL(50,-250); //渡す位置まで下がる short_break; RotateMotor(OUT_B,50,-342); //壁に垂直になるよう90度曲がる short_break; master1(); /*ここまでが前1個の紙パックを渡すプログラム*/ RotateMotor(OUT_C,50,-357); // 後ろ2個の紙パックを取りに行くために90度曲がる short_break; ONRL(50,670); // 紙パックがある場所まで前進する short_break; simeru; Wait(4000); // 紙パックを掴む short_break3; ONRL(50,-390); //渡す位置まで下がる short_break; RotateMotor(OUT_B,50,-342); // 壁に垂直になるように90度曲がる short_break; Off(OUT_BC); Wait(10000); //ロボット1の邪魔にならないように少し待機 kabedon(); short_break; akeru; Wait(2000); // アームを開ける short_break; ONRL(50,-300); // 位置調整のために少し下がる short_break2; RotateMotor(OUT_A,30,350); // アームを閉める *1 short_break2; go_forward3; // 壁まで前進 until(SENSOR_2 == 1); short_break; akeru; Wait(2000); // アームを開ける go_back; Wait(1000); // 紙パックを受け取る準備のために下がる Off(OUT_BC); master2(); //ここで通信2 /*ここまでが後ろ2個を渡すプログラム*/ master3(); //ここで通信3 Off(OUT_BC); Wait(20000); // ロボット1の邪魔にならないように少し待機 okiniiku(); //2個もっていく ONRL(50,410); short_break; okiniiku2(); /*ここまでが2個の紙パックを所定の位置まで運ぶプログラム*/ master4(); //ここで通信4 Off(OUT_BC); Wait(30000); // ロボット1の邪魔にならないように少し待機 okiniiku(); ONRL(50,450); // 残りの1個を置きにいく short_break; ONRL(50,-400); /*ここまでが残り1個の紙パックを所定の位置まで運ぶプログラム*/ } --サブルーチンの部分はサブルーチンのところを見てください。 --ロボット1がslaveでロボット2がmasterである。 --*1のアームを閉じるところだけ角度制御を行なっている。理由は通常のアームの開閉は限界まで動かせばよかったので適当で良かったが、2個の紙パックを押し渡すこの動作に限り同じようにアームを閉じてしまうとタイヤが浮いて空回りしてしまうので、その解決法として限界の少し手前になるように閉じたからである。 *感想 [#a99599f7] 初め時間による制御をしていたが電池の残量に大きく左右されていた。しかし、角度による制御法を知ってからかなり正確に制御できるようになり、この課題を上手く進めることができた。しかしながら、それでも電池の残量に少し左右されロボットの制御が難しいということを改めて感じた。 今回はロボットとプログラムの制作両方がとても大変であった。チームのメンバーと何度も集まり試行錯誤しなければならずとても忙しかった。しかし、最終的に紙パックを6個運べ、1位になることができたのでとても嬉しかった。この課題は一人では絶対にできなかったと断言だきる。しかしうまくいったのはチームメンバーの二人の力があったからであり、その力はとても大きいものであったからである。チームメンバーにほんとうに感謝したいと思う。このゼミで機械は所詮は人間が作ったものであるでの間違いや誤差がでてくるのは当然だということ痛感させられ、機械を完璧には信用すべきではないと言うことを学んだ。しかし、その誤差を極力を減らす努力はしていかなければいけないと思った。