[[2009]] *課題2 ライントレースロボットを作る [#qcba8fc1] A11R タイラー/ピーチクパーチク~ #contents **ロボット [#h779cce3] ***車体 [#p2c45fc8] #ref(main.JPG)~ 車輪は基本的にローヴァーロボットの幅をつめたもの。~ ローヴァーロボットとの最大の違いは、ギアを縦に組んだこと。~ 車高を高くすることで安定感が失われるが、光センサーを仕込みやすくコンパクトな仕上がりとなった。~ 前方に伸びた拡張パーツに、センサーやアームを装着する仕組み。 ***タッチセンサー [#ibfeb330] #ref(bamp1.JPG)~ 説明書26pのシングルバンパーをほぼそのまま使用したところ、反応しなかった。~ そのため、テコの原理を利用して長いアームのセンサーを作成。~ #ref(bamp2.JPG) #ref(bamp3.JPG)~ 交差点上の牛乳パックをこれで感知する。~ ***光センサー [#s27b9c2c] 車輪のすぐ前方に装着。センサーを真下に向けることで正確な場所感知を可能に。~ #ref(light.JPG) ***アーム [#x6cce186] #ref(arm1JPG.JPG)~ ギアとモーターを直接繋いだアーム。牛乳パックをこれで移動させる。~ 白ギアの装着により、アームに負荷がかかってもモーターに悪影響を与えない仕組み。~ しかしシンプルな構造だが脆い。車体への取り付けも不安定。~ #ref(arm2.JPG) ***キャスター [#e0833c33] 重くなる前方部分を支えるためのキャスター。~ p46のキャスターや、回転軸と固定位置を同じにしたキャスターを作ってみた。~ が、安定性の問題でうまくいかず、先輩の意見をもとに車輪でなく支え棒を作成。~ しかし、ロボット自体の重さゆえ堅牢性に欠ける。~ そんなわけでシンプルなキャスターを二つ作った。それぞれを拡張パーツの左右に装着。~ #ref(cas1.JPG) #ref(cas2.JPG) ***調整 [#of9d5627] #ref(bamp5.JPG) #ref(cas3.JPG)~ タイヤが大きすぎて不安定だったので小さくした。~ そのためキャスターもゴムを取り外しコンパクト化。小回りが利くようになった。 ***完成 [#x5e75ece] #ref(comp.JPG)~ なんだかカブトムシにクワガタムシを足したような外見になった。~ ***再調整 [#k09db49b] ''・カスタムアーム''~ #ref(arm5.JPG)~ 最大の改造点は強度。~ 基本構造そのままに棒を通すことで、かなりの強度を誇っている。~ また、アーム自体を二段に。~ 牛乳パックを逃さず捕らえるようになった。~ ~ #hr ''・カスタムタッチセンサー''~ #ref(bamp6.JPG)~ 地面に接触して反応してしまうのと、アームとの兼ね合いでバンパーパーツを外した。~ 牛乳パックを見つけにくくはなったが、タッチセンサーとしての効果は十分。~ ~ #hr ''・完成''~ #ref(comp4.JPG)~ ロボットらしく、無骨で巨大なフォルム。~ 虫らしさがほぼ消え去った。~ **コース [#td8c7c25] ***コース1 [#o04034f2] #ref(course1.JPG)~ 交差点:3~ 紙の端や交差点が狭い。 ***コース2 [#a6ffdafc] #ref(course2.JPG)~ 交差点:3~ コース1の改良版。~ 交差点や紙の端など細かいところを改良。 **プロブラム [#ka9d6769] ***1:紙パックをもとの位置に戻したのちコースに戻って進む [#s1680104] 作成:ピーチクパーチク~ ~ 牛乳パックをよけて進むのはコース的に難しそうだったので、~ アームを使ってパックを退かす方向性でプログラムを組んだ。~ ~ ''プログラム1:失敗''~ #define gs(t) OnFwd(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C); //(t)だけ直進 #define gb(t) OnRev(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C); //(t)だけ後退 #define gs2 OnFwd(OUT_A+OUT_C); //直進 #define close OnRev(OUT_B);Wait(40);Off(OUT_B); //アームを閉じる #define open OnFwd(OUT_B);Wait(40);Off(OUT_B); //アームを開く #define THRESHOLD 40 //しきい値 int x = 0; //変数xを定義 task main() { SetSensor(SENSOR_2,SENSOR_TOUCH); SetSensor(SENSOR_1, SENSOR_LIGHT); SetSensor(SENSOR_3, SENSOR_LIGHT); //センサー定義 SetPower(OUT_A,5); SetPower(OUT_C,5); //トルク調整 while (true) { gs2 //前進 OnFwd(OUT_B); //常にアーム開き続ける //ライントレースプログラム //前進中、左右のセンサーが黒線(コース)を捉えるとセンサー側に曲がる if (SENSOR_1 < THRESHOLD) { //右センサ 右に曲がる OnRev(OUT_A); Wait(2); OnFwd(OUT_A); } else if (SENSOR_3 < THRESHOLD) { //左センサ 左に曲がる OnRev(OUT_C); Wait(2); OnFwd(OUT_C); //交差点(両方のセンサが黒線を捉える) } else if ((SENSOR_1 < THRESHOLD) && (SENSOR_3 < THRESHOLD)) { gs(20) x = x + 1; //xにx+1を代入 //障害物の感知 //戻ってから進むことで他の車を回避する仕組み }else if (SENSOR_2 == 1) { ClearTimer(0); //タイマーのセット gb(110) gs(70) //障害物が牛乳パックだったとき // =タイマーが5,5秒以内だったとき } else if (( Timer(0) <= 55) && (SENSOR_2 == 1)) { Float(OUT_A+OUT_C+OUT_B); close //アームを閉じる OnRev(OUT_B); gs(120) //前進 OnFwd(OUT_C);OnRev(OUT_A); //回転 Wait(160); Float(OUT_A+OUT_C); Off(OUT_B); open //アームを開く gb(70); //後退 OnFwd(OUT_C);OnRev(OUT_A); //回転 Wait(130); //三周したら自動的に止まる // =交差点を7回通る (交差点を通る回数ーパックを運ぶ回数+調整値=7) } else if ((SENSOR_1 < THRESHOLD) && (SENSOR_3 < THRESHOLD) && (x == 7)){ Float(OUT_A+OUT_C); break; //while文を終了 } } } ~ 問題点:パックを掴んでからの回転・移動が直線的すぎてコースから外れてしまう~ ~ ~ #hr ''プログラム2''~ 主な変更点~ - タスクの分割 - 回転の精密・複雑化 ~上記のプログラムで説明したものについては、割愛したものがあります。 ~ #define gs(t) OnFwd(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C);//tだけ前進 #define gb(t) OnRev(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C);//tだけ後退 #define gs2 OnFwd(OUT_A+OUT_C);//前進 #define gb2 OnRev(OUT_A+OUT_C);//後退 #define close OnFwd(OUT_B);Wait(40);Off(OUT_B);//アームを開く #define open OnRev(OUT_B);Wait(40);Off(OUT_B);//アームを閉じる #define T 40//しきい値1 #define R 35//しきい値2 int x = 0;//変数x int turna = 0;//回転タスクで使用する変数 int turnc = 0; int halfa = 0; int halfc = 0; //メインタスク task main() { SetSensor(SENSOR_2,SENSOR_TOUCH); SetSensor(SENSOR_1, SENSOR_LIGHT); SetSensor(SENSOR_3, SENSOR_LIGHT); SetPower(OUT_A,5); SetPower(OUT_C,5);ClearTimer(0); while(true){ //障害物にぶつかるまでライントレース if((Timer(0) >= 0)&&((Timer(1) < 1)||(Timer(1) > 100))){ OnRev(OUT_B); start trace;//トレースタスクスタート until(SENSOR_2 == 1);//障害物を感知 stop trace;//トレースタスクエンド ClearTimer(1);//タイマーセット } //障害物にぶつかったとき // 10秒内でプログラムを行う if(Timer(1) < 100){ Float(OUT_A+OUT_C+OUT_B); close; OnFwd(OUT_B); ClearTimer(0);//タイマーセット start trace;//ライントレースタスク スタート until(Timer(0) > 25);//2.5秒進む stop trace;//トレースタスクエンド turnaround();//回転タスク Float(OUT_A+OUT_C+OUT_B); open; ClearTimer(2);//タイマーのセット start btrace;//後ろ向きにのライントレースタスクスタート until(FastTimer(2) > 80);//0.8秒下がる stop btrace;//トレースタスクエンド close; turnaround();//回転タスク、もとのレーンにもどる } } } //ライントレースタスク //メインタスクで呼び出された時に開始 //プログラム1とほぼ同様のプログラムなので変更点だけ説明します。 task trace() { while (true) { gs2; if ((SENSOR_1 < R) && (SENSOR_3 > T)){ //右センサが黒、左センサが白を感知したとき OnRev(OUT_A); } else if ((SENSOR_3 < R) && (SENSOR_1 > T)) { //左センサが黒、右センサが白を感知したとき OnRev(OUT_C); } else if ((SENSOR_1 < T) && (SENSOR_3 < T)) { //交差点 gs(20); x = x + 1; //3周したら停止=交差点を七回通ったとき } else if (((SENSOR_1 < T) || (SENSOR_3 < T))&& (x == 7)){ Float(OUT_A+OUT_C); break; } } } //バックライントレースタスク // 光センサーの位置の問題で、少し進んで回転という動作を行っている。 // メインタスクに呼び出されたとき開始。 // 逆向きに進むだけで前進ライントレースとほとんど同様のプログラムなので説明を割愛。 task btrace() { while (true) { gb2; if ((SENSOR_1 < R) && (SENSOR_3 > T)){ OnFwd(OUT_A+OUT_C); Wait(1); OnRev(OUT_C); Wait(2); } else if ((SENSOR_3 < R) && (SENSOR_1 > T)) { OnFwd(OUT_A+OUT_C); Wait(1); OnRev(OUT_A); Wait(2); } else if ((SENSOR_1 < T) && (SENSOR_3 < T)) { gb(20); } } } //回転プログラム //相方のものを教えてもらって搭載。 // メインタスクに呼び出されたとき開始。 // 左右のセンサが黒線を通り過ぎた後、両方のセンサが白の上に来ると止まる。 void turnaround() { Off(OUT_A+OUT_C); while ((turna == 0)||(turnc == 0)){ OnFwd(OUT_A); OnRev(OUT_C); Wait(10); Off(OUT_A+OUT_C); //常に反時計周りに回転するプログラム if (SENSOR_1 < T){ //センサ1が黒の上のとき halfa = 1; } else if (SENSOR_3 < T){ //センサ3が黒の上のとき halfc = 1; //両方が一度でも黒の上に載ったことがあるとき // =半回転したとき } else if ((halfa == 1)&&(halfc == 1)){ if (SENSOR_1 > T){ //センサ1が白のとき turna = 1; } else { turna = 0; } if (SENSOR_3 > T){ //センサ3が白のとき turnc = 1; }else{ turnc = 0; } } //両方のセンサが白の上にある=黒い線をまたいでいる } OnFwd(OUT_A); OnRev(OUT_C); Wait(8); Off(OUT_A+OUT_C);//回転 turna = 0;//変数の初期化 turnc = 0; halfa = 0; halfc = 0; } 調整が大変だったが、なんとかプログラムの完成にはこぎつけた。~ しかし、必ず成功するプログラムではないので、もっと精度を高める必要がある。 ***2:紙パックを次の交差点まで運んで行き、その交差点に紙パックを残してさらに黒い線に沿って進む [#j981cd9b] 作成:タイラー #define THOLD 40 //しきい値 #define JAW_SPEED 1 //アーム作動速度 #define DRIVE_SPEED 3 //作動速度 #define turnWait 4 //回転時待機時間 //PlaySound(0); int bite = 0; int iTurnA = 0; //回転プログラムに使用する変数 int iTurnC = 0; int halfwayA = 0; int halfwayC = 0; //ここまで int adju = 0; int intersFakeBool1 = 0; int intersFakeBool2 = 0; int intersFakeBool3 = 0; int waiter1 = 0; int wlCnt = 0; //回転プログラム // 常に回転し、左右のセンサーがそれぞれ黒線を感知した後、両方が白を感知すると止まる。 // =コースに対して逆走方向を向く void turnAround() { Off(OUT_A+OUT_C); while ((iTurnA == 0)||(iTurnC == 0)) { OnFwd(OUT_A); OnRev(OUT_C); Wait(10); Off(OUT_A+OUT_C); if (SENSOR_1 < THOLD) { halfwayA = 1; } if (SENSOR_3 < THOLD) { halfwayC = 1; } if ((halfwayA == 1)&&(halfwayC == 1)) { if (SENSOR_1 > THOLD) { iTurnA = 1; } else { iTurnA = 0; } if (SENSOR_3 > THOLD) { iTurnC = 1; } else { iTurnC = 0; } } } OnFwd(OUT_A); OnRev(OUT_C); Wait(8); Off(OUT_A+OUT_C); iTurnA = 0; iTurnC = 0; halfwayA = 0; halfwayC = 0; } //End turnAround() //ライントレースプログラム // 変数backorFwdを変化させることで前方に進む、後方に進むの二通りの動作をこなす。 // 後ろ向きに進むとき、センサの位置の問題で動き方が違うものになる。 // 後退して、左センサが黒を感知したとき、黒を感知するまで右回転し、また後退。 // 車体をそのつどカーブに合わせるようにして進む。 void adjust(int backOrFwd) {//If foward backOrFwd = 0: if backward backOrFwd = 1 //両方のセンサが黒にいるとき if((SENSOR_1 < THOLD) && (SENSOR_3 < THOLD))//============================= {//Drive Straight if you meet an intersection. if(backOrFwd == 0) //前進時 { Float(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); Wait(turnWait); Float(OUT_A+OUT_C); } else if(backOrFwd == 1) //後退時 { Float(OUT_A+OUT_C); OnRev(OUT_A+OUT_C); Wait(turnWait+5); Float(OUT_A+OUT_C); } } //右側が黒を感知したとき else if(SENSOR_1 < THOLD)//================================================ { //Right sensor tripped turn left if(backOrFwd == 0) //前進時 { Off(OUT_A+OUT_C); OnFwd(OUT_C); Wait(turnWait); Off(OUT_C); Wait(2); } else if(backOrFwd == 1) //後退時 { //Right sensor tripped turn left //Reverse opposite until seeing the black line Off(OUT_A+OUT_C); until(SENSOR_3 < THOLD) { OnFwd(OUT_C); } Off(OUT_C); //Reverese concerning side unti seeing black line until(SENSOR_1 < THOLD) { OnFwd(OUT_A); } OnRev(OUT_A+OUT_C); Wait(15); Off(OUT_A+OUT_C); } } //左側センサが黒を感知したとき else if(SENSOR_3 < THOLD)//============================================== { if(backOrFwd == 0) //前進時 { //Left sensor tripped turn right Off(OUT_A+OUT_C); OnFwd(OUT_A); Wait(turnWait); Off(OUT_A); Wait(2); } else if(backOrFwd == 1) //後退時 { Off(OUT_A+OUT_C); until(SENSOR_1 < THOLD) { OnFwd(OUT_A); } Off(OUT_A); //Reverese concerning side unti seeing black line until(SENSOR_3 < THOLD) { OnFwd(OUT_C); } OnRev(OUT_A+OUT_C); Wait(15); Off(OUT_A+OUT_C); } } else { if(backOrFwd == 0) { //PlaySound(0); OnFwd(OUT_A+OUT_C); Wait(5); Float(OUT_A+OUT_C); } else if(backOrFwd == 1) { //PlaySound(0); OnRev(OUT_A+OUT_C); Wait(5); Float(OUT_A+OUT_C); } } } //============================================================================= //============================================================================= //メインタスク task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); //Right 右光センサ SetSensor(SENSOR_2,SENSOR_TOUCH);//Touch Sensor SetSensor(SENSOR_3,SENSOR_LIGHT);//Left 左光センサ SetPower(OUT_A,DRIVE_SPEED); SetPower(OUT_B,DRIVE_SPEED); SetPower(OUT_C,DRIVE_SPEED); //トルク変更 adju = 0; while(true) { //adjust(1); //タッチセンサーが反応するか変数biteが1のとき if (SENSOR_2 == 1 || bite == 1) { if(bite == 0) // biteが0のとき {//If first touch milk carton 最初にパックに触ったとき、 //Stop and bite, 止まって掴む。 Off(OUT_A+OUT_C); Wait(40); OnFwd(OUT_B); bite = 1;//Let program know bite has occured 変数biteを1に。次のプログラムへ } else if(bite == 1) //biteが1のとき {//Run Normally plus keep biting //パックを掴んだまま通常運転 OnFwd(OUT_B); adjust(adju); //IF both sensors 交差点にさしかかったとき=両方のセンサが黒を感知し、後述する位置補正プログラムが実行されたとき // 進み、回転し、パックを離し、後退し、回転し、通常運転に戻る。 if(SENSOR_1 < THOLD && SENSOR_3 < THOLD && intersFakeBool2 == 1) { PlaySound(4); //音を鳴らす while(wlCnt < 36) //変数wlcntが36になるまで前進 { adjust(0); //一度前進プログラムを動かすたびに変数wlcntに+1する。 wlCnt = wlCnt + 1; } wlCnt = 0; PlaySound(3);//音を鳴らす turnAround(); OnRev(OUT_B);//パックを離す while(wlCnt < 20) //20回前進プログラムを動かす { adjust(1); wlCnt = wlCnt + 1; } wlCnt = 0; PlaySound(4); //音を鳴らす Off(OUT_A+OUT_B); Wait(80); turnAround(); //回転プログラムの実行 OnRev(OUT_B); intersFakeBool2 = 0; intersFakeBool1 = 0; bite = 0; //通常運行に戻るため、タスク内ルーチンの変数を初期化 } //両方が黒を感知したとき、位置調整プログラムを実行する else if(SENSOR_1 < THOLD && SENSOR_3 < THOLD) { intersFakeBool1 = 1; PlaySound(3); while(wlCnt < 15) //変数wlcntが15になるまで前進プログラムを動かす { adjust(adju); wlCnt = wlCnt + 1; } wlCnt = 0; } else if(intersFakeBool1 == 1) { //PlaySound(1); intersFakeBool2 = 1; //位置調整プログラム実行終了を表すため変数intersfakebool2を1に } } } //通常運行=ライントレース else //Run Normally =============================================== { adjust(adju); //ライントレースプログラムを動かす } } } **感想 [#i0bc5724] ピーチクパーチク:~ ただライントレースさせればいいだけだ、と簡単に思っていたが、~ さまざまな問題点が浮き彫りになってとても苦労した。~ 他グループのメンバーにも多少なり手伝っていただいたので、ここでお礼を申し上げておきます。ありがとうございました。~ タイラー:~ もしもう一度このロボットを作る機会があったら、もっといいものが作れたと思う。~ **コメント [#w23da78b] - ロボットとコースの説明はとてもよくできています。プログラムについて、taskを分割したということですが、どのようなときに、どのtaskが同時に実行されるのでしょうか?「このtaskはこんなときに起動、○○しながら××する」のような説明を入れてみてください。 -- [[こさか]] &new{2009-07-02 (木) 23:10:54}; - 全体としてプログラムの説明不足です。特に二人目のプログラムには説明がありません -- [[FI]] &new{2009-07-03 (金) 05:32:28}; - Timer()を初期化せずに使用していることが気にかかります…。そして、プログラムのパーツごとの動きは説明でわかるのですが、全体としてどのような流れなのかがあまりつかめません。ソースの中に説明を入れる以外に、フローチャートなどを用いていただくと分かりやすくなると思います。 -- [[こさか]] &new{2009-07-10 (金) 12:16:19}; #comment