*ライントレースをしながらゴールまで移動するロボット [#a6565059]
#contents
**1 ロボット [#n8016b9d]
***ロボット全体 [#ub8431c5]
&ref(2017b/Member/smith/Mission2/kadai2-2.jpg,30%,ロボットの前部。タイヤを前輪2輪のみにし、光センサを左タイヤの横に取り付けた。);
&ref(2017b/Member/smith/Mission2/kadai2-3.jpg,30%,ロボットの右部。紙コップをつかむ機構の歯車をうまく回転させるのに苦労した。);

・今回作ったロボットは、掲載ガイドにある2つのモータで4輪を動かすものをベースにそれに光センサと紙コップをつかむ機構を取り付けたものを作成した。左タイヤにモータAを、右タイヤにモータCを割当てている。本体上部のギアは、紙コップをつかむ機構を動かすためのものである。とても空転しやすく、頑丈に固定するため本体上部は多くのブロックを取り付けている。光センサは左タイヤの横につけたが、それが原因で紙コップが置かれている円の内部を本体が通ることになり、紙コップの挙動に悩まされた。また、今回自分が担当したのはルート2であり、自分が想定した機動では右折が必要でなかったため交差点を右折するプログラムは作成しなかった。

***タイヤの問題と解決 [#f6f6032a]
&ref(2017b/Member/smith/Mission2/kadai2-5.jpg,30%,ロボットの裏側。後部の摩擦を減らすためにもとにあった2輪の後輪の中央あたりに黒い半球状の部品をつけて対策した。);

・ガイドのロボットのままだとE〜F間のS字カーブが曲がり切れなかったので、上図のようにタイヤを後輪を外して前輪のみの2輪に、光センサを左のタイヤのすぐそばにつけて小回りが利きやすくし、この問題を解決しようとした。しかし、後輪を外したままだと本体の後部が地面に擦れて動きにくくなるので、上図のように黒い半球状の摩擦を減らす部品をつけ、一連の問題を解決した。

***紙コップをつかむ機構 [#na4eb7a4]
&ref(2017b/Member/smith/Mission2/kadai2-6.jpg,30%,紙コップをつかんだ状態);
&ref(2017b/Member/smith/Mission2/kadai2-7.jpg,30%,紙コップをつかむ動作を図にしたもの);

・紙コップをつかむ機構は上図一番右のように、紙コップのすぐ後ろに本体がたどり着く前まで本体後部にあり、紙コップをつかむときだけ前に動くようになっている。この機構にはモータBを割り当てていて、Bを前進で紙コップをつかみ、後進で紙コップをはなす。本体の説明で書いた通り本体が円の内部を通る仕様のため、紙コップを置くときに少し奥に置かないと本体が通りすぎるときに紙コップに当たり円に収まらない場合があったのでその調整に、またこの機構が結構重く、その分モータと機構を回転させるギアが空転しやすかったのでその2つを固く固定するのに苦戦した。

**2 プログラム [#v88f3c69]
・今回の課題は、最初の課題よりもより複雑になり、その分プログラムの量も大きくなった。
***基礎部分 [#j07930c0]

 #define Threshold 40 //センサの読み取れる範囲の中央値
 #define Hp 7 //パワー大
 #define Mp 1 //パワー中
 #define Lp 0 //パワー小
 #define Cross_time 15 //交差点を横切る時間
 #define Set_power_h SetPower(OUT_AC,Hp); //左右のパワー大
 #define Set_power_m SetPower(OUT_AC,Mp); //左右のパワー中
 #define Set_power_l SetPower(OUT_AC,Lp); //左右のパワー小
 #define Go_forward Set_power_h; OnFwd(OUT_AC); //パワー大で前進
 #define Back Set_power_h; OnRev(OUT_AC); //パワー大で後進
 #define Turn_right_l Set_power_m; OnFwd(OUT_A); Off(OUT_C); //パワー中で右折
 #define Turn_right_h Set_power_l; OnFwd(OUT_A); OnRev(OUT_C); //パワー小で右旋回
 #define Turn_left_l Set_power_m; Off(OUT_A); OnFwd(OUT_C); //パワー中で左折
 #define Turn_left_h Set_power_l; OnRev(OUT_A); OnFwd(OUT_C); //パワー小で左旋回
 #define Break Off(OUT_AC); Wait(100); //小休憩
 #define Cross Set_power_h; OnFwd(OUT_AC); Wait(Cross_time); //パワー大での交差点の横断
 #define Step 1 //ラインの検知間隔
 #define Max 5 //交差点の判定するときの本体が左折する時間
 #define N2_time 200 //サブルーチンN2の動作する時間
 #define S_time 1000 //サブルーチンSの動作する時間
・この部分は、ここから下のサブルーチン・メインプログラムに使用する光センサの値の範囲やモータのパワーの大きさ、センサの検知間隔などを設定している。

・光の範囲の基準値は40にして、そこから一定値足したり引いたりして範囲を調整している。

・光の明るさによる本体の動きは5パターンであり、直進の場合はモータのパワーを7に、右・左折の場合はモータのパワーを1に、右・左旋回の場合はモータのパワーを0にしている。また、紙コップを置いた後線上に戻るために後進するときのモータのパワーも7である。

・光センサの検知する間隔は0.01秒ごとにしている。
***交差点横断のサブルーチン [#s42b216f]

 sub C()
 {
     SetSensor(SENSOR_2, SENSOR_LIGHT); //センサの定義
     int Online=0; //左旋回のカウント
     int Cross_count=0; //交差点を通過した回数
 
     while (Cross_count < 1) { //交差点を通過するまで
 
         while (Online < Max) { //左旋回を5回連続するまで
             if (SENSOR_2 < Threshold - 5) { //センサの値が35未満の時左旋回、音を鳴らして Onlineのカウントを1足す
                 Turn_left_h;
                 PlayTone(523,1);
                 Online++;
             } else {
                 if (SENSOR_2 < Threshold - 2) { //センサの値が35以上、38未満の時左折
                     Turn_left_l;
                 } else if (SENSOR_2 < Threshold + 2) { //センサの値が38以上、42未満の時直進
                     Go_forward;
                 } else if (SENSOR_2 < Threshold + 5) { //センサの値が42以上、45未満の時右折
                     Turn_right_l;
                 } else { //センサの値が45以上の時、右旋回
                     Turn_right_h;
                 }
                 Online=0; //左旋回以外の時、Onlineの値をリセット
             }
         Wait(Step); //0.01秒ごとに線を検知
         }
     Break; //小休憩
     Turn_right_h; //0.3秒間右旋回
     Wait(30);
     Cross; //交差点を横断
     Online=0; //Onlineの値をリセット
     Cross_count++; //Cross_countを1足してこのルーチンを終了、次のルーチンへ
     }
 }
・交差点を横断するときのサブルーチン。光センサが〜34では左旋回、35〜37は左折、38〜41では直進、42〜45では右折、46〜では右旋回するようになっている。

・交差点横断は、このサブルーチン内で左旋回を0.05秒間連続で検知した場合にするようになっている。「Online」は左旋回をした回数をカウントし、それ以外の行動をしたときはこの値をリセットしている。

・「Online」の値が5になるとライントレースのループから外れ、1秒間止まった後に交差点を横断して「Online」をリセットし、交差点を通過した回数をカウントする「Cross_count」に1を足してこのサブルーチンのループから外れる。

***交差点左折のサブルーチン�� [#h98b52a3]

 sub N1()
 {
    SetSensor(SENSOR_2, SENSOR_LIGHT); //センサの定義
    int Online=0; //左旋回のカウント
    int Cross_count=0; //交差点を通過した回数
 
    while (Cross_count < 1) { //交差点を通過するまで
 
        while (Online < Max) { //左旋回を5回連続するまで
            if (SENSOR_2 < Threshold - 5) { //左旋回(範囲は交差点横断のサブルーチンと同じ、以下同)、音を鳴らしOnlineのカウントを1足す
                Turn_left_h;
                PlayTone(523,1);
                Online++;
            } else {
                if (SENSOR_2 < Threshold - 2) { //左折
                    Turn_left_l;
                } else if (SENSOR_2 < Threshold + 2) { //直進
                    Go_forward;
                } else if (SENSOR_2 < Threshold + 5) { //右折
                    Turn_right_l;
                } else { //右旋回
                    Turn_right_h;
                }
                Online=0; //左旋回以外の時、Onlineの値をリセット
            }
        Wait(Step); //0.01秒ごとに線を検知
        }
    Break; //小休憩
    Cross_count++; //Cross_countを1足してこのルーチンを終了、次のルーチンへ
    }
 }
・交差点を左折するときのサブルーチン。ライントレースのプログラムは横断の場合と同じだが、ライントレースのループを外れた後そのまま「Cross_count」に1を足してサブルーチンN2に進む。

***交差点左折のサブルーチン�� [#x5f2f3af]

 sub N2()
 {
    SetSensor(SENSOR_2, SENSOR_LIGHT); //センサを定義
    ClearTimer(0); //タイマをリセット
 
 
    while (FastTimer(0) < N2_time) { //タイマが2秒になるまで
        if (SENSOR_2 < Threshold - 5) { //左旋回
            Turn_left_h;
        } else if (SENSOR_2 < Threshold - 2) { //左折
            Turn_left_l;
        } else if (SENSOR_2 < Threshold + 2) { //直進
            Go_forward;
        } else if (SENSOR_2 < Threshold + 5) { //右折
            Turn_right_l;
        } else { //右旋回
            Turn_right_h;
        }
    }
 }
・サブルーチンN1だけで実行すると、交差点左折直後に線上に復帰するときに左旋回をして「Online」がN1のループの条件を満たして誤作動してしまうので、これを防ぐためにN1の直後に2秒間ライントレースのみをするサブルーチンN2を実行する。

***E〜F間のS字カーブ部分のサブルーチン [#h6e8519f]

 sub S()
 {
    SetSensor(SENSOR_2, SENSOR_LIGHT); //センサを定義
    ClearTimer(0); //タイマをリセット
 
 
    while (FastTimer(0) < S_time) { //タイマが10秒になるまで
        if (SENSOR_2 < Threshold - 5) { //左旋回
            Turn_left_h;
        } else if (SENSOR_2 < Threshold - 2) { //左折
            Turn_left_l;
        } else if (SENSOR_2 < Threshold + 2) { //直進
            Go_forward;
        } else if (SENSOR_2 < Threshold + 5) { //右折
            Turn_right_l;
        } else { //右旋回
            Turn_right_h;
        }
    }
 }
・E〜F間は急なS字カーブになっていて、ここも左旋回が起こりやすくサブルーチンN1が誤作動をおこすので10秒間ライントレースのみをするサブルーチンSを実行して対策している。

***紙コップをつかむサブルーチン・はなすサブルーチン [#f76d8d75]

 sub MFwd()
 {
    OnFwd(OUT_B); //機構を0.5秒間上げる
    Wait(50);
    Off(OUT_B);
 }    

 sub MRev()
 {
    OnRev(OUT_B); //機構を0.5秒間下げる
    Wait(50);
    Off(OUT_B);
 }
・紙コップをつかむ・はなすサブルーチン。MFwdがつかみ、MRevがはなすサブルーチンである。紙コップをつかむ・はなす地点に来た時に0.5秒間モータBを動かす。

***紙コップを置くために円PQRの中心に移動するサブルーチン・戻るサブルーチン [#r616e487]

 sub R1()
 {
    Turn_right_h; //1.2秒間右旋回
    Wait(120);
    Go_forward; //0.5秒間直進
    Wait(50);
    Break; //小休憩
 }

 sub R2()
 {
    Back; //0.5秒間後進
    Wait(50);
    Turn_left_h; //1.2秒間左旋回
    Wait(120);
    Break; //小休憩
 }
・ルート2の場合円Sで紙コップをつかみ、円PQRの中央ではなす必要がある。つかむ場合は中心に行かなくても本体が円の内側寄りに走っているのでそのまま実行できるが、はなす場合は中心に行く必要がある。サブルーチンR1は中心に行くための、R2は元の線上に戻るためのプログラムである。
***メインプログラム [#o4faff30]

 task main() //メインのプログラム
 {
    Go_forward;
    Wait(30);
    C(); //Cを直進
    N1(); //Bを左折
    N2();	
    N1(); //Pを左折
    N2();
    C(); //Qを直進
    N1(); //Rを左折
    N2();
    N1(); //Eを曲がる
    N2();
    S(); //S字カーブ
    N1(); //Fを左折
    N2();
    C(); //Sを直進
    MRev(); //紙コップをつかむ
    C(); //Sを直進
    N1(); //Qを左折
    N2();
    C(); //Rを直進
    R1(); //円PQRの中心に向かう
    MFwd(); //紙コップを置く
    R2(); //線上に戻る
    N1(); //Pを左折
    N2();
    N1(); //Bを左折
    N2();
    C(); //Aに侵入
    Go_forward;
    Wait(30);
    Break;
 }
・これらの8つのサブルーチンを組み合わせて、

D → Cを直進 → Bを左折 → Pを左折 → Qを直進 → Rを左折 → E〜F間のS字カーブ → Fを左折 → Sを直進 → 紙コップをつかむ → Sを直進 → Qを左折 → Rを直進 → 円PQRの中央に紙コップをはなす → 戻る → Pを左折 → Bを左折 → A

の行動順になるようにした。

**3 実行結果 [#sa02b435]

・このロボットを本番で実行した結果、モータBの接触不良で紙コップをつかむ・はなす機構が動かなかったが、ライントレース自体はうまくいき個人的には満足のいく結果となった。あまりうまくいかなかった前の課題の反省も活かせることができたと思う。この調子で課題3のロボコンもがんばっていきたいと思う。

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