[[2012b/Member]] #contents *メンバー [#fac2970d] -atchoo -aspect -HIBINO *課題 [#u09a1dc1] #ref(2012b/Member/HIBINO/Mission2/robocon2012b.png,80%,競技コース) 今回の課題は2台のロボットを上図の2つのstart地点からそれぞれ起動させ,白と黒の四角形で表されているオブジェクトをそれぞれ入れ替えることとなっている.ただし上図真ん中に描かれている茶色のものは壁を表していてこの壁を越えてオブジェクトを入れ替える作業をしなければならない. *競技用ロボット [#kec7b496] **全体 [#p6d6c1f6] #ref(2012b/Member/HIBINO/Mission2/13-02-06_001.jpg,60%,全体像) 本体は今回同じメンバーとして協力したatchooとaspectが前回の課題1で使用したロボットをベースとしてそこに大きいアームを取り付けたものとなっている.また,アームの先端にタイヤパーツをつけてオブジェクトを運ぶ際の滑り止めにし,アームの下側にさらにタイヤパーツ及び出っ張りを設けることによって倒れてしまったオブジェクトをも運ぶことができるようになっている. **アーム(アームを利用したオブジェクトの壁の越え方) [#f5c9d565] #ref(2012b/Member/HIBINO/Mission2/13-02-06_003.jpg,60%,アーム(開き)) アームが開いているところを上から見た図 #ref(2012b/Member/HIBINO/Mission2/13-02-06_007.jpg,60%,アーム(閉じ)) アームが閉じている図 尚今回の課題の要点を占める「壁を越える」方法は以下のようにした. #ref(2012b/Member/HIBINO/Mission2/壁の越え方1.jpg,60%,壁の越え方1) アームでオブジェクトを掴みつつそのまま壁に向かって前進する. #ref(2012b/Member/HIBINO/Mission2/壁の越え方2.png,60%,壁の越え方2) オブジェクトが壁に触れてからも前進を続けるとモーメントの作用に上図のようになる. #ref(2012b/Member/HIBINO/Mission2/壁の越え方3.png,60%,壁の越え方3) さらに掴んだまま前進を続けるとオブジェクトが壁の上に乗り上げる形となる. #ref(2012b/Member/HIBINO/Mission2/壁の越え方4.png,60%,壁の越え方4) 本体が壁に触れた時アームを開くことによってオブジェクトは壁の向こう側に落ちる.このようにしてオブジェクトを壁の向こう側に送る. **センサー類 [#h2a5e749] ***タッチセンサー [#g28a63fd] #ref(2012b/Member/HIBINO/Mission2/13-02-06_005.jpg,60%,タッチセンサー) タッチセンサーは上図のようにアームの下部に取り付けてある.これはアームの項目で説明したオブジェクトを壁の向こう側に送り出す動作の際に非常に重要なもので,本体が壁に触れているかいないかを確認するためのものとなっている.尚,課題2の反省点としてこのタッチセンサーを本体の中心よりやや左側でしか反応しないようにしてしまったものが挙げられる.左に寄っていると少しでも本体の向きが壁とずれていたらタッチセンサーが反応しなくなってしまうからである.パーツの追加によってタッチセンサーが反応する範囲を広げるというのも一つの方法であったと考えている. ***超音波センサー [#oa88d030] #ref(2012b/Member/HIBINO/Mission2/13-02-06_002.jpg,60%,超音波センサー) 超音波センサーは上図のようにアームよりもさらに高い位置で尚且つアームが閉じた時のアームの先端部分を感知するような位置に取り付けた.これはアームを開いた状態で本体がオブジェクトに向かって進んでいき,この超音波センサーに反応があった時に本体の前進を止めてアームを閉じれば必然的にアームがオブジェクトを掴むことになるから,というのが理由である.実際に運用をしてみると超音波センサー自体が誤作動を起こしてしまったり,上手くオブジェクトを感知したとしても若干のラグによって掴めなかったりなど色々なことがあったのだが,それは私たちがプログラムで制御しきれていなかった部分があったからであろう. *プログラム [#e0eb135f] **プログラム概要 [#rf97c347] 今回のプログラムはメンバーであったaspectが使用している方法でプログラムを作成した.大まかに説明をするならば各プログラムごとに小分けをして条件によってその小分けをどの順番で運用するか,というものである.尚,プログラム作成時のミスによりcaseの番号の並び順が1,2,5,3,4となっているがこれはこの順番で正しい. ***プログラム全体 [#k04b5434] #define SPD 40 #define SPD_H 30 //進むスピード #define SPD_Ah -15 //アームの閉じる速度 #define SPD_Ar 15 //アームの開く速度 #define TIM_W 800 //動作準備のための待機時間 #define trasew1 OnFwdReg(OUT_BC,40,OUT_REGMODE_SYNC);Wait(1); #define trasew2 OnFwd(OUT_C,40);Off(OUT_B);Wait(1); task main () { SetSensorLight(S1); //ライトセンサー定義 SetSensorLowspeed(S2); //超音波センサー定義 SetSensorTouch(S3); //タッチセンサー定義 int pattern = 1; //パターン設置 long t0 = CurrentTick(); //時間設定 int t1 = 0; //動作分岐の為の「t1」に0を代入 int count = 0; //動作分岐の為の「count」に0を代入 while(true) { switch(pattern) //"pattern"の開始 { case 1: //オブジェクトに至るまでの直進 if(SensorUS(S2) > 8) { if(t1 <= 300) { t1++; OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(1); } else { t1 = 0; trasew2; } break; } pattern = 2; break; case 2: //オブジェクトを掴む if(count == 1); { OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(550); } Off(OUT_BC); Wait(TIM_W); if(count == 0) { OnFwd(OUT_A,-20); Wait(TIM_W); pattern = 5; break; } OnFwd(OUT_A,-50); Wait(TIM_W); pattern = 5; break; case 5://オブジェクトを掴んだままオブジェクトを壁越えさせるための地点への移動 if(count == 0) { OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(3600); OnFwd(OUT_B,30); OnFwd(OUT_C,-30); Wait(1600); Off(OUT_BC); Wait(TIM_W); pattern = 3; break; } OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(4200); OnFwd(OUT_B,30); OnFwd(OUT_C,-30); Wait(1560); // 1450 Off(OUT_BC); Wait(TIM_W); pattern = 3; break; case 3: //タッチセンサーが接触するまで前進してそこからまた壁越えの済んでいないオブジェクトに向き直す if(SENSOR_3 == 0) { if(t1 <= 10000000) { t1++; OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(1); } else { t1 = 0; trasew2; } break; } Off(OUT_BC); OnFwd(OUT_A,30); Wait(TIM_W); Off(OUT_A); if(count == 0) { OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(3000); // 2400 OnFwd(OUT_B,-30); OnFwd(OUT_C,30); Wait(1200); //1200 count ++ ; Off(OUT_BC); pattern = 1; break; } OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(1550); OnFwd(OUT_B,-30); OnFwd(OUT_C,30); Wait(1100); Off(OUT_BC); pattern = 4; break; case 4://向こう側から越えてきたオブジェクトを感知して指定された位置までそれを運ぶ動作 if(SensorUS(S2) > 8) { if(t1 <= 90) { t1++; OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(1); } else { t1 = 0; trasew2; } break; } Wait(TIM_W); OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(TIM_W); Off(OUT_BC); OnFwd(OUT_A,-30); Wait(TIM_W); OnFwd(OUT_B,-30); OnFwd(OUT_C,30); Wait(800); OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(880); Off(OUT_BC); Wait(30000); break; } } } ***本プログラムにおける定義 [#b4a42852] #define SPD 40 #define SPD_H 30 //進むスピード #define SPD_Ah -15 //アームの閉じる速度 #define SPD_Ar 15 //アームの開く速度 #define TIM_W 800 //動作準備のための待機時間 #define trasew1 OnFwdReg(OUT_BC,40,OUT_REGMODE_SYNC);Wait(1); //(1) #define trasew2 OnFwd(OUT_C,40);Off(OUT_B);Wait(1); //(2) 最初に,BとCの端子についてだがそれぞれ(B:右タイヤ C:左タイヤ)に対応している. 今回のプログラムは定義が少な目になっている.プログラムの各小分けによって数値が違ったり,私が見やすくて作業しやすいように,とaspectに我儘を言った結果であろう. (1)と(2)についてであるが,これはまっすぐ前進をするのに必要な定義である.今回のロボットの設計上の欠陥なのか運用回数におけるモーターの劣化なのかは定かではないがモーターを同期させるプログラムである OnFwdReg(OUT_○,○,OUT_REGMODE_SYNC); を使用しているにも関わらずどうしても左に曲がっていってしまうためにこのような定義をaspectが導入した.この定義が運用される状況にもよるのだが,(1)では左右のタイヤを1/1000秒だけ同期させて動かすものとなっていて,(2)は右タイヤの動きを止め左タイヤだけを1/1000秒だけ動かす,というものである. ***プログラムの開始,およびプログラム内での設定 [#r652b56a] task main () { SetSensorLight(S1); //ライトセンサー定義(未使用) SetSensorLowspeed(S2); //超音波センサー定義 SetSensorTouch(S3); //タッチセンサー定義 int pattern = 1; //パターン設置 (3) long t0 = CurrentTick(); //時間設定 (未使用) int t1 = 0; //動作分岐の為の「t1」に0を代入 (4) int count = 0; //動作分岐の為の「count」に0を代入 (5) while(true) { switch(pattern) //"pattern"の開始 { (3)についてであるが,これは今回のプログラムを作成する上で非常に重要なものである.この「pattern」の値が1である間は後に説明するが「case1」が作動するようになっている.最初は「case1」に作動してもらいたいからこの場面では「pattern」に1を代入している.これも後に出てくるのだが,もし「pattern」に2を代入すれば「case2」が作動し,3を代入すれば「case3」が作動する,というものである. (4)についてであるが,これは定義の中で出てきた(1)と(2)を場面ごとに使い分ける際に必要な「t1」に0を代入,つまりここで初期化をしている,ということである. (5)についてであるが,今回の課題はそれぞれのロボットがオブジェクトを3つずつ壁の向こう側に送る必要がある.その際に動作を2回に分けるのだが,1回目はオブジェクトを1個,2回目はオブジェクトを2個運ぶ,という動作にしている.この時1回目と2回目ではそれぞれアームの閉じる力の強さや,オブジェクトを運びながら動く際のスピードなどがそれぞれ変わってくるのでその2つの条件を分けるために「count」という値を使って判断するようにしている.尚,開始の段階,つまり1個運ぶときは0,2個運ぶときは1になるようになっている.1になるタイミングについては後述する. また,「patternの開始」となっている「switch」を「while」で閉じているのは「pattern」もとい「case」を永続的に運用させるためである. ***case1:オブジェクトまでの移動 [#k5b0bae4] case 1: //オブジェクトに至るまでの直進 if(SensorUS(S2) > 8)// (6) { if(t1 <= 300)// (7) { t1++; OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(1); } else { t1 = 0; trasew2; } break; //(8) } pattern = 2;//(9) break;//(8') (6)についてであるが,これは超音波センサーの真下に超音波センサーから8cm離れただけのもの,つまりオブジェクトが存在しているかどうかを判断している.もし存在していた場合は(9)に飛び,「pattern」の値に2を代入,つまり次は「case2」が作動するようにしているのである.尚,(8)と(8')の「break」についてであるが,これは「case」が終了することを宣言するものである.今回のプログラムについてはすべてを「while」で閉じている為にそのままあらかじめ「pattern」に代入していた数値の「case」に移行するようになっている. (7)の「if」内についてであるが,これはオブジェクトにたどり着くまで真っ直ぐ進むことができるようにするためのものである.具体的には左右のタイヤを1/1000秒だけ動かしたときに「t1」に1を足していき,「t1」が300になった時,「t1」を0に戻して定義していた動作,つまり右タイヤを止め,左タイヤを動かす動作を1/1000秒だけ行う,というものである.今回300となっているのはオブジェクトにたどり着くまでに一度だけ作動するようにしたから,である.後にもこの形をしたプログラムは出てくるのだが,その際は数値の違いのみの説明とする. ***case2:オブジェクトを掴む [#f92c223c] case 2: //オブジェクトを掴む if(count == 1);//(10) { OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(550); } Off(OUT_BC);//オブジェクトは掴める位置にあるために前進止め Wait(TIM_W); if(count == 0)//(11) { OnFwd(OUT_A,-20); Wait(TIM_W); pattern = 5; break; } OnFwd(OUT_A,-50);//(12) Wait(TIM_W); pattern = 5; break; case1によって超音波センサーがオブジェクトを感知した段階でcase2に移るため,アームを閉じればオブジェクトを掴むことができる,という前提である. (10)についてだが,これは先述したように1回目の動作であるのか2回目の動作であるのかを判別している.(10)の「if」内では2回目の動作,つまり2個のオブジェクトを同時に運ぼうとするときにアームがオブジェクトを掴む位置を少しだけ奥にずらす動作となっている.これは1個を運ぶ時と同じ位置だとアームの力が上手く伝わることができず,壁を越えようとする際に失敗することが多かったためである. (11)についてであるが,これは1個だけを運ぶ時なのかどうかを判断している.当然のことながら2個を運ぶときよりも1個を運ぶときの方が力がいらないのでそれぞれアームの力のみを変えている.よって(11)「if」内と(12)以下ではアームの力のみが違っている.そして(11)(12)が済んだときどちらも次はcase5に移行するようになっている. ***case5:オブジェクトを掴んだまま壁越えをする地点までの移動 [#z4a1bb40] case 5://オブジェクトを掴んだままオブジェクトを壁越えさせるための地点への移動 if(count == 0)//(13) { OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(3600); OnFwd(OUT_B,30); OnFwd(OUT_C,-30); Wait(1600); Off(OUT_BC); Wait(TIM_W); pattern = 3; break; } OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC);//(14) Wait(4200); OnFwd(OUT_B,30); OnFwd(OUT_C,-30); Wait(1560); // 1450 Off(OUT_BC); Wait(TIM_W); pattern = 3; break; (13)についてだが,ここでは持っているオブジェクトが1個か2個かを判別している.なので(13)「if」内と(14)以下とでは時間設定のみ変わっている.動作としてはオブジェクトを掴んだ位置からそのまま真後ろに下がり,一定の距離を下がったらそこから壁の方に向く,というものである.なおこの動作の次は1回目だろうと2回目だろうとcase3に移行するようになっている. ***case3:オブジェクトを壁の向こう側まで運ぶ [#oac533e4] case 3: //タッチセンサーが接触するまで前進してそこからまた壁越えの済んでいないオブジェクトに向き直す if(SENSOR_3 == 0)//(15) { if(t1 <= 10000000)//(16) { t1++; OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(1); } else { t1 = 0; trasew2; } break; } Off(OUT_BC);//(17) OnFwd(OUT_A,30); Wait(TIM_W); Off(OUT_A); if(count == 0)//(18) { OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(3000); // 2400 OnFwd(OUT_B,-30); OnFwd(OUT_C,30); Wait(1200); //1200 count ++ ; Off(OUT_BC); pattern = 1; break; } OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC);//(19) Wait(1550); OnFwd(OUT_B,-30); OnFwd(OUT_C,30); Wait(1100); Off(OUT_BC); pattern = 4; break;