[[2012b/Member]] #contents 尚,case5がcase2とcase3の間にあるが,これはこの順番で正しい. *メンバー [#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 SPD_Ah -20 //アームの閉じる速度 #define SPD_Ar 20 //アームの開く速度 #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); #define trasew1 OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC);Wait(1); #define trasew2 OnFwd(OUT_C,SPD);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); OnFwd(OUT_A,SPD_Ah); 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); OnFwd(OUT_B,SPD_H); OnFwd(OUT_C,SPD_H); 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 OnFwd(OUT_B,SPD_H); OnFwd(OUT_C,-SPD_H); Wait(1560); 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); OnFwd(OUT_A,SPD_Ar); 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 Wait(3000); OnFwd(OUT_B,-SPD_H); OnFwd(OUT_C,SPD_H); Wait(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); OnFwd(OUT_B,-SPD_H); OnFwd(OUT_C,SPD_H); 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); OnFwd(OUT_A,SPD_Ah); Wait(TIM_W); OnFwd(OUT_B,-30); OnFwd(OUT_C,30); OnFwd(OUT_B,-SPD_H); OnFwd(OUT_C,SPD_H); 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 SPD_Ah -20 //アームの閉じる速度 #define SPD_Ar 20 //アームの開く速度 #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); OnFwd(OUT_A,SPD_Ah); 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); OnFwd(OUT_B,SPD_H); OnFwd(OUT_C,-SPD_H); 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); OnFwd(OUT_B,SPD_H); OnFwd(OUT_C,-SPD_H); Wait(1560); 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); OnFwd(OUT_A,SPD_Ar); Wait(TIM_W); Off(OUT_A); if(count == 0)//(18) { OnFwdReg(OUT_BC,-SPD,OUT_REGMODE_SYNC); Wait(3000); OnFwd(OUT_B,-30); OnFwd(OUT_C,30); OnFwd(OUT_B,-SPD_H); OnFwd(OUT_C,SPD_H); Wait(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); OnFwd(OUT_B,-SPD_H); OnFwd(OUT_C,SPD_H); Wait(1100); Off(OUT_BC); pattern = 4; break; (15)ではタッチセンサーが反応しているかどうかを判断している.また(15)「if」内では(16)とあるが,これは先述した真っ直ぐ前進をするためのプログラム(7)と同じもので,今回はt1が10000000になるまで前進,となっている.これタッチセンサーが反応するまでに一度だけ作動する頻度である. (17)ではタッチセンサーが反応している=本体が壁に接している状態なため,ここで前進を止めて,アームを開いてオブジェクトを完璧に壁の向こう側に送るようになっている.この後,この段階でオブジェクト運搬の1回目であれば2回目に行かなければならないし,2回目であれば向こう側から送られてきたオブジェクトに向かうための準備動作をしなければならないので,(18)で1回目か2回目かを判断している.尚(18)「if」内の動作,つまり1回目から2回目への移行は一定距離後ろに下がり,そこから残っている2つのオブジェクトの方に向き直るようになっている.またその後に「count」に1を足すことによって次回から2回目の動作としてプログラムが作動するようになっている.そしてそのままpattern1に移行するようになっている. (19)以下は2回目のオブジェクトの運搬後の動作,つまり向こう側から送られてきたオブジェクトに向かうための動作であり,少し後ろに下がった後,送られてきたオブジェクトの方に向き,そのままpattern4に移るようになっている.尚,(18)「if」内の動作よりも(19)以下の動作の方が短い時間になっているのは,送られてきたオブジェクトが置かれている場所は残されていたこちらのオブジェクトの位置よりもその段階での本体の位置に,より近い位置となっているからである. ***case4:送られてきたオブジェクトを掴み,目的地まで運ぶ [#k65dbdd8] case 4://向こう側から越えてきたオブジェクトを感知して指定された位置までそれを運ぶ動作 if(SensorUS(S2) > 8)//(20) { if(t1 <= 90)//(21) { t1++; OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(1); } else { t1 = 0; trasew2; } break; } Wait(TIM_W);//(22) OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(TIM_W); Off(OUT_BC); OnFwd(OUT_A,-30); OnFwd(OUT_A,SPD_Ah); Wait(TIM_W); OnFwd(OUT_B,-30); OnFwd(OUT_C,30); OnFwd(OUT_B,-SPD_H); OnFwd(OUT_C,SPD_H); Wait(800); OnFwdReg(OUT_BC,SPD,OUT_REGMODE_SYNC); Wait(880); Off(OUT_BC); Wait(30000); break; } } } (20)では超音波センサーが反応する=アームが掴める距離に向こう側から送られてきたオブジェクトが存在しているかどうかを判断している.尚,存在していない場合は(21)に移るが,これも(7)と同様に真っ直ぐ前進をするためのプログラムであり,こちらは「t1」が90になるまで前進をする,となっている.理由は定かではないがこの時の前進は他の時の前進と比べて曲がっていきやすいため,調整が頻繁に入るようになっている.存在していた場合は(22)に移る.(22)以下では超音波センサーがオブジェクトを感知した位置よりも少し前進してよりオブジェクトをアームで囲い込むようにしている.その後でアームを閉じ,目的地の方を向いて少し前進し,アームで囲い込んでいたオブジェクトを目的地に置くようになっている. *感想 [#oef1b823] 課題2は課題1の時のメンバーを2つ統合して1つのメンバーとなっている.残念なことに1人が抜けてしまったのだが,とりあえず3人でこなすことができた.今回のプログラムで使用した「pattern」「case」「switch」等は今回一緒のメンバーとなったaspectから教わったもので,彼からは様々なプログラムの可能性も教わった.工学系といえども,やはり繊維学部と工学部の違いを実感した.オブジェクトを壁の向こう側に送るアイデアは前回受講した「スキーロボットについての講義」の中で「能動型のロボットも有りなのだが受動型のロボットも注目されてきている」というのを思い出して考えたものである.ギアの作用によって1つのモーターで持つ→上げるの動作を行うことも可能であったのだが,そもそもそれを作るだけの技術が無かったのもこのアイデアで決定された理由の1つであろう.課題2の結果としてはオブジェクトを壁の向こう側へ送ることはできたのだが,1つのオブジェクトをも目的地に運びきれなかった.これはやはり行動の大半を時間指定で行っていたからであろう.途中まで課題2のルールを勘違いしていた部分があり,そのためあまり時間をかけてプログラミングすることができなかったのである.これはロボティクスのみではないが,他人が言った不確かなことを鵜呑みにしてしまうのは避けた方が良いと思い知らされた.また,今回の課題2を行うに当たってもう1人のメンバーのatchooの存在は不可欠なものであった.彼は雑務と呼ばれるようなものや調整など,細かな作業を自ら引き受けてくれて,全体の進行の円滑化をはかってくれた.確かに今回の課題については失敗してしまったが,メンバー全員が協力をして,時には話し合ったりお互いに頭を悩ませ合ったりすることの大事さや楽しさを学んだ.後悔することと言えば課題1で「行動の時間設定はプログラムとしては非常に脆いものである」と学んだと自分で言っておきながらそれを活かすことができなかったことである.これは先生にも申し訳なかった.この課題を以てロボティクス入門ゼミは講義としては終了であったが,願わくばこれから先私はロボットと関わっていき,尚且つこのゼミで学んだこと,特に「時間制御のプログラムは脆い」と言うことを忘れないでいきたい.このゼミは非常に有意義なものであった.