目次
#contents
*課題2 [#n2cefe5f]
下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。
**ミッション [#fcc071b5]
次のいずれかのコースで黒い線に沿って動き、途中でボールをゴール付近に立てた350mlの空き缶(黄色で表示)に当てるロボットを製作せよ。 
また、ボールはロボットが弧IHKJ上にある時にP地点の空き缶に当てる。
**コース [#j508b7aa]
私は下の第2コースを選んだ。
#ref(2018b/Member/riho/Mission2/2018b-mission2.jpg,80%,コースの通る道順)
矢印の先端にある交差点で1秒一時停止をする必要がある。
*ロボットの説明 [#z2fdfc94]
今回はロボットに光センサ、超音波センサ、ボールを投げるアームをつける必要があった。

写真
#ref(2018b/Member/riho/Mission2/IMG_1046.jpg,40%,ロボットの全体画像)

この写真の説明は、部品ごといかにまとめてある。
**光センサ [#mb6a681e]
光センサは、あまりにも床と近すぎるとうまく測定できないということを先生からアドバイスをいただいたので、床スレスレにならない程度に高さを出した。
**超音波センサ [#w042cfbb]
超音波センサは、床からの距離が高すぎて物体を測定できないということがないように、センサをつける高さを意識した。
**アーム [#u107343d]
アームを閉じてボールを挟んで運び、アームを広げてロボットの機体をぶつけることで、蹴るようにボールを飛ばすものにした。

#ref(2018b/Member/riho/Mission2/IMG_1047.jpg,40%,ロボットがアームを広げている時)

*定義したプログラムの説明 [#e848e9f6]
**ライントレース [#y11dff08]
まず以下のものを定義した。
 #define turn_l1 OnFwd(OUT_B,30);OnRev(OUT_C,30);  //左旋回
 #define turn_r1 OnFwd(OUT_C,30);OnRev(OUT_B,30);  //右旋回
 #define turn_l0 OnFwd(OUT_B,30);Off(OUT_C);  //左折
 #define turn_r0 Off(OUT_B);OnFwd(OUT_C,30);  //右折
 #define go_s OnFwd(OUT_BC,30); //直進
 #define stoop Off(OUT_BC);  //止まる
 #define speed 50  //モータを50%の力で動かす
 #define speed_s 30  //モータを30%の力で動かす

線に沿って走るために、白と黒を認識して進むプログラムを作成した。
「真っ白」「白よりの境界線」「白と黒の境界線」「黒よりの境界線」「真っ黒」の5つに分けて値を光センサで測定すると、下の図のような結果になった。

写真
#ref(2018b/Member/riho/Mission2/IMG_1048.jpg,70%,光センサで測定した値)

測定より、真っ白は32以下、白よりの境界線は32~41、白と黒の境界線は42~47、黒よりの境界線は48~54、真っ黒は55以上だということがわかった。

このロボットは線の左側に沿って進むように作るので、下の図のように、色を測定して黒ければ黒いほど左に、白ければ白いほど右に進まなくてはならない。

写真
#ref(2018b/Member/riho/Mission2/IMG_1049.jpg,70%,光センサで測定した値による進む方向)

よって、測定値を利用してif文を使った以下のようなプログラムを作った。

写真
 if(SENSOR_1>55){
     turn_r1;                            
 }else if(SENSOR_1>48){
     turn_r0;
 }else if(SENSOR_1>42){
     go_s;
 }else if(SENSOR_1>32){
     turn_l0;                                                       
 }else{
     turn_l1;
 }

これは、同じ要領で「白」「白と黒の境界線」「黒」の3つに分けてもロボットは動きますが、細かく分けるとより滑らかに動くので5つに分けたプログラムを作った。

これが線に沿って進む基本的なプログラムである。
上のプログラムを少し改良したものが線に沿って進む基本的なプログラムである。

プログラム
 void tuuzyou()
 {
     SetSensorLight(S1);
     long t0;                                                                   
     t0=CurrentTick(); 
     while(CurrentTick()-t0<90){   
         if(SENSOR_1>55){
             turn_r1;   
             t0=CurrentTick();                         
         }else if(SENSOR_1>48){
             turn_r0;
             t0=CurrentTick();
         }else if(SENSOR_1>42){
             go_s;
             t0=CurrentTick();
         }else if(SENSOR_1>32){
             turn_l0;
             t0=CurrentTick();                                                          
         }else{
             turn_l1;  
         }
     }
 }

このプログラムは「真っ黒」の領域を0.09秒通るとこのプログラムが終了するようになっている。

**交差点を右折するプログラム [#cc0792ce]
ロボットは線の左を沿って走っているので、交差点を右折するには一回「真っ黒」の領域を走らなければならない。上で説明した通常のライントレース用のプログラムでは右折できないので、右折ようのプログラムを作った。

写真
#ref(2018b/Member/riho/Mission2/IMG_1051.jpg,70%,右折するためのセンサの値)

上の図のように、交差点の右の線の奥側(線の左側)に行きたい。そのために交差点から、センサが「黒よりの境界線」の値である48を測定するまで右折をするプログラムを作成した。

プログラム
 void usetu()
 {
     SetSensorLight(S1);
     while(SENSOR_1>48){
         turn_r0
     }
 }

**交差点を直進するプログラム [#q019f618]
交差点で一時停止した後にそのまま直進するプログラム。

プログラム
 void massugu()  //直線の交差点で直進する時
 {
     turn_r1;
     Wait(60);
     go_s;
     Wait(150);
 }

 void massugu2()  //円の弧にある交差点で直進する時
 {
     turn_r1;
     Wait(200);
     go_s;
     Wait(300);
 }


上の交差点を右折するプログラムのように、時間で決めるのではなく、センサで測定した数値になるまで直進するというプログラムも考えたが、以下のようなことが起こり、100%成功する保証はなかったので、ある時間だけ実行するプログラムにした。

写真
#ref(2018b/Member/riho/Mission2/IMG_1054.jpg,70%,直進するときに起こった問題)


**急なカーブでも止まらないプログラム [#x2620670]
通常のライントレース用のプログラムだと、コースにあるDの直角の曲がり角や、FとGの途中にある急カーブでは、「真っ黒」の領域を0.09秒以上通るため、一時停止してしまう。そのため、急カーブに差し掛かる時間をあらかじめ時間を測って置いて、その時間内だけは「真っ黒」の領域を0.09秒以上通っても一時停止しないプログラムを作った。

***Dの直角の曲がり角でも止まらないプログラム [#xabd0d74]

プログラム
 void special()
 {
     SetSensorLight(S1);
     long t1;                                                                       
     t1=CurrentTick()
     while(CurrentTick()-t1<20000){   
         if(SENSOR_1>55){
             turn_r1;                                                    
         }else if(SENSOR_1>48){
             turn_r0;
         }else if(SENSOR_1>42){
             go_s;
         }else if(SENSOR_1>33){
             turn_l0;                                                          
         }else{
             turn_l1;
         }                                                                             
     }
 }

***FとGの途中にある急カーブでも止まらないプログラム [#r13b8e5c]

プログラム
 void special2()
 {
     SetSensorLight(S1);
     long t2;                                                                       
     t2=CurrentTick()
     while(CurrentTick()-t2<7000){   
         if(SENSOR_1>55){
             turn_r1;                                       
         }else if(SENSOR_1>48){
             turn_r0;
         }else if(SENSOR_1>42){
             go_s;
         }else if(SENSOR_1>33){
             turn_l0;                                                          
         }else{
             turn_l1;
         }                                                                          
     }
 }

***簡潔なのプログラム [#pe42b7e5]
上の2つのプログラムは、プログラムを行う時間が違うだけなので、「20000」や「7000」となっている数字を文字に置き換えて、メインプログラムでその文字に時間を入れれば、一つのプログラムにできたと、このレポートを書いていて気づいた。

プログラム
 void special3(t_t)
 {
     SetSensorLight(S1);
     long t1;                                                                       
     t1=CurrentTick()
     while(CurrentTick()-t1<t-t){   
         if(SENSOR_1>55){
             turn_r1;                                                    
         }else if(SENSOR_1>48){
             turn_r0;
         }else if(SENSOR_1>42){
             go_s;
         }else if(SENSOR_1>33){
             turn_l0;                                                          
         }else{
             turn_l1;
         }                                                                             
     }
 }

これでメインプログラムで書くときに、
 special3(20000);



 special3(7000);
と書けば、1つのプログラミングでできたと思う。

**超音波センサ [#w4ba0799]
このミッションでは、空き缶にボールを当てなくてはならなかったので、超音波センサで空き缶を探しす必要があった。そのプログラムが以下である。

プログラム
 const float diameter=5.54;                                                
 const float track=10.35;
 const float pi=3.1415;
 と定義し、

上のプログラムは、ロボット自体が360度回って、超音波センサを用いて近くにある物との距離(プログラムではd_min)を測る。
 void fwdDist(float d)
 {
     long angle;                                                         
     angle= d/(diameter*pi)*360.0;
     RotateMotorEx(OUT_BC,speed_s,angle,0,true,true);                      
 }
 
 void turnAng(long ang)
 {
     long angle;
     angle=track/diameter*ang;
     RotateMotorEx(OUT_BC,speed_s,angle,100,true,true);
 }                                                                     
 
 int searchDirection(long ang)                                         
 
 {
     long angle,tacho_min=0,tacho_corr;
     int d_min;
 
     d_min=300;
 
     angle=(track/diameter)*ang;                                                 
     turnAng(ang/2);
     ResetTachoCount(OUT_BC);                                             
 
     OnFwdSync(OUT_BC,speed_s,-100);
     while(MotorTachoCount(OUT_B)<=angle){
         if(SensorUS(S4)<d_min){
             d_min=SensorUS(S4);
             tacho_min=MotorTachoCount(OUT_B);
         }
     }                                                                           
     OnFwdSyncEx(OUT_BC,speed_s,100,RESET_NONE);
     until(MotorTachoCount(OUT_B)<=tacho_min||SensorUS(S4)<=d_min);             
 
     Wait(14);
     Off(OUT_BC);Wait(500);
     return d_min;
 }
上のプログラムは、メインプログラムで回転する範囲を「360」とすれば、ロボット自体が360度回って、超音波センサを用いて近くにある物との距離(プログラムではd_min)を測る。

写真
#ref(2018b/Member/riho/Mission2/IMG_1053.jpg,70%,超音波センサの仕組み)

d_minは物体を見つけるたびに更新されていき、一番距離の近い物体の方向を向く。これより、空き缶より別のものがロボットの近くにあると、そっちの方向を向いてしまうのでそこに注意することが必要である。

**ボールを蹴るプログラム [#n6ff0b2e]
今回のロボットは、ボールを置いてロボットで押すことでボールをけるようにしたので、ロボットを後退や前進させるてシュートさせた。

プログラム
 void shoot()
 {                                                                              
     OnRev(OUT_BC,50);
     Wait(1400); 
 
     OnFwd(OUT_A,30);
     Wait(250); 
     Off(OUT_A);                          
     OnFwd(OUT_BC,50);
     Wait(1400); 
     OnRev(OUT_A,30);
     Wait(250);
     Off(OUT_A);
     turn_r1;
     Wait(600);
 }

*メインプログラム [#f8a1b15c]
メインプログラムは上の定義したプログラムを組み合わせるなどして完成させた。

交差点では一時停止する必要があった。その仕組みは、通常のライントレース用のプログラムで「真っ黒」の領域を0.09秒以上通る所(これが交差点)を見つけ通常プログラムを終了させ、その下にモータを停止させるプログラム(stoop;)と一秒間続けるプログラム(Wait(1000))を置くことで交差点で1秒間一時停止する。

プログラム
 task main()
 {
     go_s;
     Wait(1000);    
     tuuzyou();
     stoop;                                                
     Wait(1000);
     massugu();
     Wait(1000);
     tuuzyou();
     stoop;
     Wait(1000);
     turn_l1;
     Wait(200);
     tuuzyou();
     massugu2();
     SetSensorLowspeed(S4);
     int d=searchDirection(360);
     if (d>38){
         fwdDist(d-38.0);                                   
     }
     shoot();
     tuuzyou();
     massugu2();
     special2();
     tuuzyou();
     stoop;                                              
     Wait(1000);
     usetu();
     special();
     tuuzyou();
     stoop;
     Wait(1000);
     massugu();
     Wait(1000);
     special();
     tuuzyou();
     stoop;
     Wait(1000);
     massugu();
     Wait(1000);
     tuuzyou();
     massugu();
     Wait(2000);
     stoop;
 }


*最後のまとめ [#a2a66780]
**反省 [#qb43d62d]
・ボールを蹴るプログラムではロボット自体が動くことでボールを蹴るというプログラムにしたので、残りの電池の量や少しの環境の変化で線から外れてしまうこともあり、すごく不安定だった → ロボットは動かないでボールを落とす様なロボットにすればよかった。

・上でも述べたが、急カーブではとまらないプログラムを2つ作るのではなく、数字の部分を文字に置くなどしたら、プログラムを1つにできてスッキリする → 次回からはプログラムを作る際、なるべく同じことを何回も書かない様に、省略できるところはないか考えながら作る。

**感想 [#w05a04ce]
今回のミッションではあまり自分らしさや自己流の工夫ができなかった。ロボットに関してもプログラムに関しても、「注目ポイントはありますか?」と聞かれても正直答えるのが難しい。次回は、ただミッションを達成させるロボットを作るのではなく、どう作れば簡潔か、どうすれば100%絶対成功するロボットやプログラムが作れるかをもっと考えながら作りたい。


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS