#author("2020-01-13T19:33:24+09:00","jh1dmz","jh1dmz")
#author("2020-02-02T21:10:43+09:00","jh1dmz","jh1dmz")
[[2019b/Member]]
*課題2 [#u2219328]
下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。
**コース [#je0f2f1f]
#ref(2019b/Member/jh1dmz/Mission2/2019b-mission2.png,640px)
このコース上を以下のようにライントレースする。
+A地点から出発
+J
+H (直進)
+I (ボール or キューボイドをつかんでUターン)
+H (右折)
+G (一時停止の後、直進)
+D (右折)
+E, F 通過
+G (一時停止の後、直進)
+C (一時停止の後、左折)
+B (一時停止)
+A地点に入る(ゴール)

*ロボットについて [#f5ff549a]
#ref(2019b/Member/jh1dmz/Mission2/20191220183110_p.jpg,640px)
今回のロボットも前回と同様に最初に組み立てたロボットを基本に改造していった。
#ref(2019b/Member/jh1dmz/Mission2/20191220183137_p.jpg,320px)
#ref(2019b/Member/jh1dmz/Mission2/20191220183140_p.jpg,320px)
光センサーをタイヤの軸に少し近づくようにした。これによりライントレースをしやすくした。
**主な改造点 [#zf4b862b]
#ref(2019b/Member/jh1dmz/Mission2/20191220183115_p.jpg,320px)
#ref(2019b/Member/jh1dmz/Mission2/20191220183119_p.jpg,320px)
#ref(2019b/Member/jh1dmz/Mission2/20191220183125_p.jpg,320px)
主な改造点である、ボールを認識する、ボールを移動させる仕組みである。
ボールの認識には超音波センサーを用いた。センサーをロボット上部に下向きに取り付け、距離が一定値以下になったときにモーターを駆動させるようにした。

次に、ボールを移動させる仕組みであるが、モーターに四角い囲いを取り付けボールを掴むまでは囲いを上げておき、ボールを認識したところで囲いを下ろすようにした。残りの工程はそのままボールを引きずるように移動する。

*プログラムについて [#ea4a81a1]

**定義、関数 [#iaa5c1a2]
 #define SP 50
速度を50と定義した。

 void go(int g)
 { 
 OnFwd(OUT_BC,SP);
 Wait(g);
 }

前進する関数である。任意の値を指定することで進む距離の調整ができる。

 void follow_line(int n)
 {
     int t;
     t=0;
     while(t<n){
         if(SENSOR_3<45){
             RotateMotorEx(OUT_BC,SP,5.0,50,true,true);
             t=t+1;
         }else if(SENSOR_3<50){
             Off(OUT_B);
             OnFwd(OUT_C,SP);
             t=0;
         }else if(SENSOR_3<65){
             OnFwd(OUT_BC,SP);
             Wait(10);
             Off(OUT_BC);
             t=0;
         }else if(SENSOR_3<75){
             OnFwd(OUT_B,SP);
             Off(OUT_C);
             t=0;
         }else if(SENSOR_3>=75){
             RotateMotorEx(OUT_BC,SP,2.0,-50,true,true);
             t=0;
         }
     }
     Wait(1000);
 }

ライントレースをして交差点と認識したところで止まる関数である。この関数は黒が連続した回数で交差点を認識するようになっている。この回数を指定できるようにしてあるので様々な状況に対応できるものにした。黒、灰黒、灰色、白灰、白の5段階で分けた。
ライントレースをして交差点と認識したところで止まる関数である。この関数は黒が連続した回数で交差点を認識するようになっている。この回数指定がnになっており、tが黒が連続した回数になる。この値tがn以下になるような条件でwhileループを行うので引数を変えることで交差点の認識感度を調整できるようになる。このため様々な状況に対応できるものになっている。黒、灰黒、灰色、白灰、白の5段階で分けた。

 void follow_line2()//ライントレースのみ
 {
         if(SENSOR_3<50){
             RotateMotorEx(OUT_BC,SP,5.0,70,true,true);
         }else if(SENSOR_3<60){
             Off(OUT_B);
             OnFwd(OUT_C,SP);
         }else if(SENSOR_3<65){
             OnFwd(OUT_BC,SP);
             Wait(10);
             Off(OUT_BC);
         }else if(SENSOR_3<75){
             OnFwd(OUT_B,SP);
             Off(OUT_C);
         }else if(SENSOR_3>=75){
             RotateMotorEx(OUT_BC,SP,2.0,-50,true,true);
         }
 }

この関数はライントレースをするだけのものである。回数などは数えず、主に時間指定してひたすらライントレースをする際に用いた。色の認識は先程と同じ5段階になっている。

 float GetAngle(float d)//角度dからタイヤの回転数を計算する関数
 {
  const float diameter=5.45;
  const float pi=3.1415;
  const float distance=12.00;//タイヤ間の距離
  float ang = (distance*d)/diameter;
  return ang;
 }

今まで何度も使ってきた関数である。角度を指定してタイヤの回転数を計算するもので、RotateMotorExとともにも用い指定した角度にロボットが向くようにする。

**task main [#ja636622]

 task main()
 {
 SetSensorLowspeed(S4);
 SetSensorLight(S3);
 long d,s,first_time,hturn;
 first_time = CurrentTick();
 while(true){
     if(CurrentTick()-first_time<17000){
         follow_line2();
     }else{
         break;
     }
 }

まずはセンサーをすべて認識し、今後使う変数も含めてlongにした。
そこから17秒間交差点の認識をせずにひたすらライントレースをするようにした。
この動作をすることで最初の急カーブを交差点と誤認識することを防止した。

 while(true){
     d=SensorUS(S4);
     if(d<9){
         Off(OUT_BC);
         Wait(300);
         OnRev(OUT_A,60);
         Wait(300);
         Off(OUT_A);
         int tenkan = GetAngle(200);
         RotateMotorEx(OUT_BC,SP,tenkan,100,true,true);
         break;
     }else{
         if(SENSOR_3<50){
             RotateMotorEx(OUT_BC,SP,5.0,70,true,true);
         }else if(SENSOR_3<60){
             Off(OUT_B);
             OnFwd(OUT_C,70);
         }else if(SENSOR_3<65){
             OnFwd(OUT_BC,100);
             Wait(10);
             Off(OUT_BC);
         }else if(SENSOR_3<75){
             OnFwd(OUT_B,70);
             Off(OUT_C);
         }else if(SENSOR_3>=75){
             RotateMotorEx(OUT_BC,SP,2.0,-50,true,true);
         }
     }
 }

これが、最初のカーブを過ぎてボールを取るまでの動作である。一回超音波センサーで距離を出し、値が9以上であった場合はボールはその下に存在しないためライントレースを行う。これをwhileループで繰り返し、9以下になった時点で囲いを下ろして転回する。最後にbreakでwhileループを脱する。

このプログラムでは転回の角度を180度以上に指定しているが、これは進行方向左側に黒線が必ず来るようにするためにあえて余分に回すようにしているためである。ここからラインまで修正しつつ次の工程までトレースする。
また、ライントレースの部分で先程定義したfollow_line2を使わなかったのはこの状況に合わせてなるべく高速で行うために速度の数値を変更したためである。

 hturn=CurrentTick();
 while(true){
     if(CurrentTick()-hturn<4500){
         follow_line2();
     }else{
         break;
     }
 }

ここまででHを曲がる。時間指定をして確実にHを曲がれるようにした。

 follow_line(7);
 RotateMotorEx(OUT_BC,SP,20,-50,true,true);//修正
 go(160);//G通過
 follow_line(6);
 RotateMotorEx(OUT_BC,SP,20,-50,true,true);//修正
 int angleg=GetAngle(90);
 RotateMotorEx(OUT_BC,SP,angleg,50,true,true);//D右折
 follow_line(8);
 RotateMotorEx(OUT_BC,SP,20,-50,true,true);//修正
 RotateMotorEx(OUT_BC,SP,angleg,50,true,true);//E右折
 follow_line(8);
 RotateMotorEx(OUT_BC,SP,20,-50,true,true);//修正
 RotateMotorEx(OUT_BC,SP,angleg,50,true,true);//F右折
 follow_line(8);
 RotateMotorEx(OUT_BC,SP,20,-50,true,true);//修正
 go(150);//G直進
 follow_line(8);
 int anglec=GetAngle(60);
 RotateMotorEx(OUT_BC,SP,anglec,-50,true,true);//左折
 follow_line(6);
 RotateMotorEx(OUT_BC,SP,20,-50,true,true);//修正
 go(500);
 }

これでHを過ぎてライントレースを再開し、Gを通過からゴールまでである。
すべて交差点を認識して一時停止、交差点を認識すると向きは右になっているので向きをまっすぐに修正、RotateMotorExで90度の右左折を行い、ライントレースを再開するといった手順になっている。
最後は交差点の認識後ゴールまで直進する。

*感想考察 [#ff28ef4f]
今回は状況合わせてロボットが動いてくれるため、前回ほど難しくはなかった印象である。最終的にしっかりとゴールできるプログラムに出来たので良かったと思う。しかし、時々失敗することがある。これは証明の位置関係や、電池残量に影響しているのではないかと思っている。

この課題をクリアする上で特に難しかったのはHを曲がるところである。普通にfollow_lineで進もうと思うと交差点と認識したりしなかったりで安定しなかった。そのために時間指定をすることでクリアできるようにした。その他はかなり順調に出来たためとてもスムーズに課題ができたと思う。

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS