ユーザー名が『tadanobo』となっていますが、漢字で書くと『只之某』で、本当の読み方は『ただのなにがし』です。

目次
#contents

*メンバー [#jead2205]

 ・tadanobo

 ・bgpat


*課題の説明 [#yb3b921b]

詳しい説明は[[2014a/Mission1]]を見てください。

&ref(2014a/Member/tadanobo/Mission1/課題地図2.png,80%);

上図のコースを左のスタートから右のゴールに向けて進みます。

なお、ボールは上図の青丸の位置に置かれています。


*ロボット本体 [#p31fe5db]

&ref(2014a/Member/tadanobo/Mission1/DSC01815.jpg,15%);

**ドライブベース [#p763e815]

&ref(2014a/Member/tadanobo/Mission1/DSC01822-1.jpg,15%);

ドライブベースは光センサーがぎりぎり入る程度までに2つのモーターの間をできるだけ狭めてコンパクトにし、小回りを効きやすくしました。

**アーム [#t227c31b]

&ref(2014a/Member/tadanobo/Mission1/DSC01846.jpg,9%);
&ref(2014a/Member/tadanobo/Mission1/DSC01847.jpg,9%);
&ref(2014a/Member/tadanobo/Mission1/DSC01848.jpg,9%);

アームはゲージを上から下ろすスタイルになっています。

&ref(2014a/Member/tadanobo/Mission1/アームの構造2.png,80%);
&ref(2014a/Member/tadanobo/Mission1/アームの構造.png,80%);


アームを下すと車体正面の二本の棒の坂にボールが乗るので、アームを上げるだけで球は自然に転がり出ます。


*プログラム [#k9e1adf3]

**定義文 [#ec25770d]

 #define THRESHOLD 40                        //しきい値を40に設定
 #define SPEED_H 38                         //ハイスピードは38%
 #define SPEED_L 25                         //ロウスピードは25%
 #define OnRL(speedR,speedL) OnFwd(OUT_A,speedR);OnFwd(OUT_C,speedL);
 #define go_forward OnRL(SPEED_H,SPEED_H);              //前進
 #define spin_left OnRL(SPEED_H,-SPEED_H);              //左旋回
 #define turn_left OnRL(SPEED_H,0);                  //左に曲がる
 #define turn_right OnRL(0,SPEED_H);                 //右に曲がる
 #define spin_right OnRL(-SPEED_H,SPEED_H);             //右旋回
 #define nMAX2 350                          //nOnlineの上限値(説明後述)
 #define CROSS_TIME 400                       //交差点通過時の前進する時間
 #define cross_line OnRL(SPEED_H,SPEED_H);Wait(CROSS_TIME);     //交差点通過
 #define STEP 1                           //各動作にかける時間
 #define go_back OnRL(-SPEED_L,-SPEED_L);              //後進
 #define go_back2 OnRL(-SPEED_H -5,-SPEED_L);            //後進
 #define shoot_ball go_back;Wait(400);Off(OUT_AC);\         //最後にアームを
                    RotateMotor(OUT_B,25,-90);Off(OUT_AC);       上げてボールを放つ


**ライントレース [#ea62200c]

 task main()
 {
    SetSensorLight(S3);                          //光センサーをセット
    _
    int nOnline = 0;                //"nOnline"という名前のカウンターをセット。右旋回の回数を計る
    int nCorner = 0;                             //"nCorner"という名前のカウンターをセット。直角カーブの数を計る
    _
    go_forward;until(SENSOR_3 < THRESHOLD -8)    //STARTの位置からコースの
    go_forward;Wait(200);                  黒線に乗るまで前進する
    _
    while(nCorner <= 6) {                        //nCornerが6以下の間は{}内の命令を繰り返し実行する
      if(nOnline < nMAX2) {                      //nOnlineの値がnMAX2以下の時は以下の動作をする
        if(SENSOR_3 < THRESHOLD -5) {            //車体が黒線上にいるとき
          spin_right;                            //右旋回する*
          nOnline++;                             //nOnlineを1加算
        } else {
          if(SENSOR_3 < THRESHOLD +5) {           //車体が黒線上の境界線よりにいるとき
            turn_right;                          //右に曲がる*
          } else if(SENSOR_3 < THRESHOLD +10) {   //車体が境界線上にいるとき
            go_forward;                          //前進する*
          } else if(SENSOR_3 < THRESHOLD +14) {   //車体が黒線外の境界線よりにいるとき
            turn_left;                           //左に曲がる*
          } else {                                //車体が黒線外にいるとき
            spin_left;                            //左旋回する*
             }
          nOnline=0;                             //右旋回以外の動作をしたときnOnlineをリセットする
          }
        Wait(STEP);                              //各動作は一回当たり1/1000秒間行う
    (☆に続く)


基本的には、光センサーにより明るさを測って、明度の値により左右に曲がらせてライン上を進みます。

 直角カーブは右旋回の回数を計ることで判別します。右旋回の回数はnOnlineというカウンターで
計ります。上記の*の動作は一回あたり1/1000秒間行われます。つまり連続で右旋回が行われて
nOnlineが加算されていった場合、かかる時間は(nOnlineの回数)/1000秒として考えることができます。nOnlineの値(連続で右旋回した回数)をN、連続でN回右旋回するのにかかる時間をtとすると、
t=N/1000(秒)という式ができます。

 例えば、100回連続で右旋回した場合かかる時間は100/1000秒=0.1秒となります。上記のプログラ
ムでは、nOnlineの上限値をnMAX2=350としているので350回以上連続で、言い換えれば0.35秒以上連
続で右旋回をすると直角カーブと判断します。逆に、右旋回が0.35秒以上行われない限りは通常であ
ると判断しライントレースを続けます。



**交差点を渡る・直角,ヘアピンカーブを曲がる・ボールを放つ [#ud4897d3]


  (☆)
      } else {                                                        //nOnlineがnMAX2以上になったときは以下の動作をする
        PlayTone(440,100);  //合図のため"ラ"の音を鳴らす
        Off(OUT_AC);Wait(1000);  //一時停止
        if((nCorner == 0)||(nCorner == 5)) {                        //ヘアピンカーブのとき
          spin_right;until(SENSOR_3 > THRESHOLD +11)                //カーブを曲がりきるまで右旋回
        } else if((nCorner == 1)||(nCorner == 3)||(nCorner == 4)) {  //交差点の時
          PlaySound(SOUND_UP);                                      //合図のため音を鳴らす
          if(nCorner == 1) {                                        //一つ目の交差点の時
            go_forward;Wait(100);                          //ボールに接近
            RotateMotor(OUT_B,15,85);                                 //アームを下ろす
            Off(OUT_B);                                               //アームを止める
            go_back2;Wait(300);                                       //
            go_back2;until(SENSOR_3 < THRESHOLD -10);                 //元のコースに戻る  
            go_back2;Wait(300);                                       //元のコースに戻る
            go_back2;until(SENSOR_3 < THRESHOLD -10);                 //   〃  
             }
          spin_left; Wait(nMAX2*STEP);                              //軌道修正のため左旋回
          if(nCorner == 4) {                                        //3つ目の交差点のとき
            spin_left;Wait(200);                                    //さらに軌道修正のため左旋回
             }
          cross_line;                                               //交差点を通過
        } else if(nCorner == 2) {                                   //直角カーブの時
          PlaySound(SOUND_LOW_BEEP);                                //合図のため音を鳴らす
          spin_right;until(SENSOR_3 > THRESHOLD -2)                 //直角カーブを曲がりきるまで右旋回
        } else if(nCorner == 6) {                                   //ゴール前に到着したとき
          spin_left;Wait(nMAX2*STEP);                               //左旋回して軌道修正し、ゴールと正対する
          shoot_ball;                                               //ボールを放つ
          }
        nOnline=0;                                                  //nOnlineをリセット
        nCorner++;                                                  //nCornerを1加算
        }
     
     }
    Off(OUT_AC);                                                  //nCornerの値が6を超えたら停止、以上で終了。
 }


 コース上を走行した際、直角カーブ・交差点・ヘアピンカーブ(以下:直角ポイント)にいつ、何
回あうのかは事前にわかります。なので、それらの数を数えることでマシンに適切に対応させます。
そのため、プログラムの始めにnCornerというカウンターを定義します。

 今回の課題のコースでは、右からスタートすると下図のような順に直角ポイントにあたりま(��,
�Δ魯悒▲團鵐�ーブ、��,��,�イ聾鮑硬澄↓�は直角カーブ、�Г禄�着点です)。カウンターの
nCornerの値は最初0になっています。なので、�,猟廠僖櫂ぅ鵐箸忙蠅辰浸�点ではnCorner=0の状態です。
 直角ポイント�,忙蠅辰謄悒▲團鵐�ーブを判別したら、カーブを曲がりきるよう右旋回させます。その後nCornerの値を1加算します。これでnCornerの値は1になりました。続いて直角ポイント�△�
ついたら玉を回収しつつ元の位置に後進で戻り、そして交差点を越えます。ここでnCornerの値をま
た1加算し、nCornerの値は2になります。直角ポイント��についたら�,了�と同様に右旋回で角を
曲がり切ります。そしてnCornerの値を1加算し、これでnCornerの値は3になります。以降、直角ポイントにつくたびにこのようにして進んでいきます。

&ref(2014a/Member/tadanobo/Mission1/直角ポイント.png,50%);

 このように、直角ポイントにつくごとにそれぞれ適切な対処をし、その後nCornerの値を1ずつ加算していくことで順に来る直角ポイントを正確に判別させ、コースを進ませます。
 交差点を越える際の軌道修正は、直角を判定するために右旋回を少なくとも0.35秒するので、その分車体が直進するべき交差点の手前で右に向いてしまいます。なので交差点に対しまっすぐになるよう左旋回して軌道を修正します。

 最後のボールを放つところは、軌道修正してゴールと正対したらあとはアームを上げるだけでボールは坂を転がり自動的に正面へ放たれる、といった具合になっています。


*感想 [#j8f08630]

 今回の課題達成までにマシンの構造をどうするか、プログラムはどのようにするかなど思案すべき点が多々あったため完成させるのには大変骨が折れた。だからこそ、マシンが初めて目的を満たす動きを見せた時の感動と達成感は忘れ難いものだった。知恵を分けてもらい、目標達成に向け協力してくれたメンバーには感謝をしたい。 

 さて、今回作成したこのプログラムの中で一番の難点だったのがライントレースだった。コースの作成はPC上で作られた図を分割印刷して張り合わせたもので、セロテープを用いたためテープの部分だけ光の反射により若干明るくなってしまい、しきい値の調整が難しかった。その上でトレースを成功させられたので満足だ。

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