目次 #contents *課題説明 [#tf0f6ee4] 今回の課題は、紙に書かれた黒い線の上をなぞって進み、途中置かれている紙コップをつかみ指定の場所まで移動させゴールするという課題である。 *コース [#i3b3d179] #ref(2017b/Member/Masa/Mission2/ko-su.jpg,75%,コースの画像) このコースを使ってライントレースする。3つの経路のうち私は第1コースとなった。 第1コース -1. Aをスタート -2. Bを直進 -3. Cを右折 -4. Fを直進 -5. Rを左折(一時停止) -6. Pを直進 -7. X地点の紙コップを取得してコースに戻る -8. Qを左折 -9. Sを直進(一時停止) -10. Y地点に紙コップを置いてコースに戻る -11. Sを直進(一時停止) -12. Fを左折(一時停止) -13. Cを右折(一時停止) -14. D地点へ(ゴール) また、コースを作りで線を黒く塗るときに真ん中が一番黒くなるようにした。 *ロボット概要 [#bc29bc06] **ロボット本体 [#l1f7fb7f] #ref(2017b/Member/Masa/Mission2/torekitai1.jpg,150%,機体全体の画像) 今回は、前回の課題1のときより動く距離が長いためできるだけ小さくする方がよいと考えた。なので、動作に問題がなければ細かいところでしっかり固定したりはしないようにした。 **センサーについて [#k2fbf3a3] #ref(2017b/Member/Masa/Mission2/sensorkakudo.jpg,150%,センサーの取り付け角度) 最初センサーの値の計測をしたときに少し角度がつくようにして計測したためそのままセンサーは地面に対して少し角度がつくように取り付けた。試しに地面に垂直に取り付けてみたが、値が角度をつけたときと大きく変わって低くなり、変化する幅も小さくなったため難しそうだと判断した。(センサーと地面が近すぎだけかもしれない) **紙コップを取る機構 [#t91751e3] 紙コップを取るには紙コップを取れる位置まで移動しないといけないが、その調整が大変そうだったので紙コップの方を移動させることにした。 &ref(2017b/Member/Masa/Mission2/kamicp1.jpg,150%,紙コップを捕まえる工夫); 機体の前についた棒にはまるように紙コップを移動させ &ref(2017b/Member/Masa/Mission2/kamicp2.jpg,150%,紙コップをつかむ); 紙コップをつかむ *交差点、カーブの判断方法について [#nb9f329c] #ref(2017b/Member/Masa/Mission2/keiro1.jpg,140%,コースの色について) コースの色の大体の値は一番黒いところが30%、その次に黒いところが40%、白いところが70%である。 #ref(2017b/Member/Masa/Mission2/keiro2.jpg,140%,走るところの説明) 基本的に40%のところをまっすぐ走るようにし、黒いところ、白いところに行くと右側を走っているか、左側を走っているかによるが、それに応じて右に曲がる、左に曲がるプログラムにしいている。今回作ったライントレースのプログラムはカウンター方式で、一番黒いところ、次に黒いところ、白いところの3つ、あるいはそれぞれの場所の値の間にもう1ヶ所増やし5ヶ所を判別するプログラムを作り、それぞれの場所でする行動(前進、右に曲がる、左に大きく曲がる、など...)に付け加えてカウンターを増やすプログラムとカウンターをリセットするプログラムを追加する。そのカウンターに上限の値を設定してき、値を超えるとプログラムを終了するようにしている。このプログラムは交差点だけ反応してほしいのに緩やかなカーブでも反応してしまうときなどは、上限の値を変えるもしくは、モーターのパワーを小さくし遅くすることで誤反応をなくすことができる。 **交差点の判定 [#l3bdbcee] 今からの説明は右側を走っている場合である。 #ref(2017b/Member/Masa/Mission2/keiro3.jpg,140%,交差点の判定1) 交差点に行くと一番黒い線にぶつかる。 #ref(2017b/Member/Masa/Mission2/keiro4.jpg,140%,交差点の判定2) プログラムによって右のタイヤを支点として右に曲がるが、しばらくは黒いところが続くのでカウンターがたまっていく。 #ref(2017b/Member/Masa/Mission2/keiro5.jpg,140%,交差点の判定3) すると、カウンターが設定していた値を超え実行していたプログラムが終了し次のプログラムに移行する。 #ref(2017b/Member/Masa/Mission2/keiro6.jpg,140%,交差点の判定4) 次のプログラムは、交差点から抜け出すもので光センサーが白いところを読み取るまで左タイヤを支点に左に曲がるというものである。 #ref(2017b/Member/Masa/Mission2/keiro7.jpg,140%,交差点の判定5) 白いところまで行くとカウンターをカウントし始める。この時のカウンターの設定値を小さくしておくことで一瞬でも読み取るとプログラムが終わるようになっている。 #ref(2017b/Member/Masa/Mission2/keiro8.jpg,140%,交差点の判定5) 交差点を抜けたら、最初に説明したプログラムを実行する。そうすると、黒いところまで左に曲がりライントレースを再開する。この時、プログラムのカウンターは白いところにあるので0となりプログラムが途中で終了することはない。 **カーブの判定 [#ze73f4c2] #ref(2017b/Member/Masa/Mission2/cab1.jpg,140%,カーブのの判定1) カーブに入ってくる直進用のプログラムも少し変えている。 &ref(2017b/Member/Masa/Mission2/cab2.jpg,140%,カーブのの判定2); まだ緩やかなところでは、 &ref(2017b/Member/Masa/Mission2/cab3.jpg,140%,カーブのの判定3); ライントレースを続ける。 #ref(2017b/Member/Masa/Mission2/cab4.jpg,140%,カーブのの判定4) しかし、カーブがきつくなると白いところから抜け出すのが遅くなる。なのでカウンターを白いところでカウントするようにしておき値を調整すると、図のようなところでカウンターが設定した値となり、プログラムが終了する。 #ref(2017b/Member/Masa/Mission2/cab5.jpg,140%,カーブのの判定5) そして、カーブ用のプログラムが実行される。このプログラムは直進用とほとんど同じで、違うのは白い所に出たときに起動する左に曲がるプログラムを左のタイヤを止めて曲げるのではなく、左は逆回転して曲がるものにする。そうすると急なカーブを曲がることができる。 #ref(2017b/Member/Masa/Mission2/cab6.jpg,140%,カーブのの判定6) また、このカーブのプログラムにもカウンターをつけており、2番目に黒いところでカウンターがカウントされるようにしておく。そうすることで、直進になった時にカウントが設定した値になり、うろグラムが終了するようになる。(このとき、誤作動しないように設定する値は少し大きめにしておく。 *プログラムについて [#aa137803] **定義 [#mb6c9767] #define speedA 28 //モーターAの出力 #define speedB 26 //モーターBの出力 #define Cpower 20 //モーターCの出力 #define THRESHOLD 50 //しきい値 #define STEP 1 //1回の判定で進む時間 #define sA2 speedA/2 //Aの出力1/2 #define sB2 speedB/2 //Bの出力1/2 #define sA3 speedA/3 //Aの出力1/3 #define sB3 speedB/3 //Bの出力1/3 #define sA4 speedA/4 //Aの出力1/4 #define sB4 speedB/4 //Bの出力1/4 パワーが大きいと動きが速くなり反応しないことがあったので少し小さめにした **サブルーチン [#fd36586f] sub go_forward(int x,int y) //前進 { OnFwd(OUT_A,speedA-x);OnFwd(OUT_B,speedB-y); } sub go_back(int x,int y) //後進 { OnFwd(OUT_A,-speedA-x);OnFwd(OUT_B,-speedB-y); } sub go_right1(int x,int y) //右の車輪を軸に右へ { OnFwd(OUT_B,speedB-y);Off(OUT_A); } sub go_left1(int x,int y) //左の車輪を軸に左へ { OnFwd(OUT_A,speedA-x);Off(OUT_B); } sub go_right2(int x,int y) //その場で右へ { OnFwd(OUT_A,-speedA-x);OnFwd(OUT_B,speedB-y); } sub go_left2(int x,int y) //その場で左へ { OnFwd(OUT_A,speedA-x);OnFwd(OUT_B,-speedB-y); } ロボットの基本的な動きである前進、後進、右回転、左回転を関数にしている。関数の引数であるx,yに数値を入れるとその分だけスピードを遅くすることができるようにしてある。 sub gogo_b(int x,int y) //黒い線まで前進 { while (SENSOR_1 > THRESHOLD -9){ go_forward(x,y); Wait(STEP); } PlayTone(523,50); } sub gogo_w(int x,int y) //白い線まで前進 { while (SENSOR_1 < THRESHOLD -9){ go_forward(x,y); Wait(STEP); } PlayTone(523,50); } sub lele(int x,int y) //黒い線まで左回転 { while (SENSOR_1 < THRESHOLD -9){ go_left1(x,y); Wait(STEP); } PlayTone(523,50); } センサーが指定された値を読み取るまで動くようにした。また、動作が終わると音が鳴る。 sub r_left(int x,int y) //右側で左カーブ { int n = 0; while (n<400){ if (SENSOR_1 < THRESHOLD -13) { go_right2(x,y);n=n+1; } else if (SENSOR_1 < THRESHOLD -9) { go_forward(x,y);n=n+1; } else if (SENSOR_1 < THRESHOLD +10) { go_left1(x,y); } else { go_left2(x,y);n=0; } Wait(STEP); } PlayTone(587,50); } sub l_right(int x,int y) //左側で右カーブ { int n = 0; while (n<300){ if (SENSOR_1 < THRESHOLD -15) { go_left2(x,y);n=0; } else if (SENSOR_1 < THRESHOLD -13) { go_left1(x,y); } else if (SENSOR_1 < THRESHOLD -9) { go_forward(x,y);n=n+1; } else if (SENSOR_1 < THRESHOLD +10) { go_right1(x,y); } else { go_right2(x,y);n=0; } Wait(STEP); } PlayTone(587,50); } sub r_right(int x,int y) //右側で右カーブ { int n = 0; while (n < 300){ if (SENSOR_1 < THRESHOLD -15) { go_right2(x,y); n=0; } else if (SENSOR_1 < THRESHOLD -13) { go_right1(x,y); } else if (SENSOR_1 < THRESHOLD -9) { go_forward(x,y); n=n+1; } else if (SENSOR_1 < THRESHOLD +10) { go_left1(x,y); } else { go_left2(x,y); n=0; } Wait(STEP); } PlayTone(587,50); } sub l_straight1(int x,int y) //左側で直進1 { int n = 0; while (n<300){ if (SENSOR_1 < THRESHOLD -15) { go_left1(x,y);n=0; } else if (SENSOR_1 < THRESHOLD) { go_forward(x,y); } else { go_right1(x,y);n=n+1; } Wait(STEP); } PlayTone(523,50); } sub l_straight2(int x,int y) //左側で直進2 { int n = 0; while (n<300){ if (SENSOR_1 < THRESHOLD -15) { go_left1(x,y);n=n+1; } else if (SENSOR_1 < THRESHOLD) { go_forward(x,y); } else { go_right2(x,y);n=0; } Wait(STEP); } PlayTone(523,50); } sub l_straight3(int x,int y) //左側で直進3 { int n = 0; while (n < 250){ if (SENSOR_1 < THRESHOLD -15) { go_left1(x,y);n=n+1; } else if (SENSOR_1 < THRESHOLD -9) { go_forward(x,y); } else { go_right1(x,y);n=0; } Wait(STEP); } PlayTone(523,50); } sub l_straight4(int x,int y) //左側で直進4 { int n = 0; while (n<300){ if (SENSOR_1 < THRESHOLD -15) { go_left1(x,y);n=0; } else if (SENSOR_1 < THRESHOLD - 9) { go_forward(x,y); } else { go_right2(x,y);n=n+1; } Wait(STEP); } PlayTone(523,50); } sub r_straight1(int x,int y) //右側で直進1 { int n = 0; while (n < 300){ if (SENSOR_1 < THRESHOLD -13) { go_right2(0,0); n=n+1; } else if (SENSOR_1 < THRESHOLD) { go_forward(x,y); } else { go_left1(x,y); n=0; } Wait(STEP); } PlayTone(523,50); } sub r_straight2(int x,int y) //右側で直進2 { int n = 0; while (n < 300){ if (SENSOR_1 < THRESHOLD -13) { go_right2(0,0); n=0; } else if (SENSOR_1 < THRESHOLD) { go_forward(x,y); } else { go_left1(x,y); n=n+1; } Wait(STEP); } PlayTone(523,50); } sub r_straight3(int x,int y) //右側で直進3 { int n = 0; while (n < 300){ if (SENSOR_1 < THRESHOLD -13) { go_right1(0,0); n=0; } else if (SENSOR_1 < THRESHOLD) { go_forward(x,y); } else { go_left1(x,y); n=n+1; } Wait(STEP); } PlayTone(523,50); } sub r_straight4(int x,int y) //右側で直進4 { int n = 0; while (n < 250){ if (SENSOR_1 < THRESHOLD -13) { go_right2(0,0); n=n+1; } else if (SENSOR_1 < THRESHOLD) { go_forward(x,y); } else { go_left1(x,y); n=0; } Wait(STEP); } PlayTone(523,50); } sub l_w() //白くなるまで左へ1 { int n = 0; while (n<50){ if (SENSOR_1 < THRESHOLD +15) { go_left1(sA4,sB4); } else { go_left1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub l_w2() //白くなるまで左へ2 { int n = 0; while (n<50){ if (SENSOR_1 < THRESHOLD +15) { go_left2(sA4,sB4); } else { go_left1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub l_w3() //白くなるまで左へ3 { int n = 0; while (n<150){ if (SENSOR_1 < THRESHOLD +15) { go_left1(sA4,sB4); } else { go_left1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub r_w() //白くなるまで右へ1 { int n = 0; while (n<50){ if (SENSOR_1 < THRESHOLD +15) { go_right1(sA4,sB4); } else { go_right1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub r_w2() //白くなるまで右へ2 { int n = 0; while (n<50){ if (SENSOR_1 < THRESHOLD +15) { go_right2(sA4,sB4); } else { go_right1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub r_b() //黒くなるまで右へ1 { int n = 0; while (n<50){ if (SENSOR_1 > THRESHOLD - 9) { go_right1(sA4,sB4); } else { go_right1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub r_b2() //黒くなるまで右へ2 { int n = 0; while (n<50){ if (SENSOR_1 > THRESHOLD - 9) { go_right2(sA4,sB4); } else { go_right1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub l_b() //黒くなるまで左へ1 { int n = 0; while (n<50){ if (SENSOR_1 > THRESHOLD - 9) { go_left1(sA4,sB4); } else { go_left1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } sub l_b2() //黒くなるまで左へ2 { int n = 0; while (n<50){ if (SENSOR_1 > THRESHOLD - 9) { go_left2(sA4,sB4); } else { go_left1(sA4,sB4);n=n+1; } Wait(STEP); } PlayTone(659,50); } このライントレースでは、5段階または3段階で明るさを評価した。また、真ん中を一番黒くしているので線の右側を走るのと左側を走るプログラムを作った。ライントレースの方法は5段階もしくは3段階にわけた中にカウントを増やすプログラムとカウントをリセットするプログラムを作り、そのライントレースのプログラムで設定したカウント以上になるまでトレースし続けるというものにした。また、プログラムが終わると音が鳴るようにしてある。 sub c_ca() //紙コップをつかむ { OnFwd(OUT_C,Cpower);Wait(1100); Off(OUT_C); } sub c_re() //紙コップを放す { OnFwd(OUT_C,-Cpower);Wait(1100); Off(OUT_C); } **本文 [#mb4a6e33] 最初は枠の内側の右寄りに置いてスタートする。 task main() { SetSensorLight(S1); //端子1に光センサー gogo_b(0,0); //最初の枠から出る gogo_w(0,0); lele(0,0); r_straight1(0,0); //Bまで l_w(); //進路修正 r_straight1(0,0); //Cまで r_w(); r_straight1(0,0); //Fまで l_w(); //進路修正 ↑枠からでた後のトレースは右側を通っていきBのまがり角では黒の上にいる時間が多くなりプログラムが終了する。そのあとに白いところまで出ていきまたトレースを始める。 r_straight2(0,0); r_left(sA3,sB3);//カーブ1 l_w();//車線変更 l_straight4(0,0); PlayTone(523,50); l_right(sA3,sB3);//カーブ2 long t0 = CurrentTick(); while (CurrentTick() - t0 < 10000){ if (SENSOR_1 < THRESHOLD -15) { go_left1(0,0); } else if (SENSOR_1 < THRESHOLD -9) { go_forward(0,0); } else { go_right2(0,0); } Wait(STEP); } PlayTone(880,100); l_straight2(sA2,sB2); Off(OUT_AB);//Rまで Wait(1000); l_w(); //進路修正 l_straight2(0,0); r_w();//Pまで r_b(); ↑カーブは外側のラインをトレースしたかったので1つ目のカーブを曲がったあとに左側に車線変更している。また、Eの角を曲がるためにwhile文で一定の時間はライントレースさせ続けるようにした。 r_w2(); r_b2(); Off(OUT_AB);Wait(300); go_forward(0,0);Wait(500);Off(OUT_AB); c_ca(); //紙コップを取る Off(OUT_AB);Wait(300); go_back(0,0);Wait(450);Off(OUT_AB); go_left2(0,0);Wait(1500); //コースに戻る ↑これは、紙コップを回収するプログラムで、機体を回転させ棒で紙コップをよせてから回収している。 l_straight2(0,0); PlayTone(880,100); l_w3();//Qまで long t1 = CurrentTick(); while (CurrentTick() - t1 < 2000){ if (SENSOR_1 < THRESHOLD -15) { go_left1(0,0); } else if (SENSOR_1 < THRESHOLD -9) { go_forward(0,0); } else { go_right1(0,0); } Wait(STEP); } PlayTone(880,100); l_straight3(0,0); Off(OUT_AB);Wait(1000);//Sまで r_w(); //進路変更 r_straight3(0,0); r_straight4(0,0); ↑途中のwhile文はそこの部分の色の塗り方の問題でうまく反応しなかったため一定の時間トレースするようにしている。また、カーブをトレースするプログラムがうまくいかなかったので直進用に作ったプログラムを入れてみるとうまくいったのでそのまま使っている。 r_w2(); r_b2(); r_w2(); go_right2(0,0);Wait(800); Off(OUT_AB);Wait(300); c_re(); //紙コップを放す Off(OUT_AB);Wait(300); l_b2(); go_forward(0,0);Wait(1200); //コースに戻る go_left2(0,0);Wait(1800); ↑紙コップを放すプログラム。棒を取り付けた影響で紙コップを置いた後決まった方にしか回ることができなかった。 r_straight4(0,0); Off(OUT_AB);Wait(1000);//Sまで l_w(); //進路変更 l_straight3(sA4,sB4); Off(OUT_AB);Wait(1000);//Fまで l_w(); //進路変更 r_straight1(0,0); Off(OUT_AB);Wait(1000);//Cまで gogo_w(0,0); l_straight2(0,0); gogo_w(0,0); go_right2(0,0);Wait(750); //枠の中に入れる go_forward(0,0);Wait(1200); Off(OUT_AB); PlayTone(880,200); //ゴール } ↑最後に枠の中にゴールするまでのプログラム。ここではライントレースをしてゴールするだけなのでこれまでと違ったところはなかったが、1ヶ所安定しないところがあったので速度を遅くした。また、最後に枠の中に入れるところは時間で動かした。 *結果 [#x24738f3] 本番では、電池の消耗でプログラムがうまく動かず最初はダメだったが2回目ではうまく動いてくれた。電池が消耗しても速さを変えることで完璧にする予定だったが直前でうまく調整できなかったのが残念だった。 *感想 [#ld31eb27] 今回の課題ではカーブを曲がるところが難しく自分たちで作ったコースの色の塗り方が雑だったためカーブを上手く曲がれないことがあり苦戦した。もっと丁寧にコースを作るべきだったと後悔した。トレースのプログラム自体を途中で変えたので無駄な作業時間が多くとても時間がかかった。しかし、作業をしているときはそれほど時間を感じず楽しくできたし、達成感も大きかった。次の課題は期間が短くまた忙しい時期ではあるけれど、最後までしっかりやりきりたいと思う。