[[2017b/Member]]

* 課題2 下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。 [#m2e984f9]
** コースとミッション  [#n33fc0ec]

#ref(2017b/Member/takeshi/Mission2/課題2のコース.png,640x480,課題2のコース)
私は第2コースを選んだ。第2コースのミッションは以下の通り

 1.Dをスタート
 2.Cを直進
 3.Bを左折
 4.Pを左折(一時停止)
 5.Qを直進
 6.Rを左折
 7.Fを左折
 8.Sを直進(一時停止)
 9.Y地点の紙コップを取得してコースに戻る
 10.Sを直進(一時停止)
 11.Qを左折(一時停止)
 12.Rを直進
 13.X地点に紙コップを置いてコースに戻る
 14.Pを左折
 15.B を左折(一時停止)
 16.A地点へ(ゴール)

* ロボットの全体図 [#bcfbca0a]
#ref(2017b/Member/takeshi/Mission2/s_s_2.JPG,480x640,ロボットの全体図)
光センサーはなるべく地面に近づけるようにして直角に取り付けた。
#ref(2017b/Member/takeshi/Mission2/s_IMG_4823.JPG,480x640,ロボットのアーム)
ロボットの前方に紙コップを取るためのアームを取り付けた。モーターに棒を通しそれにブロックで作った枠を取り付けてアームを作った。モーターを本体の右側に取り付けたので右側が重くなり、右タイヤを動かすためのモーターの出力を大きくしなければならなくなった。
#ref(2017b/Member/takeshi/Mission2/紙コップを取る.png,640x480,紙コップを取る)
アームが紙コップの位置に来るようにロボットを移動させてアームを下ろす。
一発勝負なので枠は大きな正方形にした。
#ref(2017b/Member/takeshi/Mission2/s_IMG_4822.JPG,480x640,ロボットの全体図)
相方がロボットの左側にタッチセンサーを利用したスタートボタンを取り付けた。取り付ける前に比べてスタートが楽になった。

* プログラム [#i1105a68]
** 基本的な動作を行うためのプログラム [#o1e7053c]

まず、直進する、緩やかに曲がる、旋回する、右左折の前に位置を調節するためのプログラムをマクロ関数で定義した。 
 
 #define go_forward OnFwd(OUT_A,30);OnFwd(OUT_B,30);//直進
 #define turn_right1 OnFwd(OUT_A,0);OnFwd(OUT_B,55);//右に緩やかに曲がる
 #define turn_left1 OnFwd(OUT_A,50);OnFwd(OUT_B,0);//左に緩やかに曲がる
 #define turn_right2 OnFwd(OUT_A,-50);OnFwd(OUT_B,55);//右旋回
 #define turn_left2 OnFwd(OUT_A,50);OnFwd(OUT_B,-55);//左旋回
 #define before_turn  OnFwd(OUT_AB,20);Wait(1000);//右左折の前に位置を調節

そして、紙コップを取るためのプログラムをサブ関数で定義した。モーターを一定の角度回すプログラムを利用した。

 sub arm_down()//アームを下げる
 {
     ResetTachoCount(OUT_C);
     RotateMotor(OUT_C,10,150);//モーターを150度前に回す
     Wait(1000);
     Off(OUT_C);
 }

 sub arm_up()//アームを上げる
 {   
     ResetTachoCount(OUT_C);
     RotateMotor(OUT_C,-10,150);モーターを150度後ろに回す
     Wait(1000);
     Off(OUT_C);
 }

** 境界線上を走り、交差点を感知するためのプログラム [#i3ed44b7]

境界線の上を走り続けるには、境界線の上ならば直進、そうでなければ、右か左にずれて常に境界線の上に乗るように進めば良い。

#ref(2017b/Member/takeshi/Mission2/境界線の説明2.png,640x480,境界線の説明)

私はコース2を選択したので、画像のように黒い線の左側の境界線の上を走らせた。そのためには、境界線上なら直進、白ならば右へ、黒ならば左へ動くプログラムを作る。そのようにする理由は、交差点を感知する必要があったからである。

#ref(2017b/Member/takeshi/Mission2/交差点の感知.png,640x480,交差点の感知)

交差点を感知するためには黒をある一定の時間以上連続して感知する時間を計るためのプログラムを作る。画像のように、光センサーが交差点にさしかかれば光センサーは黒を感知し、ロボットは左に曲がろうとする。交差点でなければ、白くなってゆくが、交差点ならば黒が長く続くので交差点であることが分かる。

上記のプログラムを組み合わせた物がこれである。
 
 #define threshold 50//境界線の光の強さ
 
 sub follow_line()//境界線上を進む
 {
    SetSensorLight(S1);//光センサーの準備
    long t0 = CurrentTick();//タイマーをセット
    while (CurrentTick()-t0 < 80)//タイマーセット後の経過時間が0.8秒未満という条件
  {  if (SENSOR_1 < threshold -13) {
    turn_left2; }//黒ければ左旋回
    else if (SENSOR_1 < threshold -7) {
    turn_left1;t0=CurrentTick() }//少し黒ければ左に緩やかに曲がり、タイマーをリセット
    else if (SENSOR_1 < threshold){
    go_forward;t0=CurrentTick() }//境界線上ならば直進し、タイマーをリセット
    else if (SENSOR_1 < threshold +7){
    turn_right1;t0=CurrentTick() }//少し白ければ右に緩やかに曲がり、タイマーをリセット
    else { 
    turn_right2;t0=CurrentTick() }//白ければ右旋回し、タイマーをリセット
  }
 Off(OUT_AB);
 }

境界線の光の強さをマクロ関数で定義し、境界線上を進むプログラムをサブ関数で定義した。
タイマーの部分が重要である。先ほど述べた「ある一定の時間」は0.8秒である。黒を0.8秒以上連続して感知すればそこは交差点ということになる。黒を0.8秒以上連続して感知すると、whileの条件を外れてモーターはストップし、このプログラムは終了する。境界線や白を感知した時は、プログラムが終了しないように、タイマーをリセットする。

*** ヘアピンカーブ問題 [#i44d0a7a]

このコースは、EF間にヘアピンカーブが存在する。EF間において先ほどの「境界線上を進む」プログラムを実行するとヘアピンカーブを交差点だと感知してしまい、プログラムが終了してしまうことがわかった。そこで、EF間に限っては黒を連続して0.8秒以上感知しても終了しないプログラムを新たに作った。

 sub follow_line2()//黒を0.8秒以上連続して感知しても無視して境界線上を進む
 {
    SetSensorLight(S1);
    long t0 = CurrentTick();
    while(CurrentTick()-t0 < 10000)//タイマーセット後の経過時間が10秒未満という条件
   { if (SENSOR_1 < threshold -13) {
    turn_left2; }
    else if (SENSOR_1 < threshold -7) {
    turn_left1; }
    else if (SENSOR_1 < threshold){
    go_forward;}
    else if (SENSOR_1 < threshold +7){
    turn_right1;}
    else { 
    turn_right2;}
   }
 }

先ほどの「境界線上を進む」プログラムを改編して作った。EF間を移動するのにかかる時間が約12秒、最後のヘアピンカーブが終わってからFまでを移動するのにかかる時間が約2秒だったので、差し引いて10秒間は、黒を0.8秒以上連続して感知しても無視出来るようにした。

#ref(2017b/Member/takeshi/Mission2/ヘアピンカーブ.png,640x480,ヘアピンカーブ) 
*** 交差点を感知した後、無視して直進するための緩衝材となるプログラム [#rb233be4]

#ref(2017b/Member/takeshi/Mission2/境界線上に復帰.png,640x480,交差点を無視して直進)

交差点を感知するとロボットは停止するが、直進させようとして、そのまま続けて「境界線上を進む」プログラムを実行させると、黒の上からスタートするので、また停止してしまったり、左に曲がってしまう。
そのため、停止した後少しだけ前に進ませる単純なプログラムをマクロ関数で定義した。

 #define on_line OnFwd(OUT_B,20);OnFwd(OUT_A,15);Wait(1500);Off(OUT_AB);

** ミッションを遂行するためのプログラム [#o2a2663b]

これまでに示したプログラムを組み合わせて課題2のミッションを遂行するためのプログラムを作った。

 task main()
 {
    SetSensorTouch(S4);
    while(SENSOR_4 == 0){}//ボタンを押すとwhileの条件を抜けてスタート
    follow_line();
    on_line;//Cを直進
    follow_line();
    PlaySound(SOUND_LOW_BEEP);//一時停止
    before_turn; 
    turn_left2;//Bを左折
    Wait(800);
    follow_line();
    before_turn; 
    turn_left2;//Pを左折
    Wait(600);
    follow_line();
    before_turn;
    turn_right2;//Qを直進
    Wait(400);
    follow_line();
    before_turn;
    turn_left2;//Rを左折
    Wait(600);
    follow_line();
    before_turn;
    turn_left2;//Eを左折
    Wait(800);
    follow_line2();//黒を0.8秒以上連続して感知しても無視して境界線上を進む
    follow_line();
    before_turn;
    turn_left2;//Fを左折
    Wait(800);
    follow_line();
    PlaySound(SOUND_LOW_BEEP);//一時停止
    on_line;//Sを直進
    turn_right2;
    Wait(300);
    Off(OUT_AB);
    arm_down();//アームを下ろす
    turn_left2;
    Wait(300);
    Off(OUT_AB);
    follow_line();
    PlaySound(SOUND_LOW_BEEP);//一時停止
    on_line;//Sを直進
    follow_line();
    PlaySound(SOUND_LOW_BEEP);//一時停止
    before_turn;
    turn_left2;//Qを左折
    Wait(600);
    follow_line();
    on_line;//Rを直進
    turn_right2;
    Wait(1100);
    Off(OUT_AB);
    arm_up();//アームを上げる
    turn_left2;
    Wait(1100);
    Off(OUT_AB);
    follow_line();
    before_turn;
    turn_left2;//Pを左折
    Wait(600);
    follow_line();
    PlaySound(SOUND_LOW_BEEP);//一時停止
    before_turn;
    turn_left2;//Bを左折
    Wait(800);
    follow_line();
    on_line;    
    go_forward;
    Wait(2000);
    PlaySound(SOUND_UP);//Aに到着
 }

スタートボタンを押すとプログラムの実行が始まるようにした。 
一時停止しなければならないところと、ゴールしたときはブザーが鳴るようにした。

* 感想 [#da36f175]

課題1に比べると、ロボット自身が勝手に境界線上を進んでくれることもあって調整自体は楽だった。しかし、ifやwhileなどの論理記号を理解して組み立てて行くのが難しかった。コースを作ったときに黒塗りのムラがあり、たまに交差点を感知しないことがあり、大変だった。発表の時もうまくいかなくて残念だった。

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