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

&ref(2018b/Member/Jerry/Mission2/コース.png,70%,コース);

今回、私が走らせるコースはBコースであり、詳しいコースの内容は以下の通りである。 赤い線がBコースである。

&ref(2018b/Member/Jerry/Mission2/Bコース.jpg,40%,Bコース);

    .蹈椒奪箸鮴喫形X内におき、Lをスタート
    Eを一時停止して直進。
    Iを一時停止して左折。
    Hを直進。
    Kを直進。
    Jを左折。
    Cを一時停止して右折。
    Eを一時停止して直進。
    Gを一時停止して直進。
    長方形X内に入って停止。
    (一時停止の指定がある場所は、1秒間停止すること)
    ボールはロボットが弧IHKJ上にある時にQ地点の空き缶に当てる。
*今回のロボットについて [#d390a7d1]
**光センサ部分 [#qec9c6c5]

&ref(2018b/Member/Jerry/Mission2/光センサ.jpg,25%,光センサ);

光センサと紙が平行になるような位置に光センサを取り付け、光センサの値を正確に測ることができるようにした。また、光センサをタイヤの中点の位置に取り付けると、うまくライントレースすることができなかったので、タイヤの中点よりも右側に光センサを取り付けるようにした。
**超音波センサ部分 [#jbba0b34]

&ref(2018b/Member/Jerry/Mission2/超音波センサ.jpg,25%,超音波センサ);

空き缶との距離を適切に測ることができるように超音波センサの前に他のセンサとの接続コードがこないような位置に超音波センサを取り付けた。また、超音波センサを少し下向きに傾けることで、空き缶を認識しやすいようにした。
**アームを動かすためのモータ [#y0f397c4]

&ref(2018b/Member/Jerry/Mission2/アーム.jpg,25%,アーム);

ボールとモータとの距離を離しすぎると走行中にアームが不安定になりボールを転がしてしまうことがあったので、ボールとの距離がなるべく近づけられるような位置にモータを取り付けた。また、地面と垂直になるようにアームを取り付けることで、バランスを保ちやすくした。

*ロボットを動かすためのプログラム [#o323fe35]
**ライントレース [#rdf914a5]
今回は、「黒と白の境界線をライントレースする」というプログラムを制作した。
実際にコース上で明るさを測定してみると「白」「白と境界線の間」「境界線」「黒と境界線の間」「黒」 という5段階の明るさの値を測定できた。5つの測定できた値は以下のものとなった。

&ref(2018b/Member/Jerry/Mission2/明るさの値.jpg,25%,明るさの値);

明るさの値が5段階存在するので、それぞれの明るさに対応した動きをするために5段階で動きを制御する必要があるので、以下のように動くようなプログラムを作成した。

&ref(2018b/Member/Jerry/Mission2/動き方.jpg,25%,動き方);

    #define go_forward OnFwd(OUT_B,40);OnFwd(OUT_C,40)   //直進
    #define turn_left1 OnFwd(OUT_B,35);OnFwd(OUT_C,-30)  //左旋回
    #define turn_left2 OnFwd(OUT_B,25);OnFwd(OUT_C,-20)  //左折
    #define turn_right1 OnFwd(OUT_C,35);OnFwd(OUT_B,-30) //右旋回
    #define turn_right2 OnFwd(OUT_C,25);OnFwd(OUT_B,-20) //右折

また、黒と白の境界線には「黒線の右側をライントレースする」、「黒線の左側をライントレースする」という2種類の境界線が存在するので、これらのプログラムを分けて考えることにした。
***左側のライントレース [#eb9a7328]
先ほども示したように白と黒の境界線の明るさの値が45なので
     #define THRESHOLD 45 //白と黒の境界線の明るさの値が45である。
と定義して、以下のようなプログラムを作成した。
    void Lfollow_line(long max_t) //max_tにいれた時間分だけラインの左側をライントレースする。
    { 
    long t0=CurrentTick(); //現在の時間を記録する。
    while (CurrentTick()-t0<=max_t) //現在の時間とt0の時間の差がmax_t以下の時、以下のプログラムを実行する。{
        if (SENSOR_4<THRESHOLD-11) {
           if (SENSOR_4<THRESHOLD-11) {
            turn_right1; //明るさの値が34未満の時、turn_right1の動きをする。
        }
    else if (SENSOR_4<THRESHOLD-7){
           }
           else if (SENSOR_4<THRESHOLD-7){
            turn_right2; //明るさの値が34以上38未満の時、turn_right2の動きをする。
        } 
    else if (SENSOR_4<THRESHOLD+7){  
           } 
           else if (SENSOR_4<THRESHOLD+7){  
            go_forward; //明るさの値が38以上52未満の時、go_forwardの動きをする。
        } 
    else if (SENSOR_4<THRESHOLD+11){
           } 
           else if (SENSOR_4<THRESHOLD+11){
            turn_left1; //明るさの値が52以上56未満の時、turn_left1の動きをする。
        } 
    else {
           } 
           else {
            turn_left2; //それ以外の時、turn_left2の動きをする。
         }
           }
    }
このプログラムは下図のように動くようになっている。

&ref(2018b/Member/Jerry/Mission2/左側のライントレース.jpg,25%,左側のライントレース);

***右側のライントレース [#d2668aea]

    void Rfollow_line(long max_t) //max_tにいれた時間分だけラインの右側をライントレースする。
    { 
    long t0=CurrentTick(); //現在の時間を記録する。
    while (CurrentTick()-t0<=max_t) //現在の時間とt0の時間の差がmax_t以下の時、以下のプログラムを実行する。{
        if (SENSOR_4<THRESHOLD-11) {
           if (SENSOR_4<THRESHOLD-11) {
            turn_left1; //明るさの値が34未満の時、turn_left1の動きをする。
        }
    else if (SENSOR_4<THRESHOLD-7){
           }
           else if (SENSOR_4<THRESHOLD-7){
            turn_left2; //明るさの値が34以上38未満の時、turn_left2の動きをする。
        } 
    else if (SENSOR_4<THRESHOLD+7){  
           } 
           else if (SENSOR_4<THRESHOLD+7){  
            go_forward; //明るさの値が38以上52未満の時、go_forwardの動きをする。
        } 
    else if (SENSOR_4<THRESHOLD+11){
           } 
           else if (SENSOR_4<THRESHOLD+11){
            turn_right1; //明るさの値が52以上56未満の時、turn_right1の動きをする。
        } 
    else {
           } 
           else {
            turn_right2; //それ以外の時、turn_right2の動きをする。
         }
           }
    }
このプログラムは下図のように動くようになっている。

&ref(2018b/Member/Jerry/Mission2/右側のライントレース.jpg,25%,右側のライントレース);

**交差点の認識 [#o92a7fcb]
今まで示してきたプログラムだけだと交差点にさしかかっても、そのまま角に沿ってライントレースすることとなってしまうので、交差点を認識するプログラムを作成した。 

&ref(2018b/Member/Jerry/Mission2/交差点の認識.jpg,40%,交差点の認識);

交差点認識の仕組みは、上図に示したようにライントレースの最中にある動作を連続で何秒間か行った場合、ライントレースを終了させるというものである。そのプログラムが以下のものである。
    void follow_intersection(long min_t) //min_tにいれた時間分だけライントレースをする。  
    { 
    long t1=CurrentTick(); //現在の時間を記録する。
    while (CurrentTick()-t1<=min_t) //現在の時間とt1の時間の差がmin_t以下の時、以下のプログラムを実行する。(min_tの時間で交差点を認識する。){
        if (SENSOR_4<THRESHOLD-11) {
           if (SENSOR_4<THRESHOLD-11) {
            Off(OUT_BC);Wait(1000); //明るさの値が34未満の時、B,Cのモータを1秒間停止させる。
        }
         if (SENSOR_4<THRESHOLD-7){
           }
           else if (SENSOR_4<THRESHOLD-7){
            turn_left2; //明るさの値が34以上38未満の時、turn_left2の動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
        }
    else if (SENSOR_4<THRESHOLD+7){ 
           }
           else if (SENSOR_4<THRESHOLD+7){ 
            go_forward; //明るさの値が38以上52未満の時、go_forwardの動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
        }
    else if (SENSOR_4<THRESHOLD+11){
           }
           else if (SENSOR_4<THRESHOLD+11){
            turn_right1; //明るさの値が52以上56未満の時、turn_right1の動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
        }
    else {
           }
           else {
            turn_right2; //それ以外の時、turn_right2の動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
         }
           }
    }

**交差点の横断 [#x64b1f0f]
交差点を認識した後、直進、左折、右折などの動きをする必要があるので、交差点を横断するプログラムを考える。交差点の横断の仕方は主に2種類ある。

&ref(2018b/Member/Jerry/Mission2/交差点の横断.jpg,50%,交差点の横断);

,鮗孫圓垢襪燭瓩離廛蹈哀薀爐楼焚爾里發里任△襦
    #define across OnFwd(OUT_B,40);OnFwd(OUT_C,40);Wait(1000)//1秒間交差点を横断する。
    #define across2 OnFwd(OUT_B,40);OnFwd(OUT_C,40);Wait(400)//0.4秒間交差点を横断する。
    #define across3 OnFwd(OUT_B,40);OnFwd(OUT_C,40);Wait(200)//0.2秒間交差点を横断する。
**空き缶を探すためのプログラム [#n07ded69]
    #define SPEED 50
    #define SPEED_SLOW 30
    const float diameter = 5.45; //タイヤの直径(cm)
    const float track = 10.35;   //タイヤのトレッド幅(cm)
    const float pi = 3.1415;     //円周率

    void turnAng(long ang) // 角度 ang 度の時計回りの旋回する。
    {
    long angle;
    angle = track/diameter*ang;
    RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 100, true, true);   
    }

    int searchDirection(long ang)  // 現在の方向を中心に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_SLOW,-100);// 反時計回りに旋回する。
    while(MotorTachoCount(OUT_B)<=angle){
        if(SensorUS(S2)<d_min){
        d_min=SensorUS(S2);          // 仮の最小値を更新する。
        tacho_min=MotorTachoCount(OUT_B);
        }
         if(SensorUS(S2)<d_min){
         d_min=SensorUS(S2);          // 仮の最小値を更新する。
         tacho_min=MotorTachoCount(OUT_B);
         }
    }
    OnFwdSyncEx(OUT_BC,SPEED_SLOW,100,RESET_NONE);
    until(MotorTachoCount(OUT_B)<=tacho_min||SensorUS(S2)<=d_min);
    Wait(14);  //微調整
    Off(OUT_BC);Wait(500);
    return d_min;
    }
上のプログラムは下図のような仕組みで制御されている。

&ref(2018b/Member/Jerry/Mission2/空き缶を認識する仕組み.jpg,40%,空き缶を認識する仕組み);


今回はロボットを360度回転させ,空き缶の位置を探す。
    int d=searchDirection(360);  //現在の方向を中心に360度回転し、最小値の方向を向く。

**空き缶にボールをあてるためのプログラム [#yc171ea9]
    #define throw
    OnFwd(OUT_A,30);Wait(700);Off(OUT_A);Wait(2000); //アームを動かし、ボールを空き缶に当てる。
    OnFwd(OUT_A,-35);Wait(700);Off(OUT_A);           //アームをもとの位置に戻す。
**効果音 [#z851aaa6]
ライントレースマシンを作成している時に、交差点の認識がうまく行えているかを確認するために、音を用いた。この音のおかげで作業効率が大幅に上がった。
     #define MI 659 //ミの音
     SetSensorSound(S1);

     void follow_intersection(long min_t) //min_tにいれた時間分だけライントレースをする。 
    {  
    long t1=CurrentTick(); //現在の時間を記録する。
    while (CurrentTick()-t1<=min_t) //現在の時間とt1の時間の差がmin_t以下の時、以下のプログラムを実行する。{
        if (SENSOR_4<THRESHOLD-11) {
           if (SENSOR_4<THRESHOLD-11) {
            Off(OUT_BC);Wait(1000); //明るさの値が34未満の時、B,Cのモータを1秒間停止させる。
        }
         if (SENSOR_4<THRESHOLD-7){
           }
           else if (SENSOR_4<THRESHOLD-7){
            turn_left2; //明るさの値が34以上38未満の時、turn_left2の動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
        }
    else if (SENSOR_4<THRESHOLD+7){ 
           }
           else if (SENSOR_4<THRESHOLD+7){ 
            go_forward; //明るさの値が38以上52未満の時、go_forwardの動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
        }
    else if (SENSOR_4<THRESHOLD+11){
           }
           else if (SENSOR_4<THRESHOLD+11){
            turn_right1; //明るさの値が52以上56未満の時、turn_right1の動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
        }
    else {
           }
           else {
            turn_right2; //それ以外の時、turn_right2の動きをする。
            t1=CurrentTick(); //現在の時間を記録する。
         }
           }
    }
    PlayTone(MI,900);Wait(1000); //ミの音を0.9秒間出す。
 }
*全体のプログラム [#r8027741]
これまでに記述してきたプログラムを組み合わせて、全体のプログラムを作成する。
 task main()
 {
    SetSensorLight(S4);   //光センサを4に接続する。
    SetSensorLowspeed(S2);//超音波センサを2に接続する。
    Wait(3000);//スタートボタンを押してからすぐにロボットが動くのを防ぐために、3秒間ロボットを停止させる。
    across2;//0.4秒間交差点を横断する。
    Lfollow_line(2500);//2.5秒間ラインの左側をライントレースする。 
    follow_intersection(400);//0.4秒で交差点を認識する。
    across2;//0.4秒間交差点を横断する。
    Lfollow_line(950);//0.95秒間ラインの左側をライントレースする。 
    Lfollow_line(400);//0.4秒間ラインの左側をライントレースする。 
    follow_intersection(400);//0.4秒で交差点を認識する。
    Rfollow_line(8000);//8秒間ラインの右側をライントレースする。 
    int d=searchDirection(360);//現在の方向を中心に360度回転し、最小値(空き缶)の方向を向く。
    throw; //ボールを投げる。
    Lfollow_line(6000);//6秒間ラインの左側をライントレースする。 
    follow_intersection(400);//0.4秒で交差点を認識する。
    across3;//微調整のため、0.2秒間前進させる。
    across3;//微調整のため、0.2秒間前進させる。
    Lfollow_line(8500);//8.5秒間ラインの左側をライントレースする。 
    follow_intersection(400);//0.4秒で交差点を認識する。
    turn_left2;Wait(1000);//交差点を左折する。
    Rfollow_line(26000);//26秒間ラインの右側をライントレースする。 
    follow_intersection(400);//0.4秒で交差点を認識する。
    across2;//微調整のため、0.4秒間前進させる。
    across2;//微調整のため、0.4秒間前進させる。
    across2;//微調整のため、0.4秒間前進させる。
    Rfollow_line(26500);//26.5秒間ラインの右側をライントレースする。 
    follow_intersection(400);//0.4秒で交差点を認識する。
    across2;//微調整のため、0.4秒間前進させる。
    across2;//0.4秒間交差点を横断する。
    Rfollow_line(1500);//1.5秒間ラインの右側をライントレースする。 
    across;//ゴールに向かって前進する。
 }
*まとめ [#bc366f6e]
今回の課題では、交差点の認識がうまく行えるかがコースを完走するための鍵となった。ロボットの製作過程で電池の残量によってロボットの進み方が変わり、それにより交差点の認識に誤差が生じるという問題が発生したが、2人で話し合いながらより良いプログラム作りに取り組むことができたので良かった。ただ、超音波センサを扱うにあたって、同じプログラムを使っても空き缶を認識できる時とできない時が存在してしまい、この問題を根本的に解決することができなかったので、超音波センサのプログラミングについてもう一度復習をして、次回の課題では超音波センサをうまく活用できるようにしていきたいと思う。

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