目次

課題2

  • 指定課題
    • 次のいずれかのコースで黒い線に沿って動き、途中でボールをゴール付近に立てた350mlの空き缶(黄色で表示)に当てるロボットを製作せよ。 (相棒と違うコースを選ぶこと)
      • 使用コース見本
        コース見本[単位はcm]
  • 第1コース
    • ロボットを長方形X内におき、Aをスタート
      Bを右折
      Kで一時停止して左折
      Jを直進
      Iを直進
      Hを左折
      Gで一時停止して左折
      Eで一時停止して右折
      Lを経て正方形Y内に入って停止
  • (一時停止の指定がある場所は、1秒間停止すること)
  • ボールはロボットが弧KJIH上にある時にQ地点の空き缶に当てる
  • 第2コース
    • ロボットを正方形X内におき、Lをスタート
      Eを一時停止して直進
      Iを一時停止して左折
      Hを直進
      Kを直進
      Jを左折
      Cを一時停止して右折
      Eを一時停止して直進
      Gを一時停止して直進
      長方形X内に入って停止
  • (一時停止の指定がある場所は、1秒間停止すること)
  • ボールはロボットが弧IHKJ上にある時にP地点の空き缶に当てる

実施コース

  • 自分は第1コースを選択したため、以下の赤線で示した道順を辿り、Q地点の空き缶にボールを当てる。
  • また、課題で指定されている地点(矢印の終点)で1秒間停止する。
    作成コース

作成ロボット

全体像

前 赤丸:超音波センサ 緑丸:光センサ
後

モーターAで前方のアーム、モーターB・Cでそれぞれ右前輪・左前輪を稼働させる。

  • ライントレース部分
    • 固定前輪2輪と駆動後輪1輪の計3輪でライン上を移動する。
    • 車体前方下部に光センサを取り付け、明暗を測定する。
  • ボール投射部分
    • 車体前方上部に前方を向くように超音波センサを取り付け、障害物までの距離を測定する。
    • ボールをアームで固定し、投射時にはアームを上げることで転がす。
      保持状態
      投射後
  • 工夫
    • 最初の構想では、超音波センサ・ボール投射部分ともにロボット左方につける予定だったが、重心が偏り旋回が上手くいかなかったので、ロボット前方に取り付け安定するようにした。
    • 時間で一回転旋回させるのは安定しなかったため、角度で行った。

動作説明

ライントレース

今回は「光センサが線外に出た時線上に戻る」「光センサが線上にある時線外に出る」「光センサが線の境目にある時は直進する」という3つの動作を光センサの値によって制御することで、ロボットがライントレースを行えるようにした。つまり線をトレースするのではなく、線の境目をトレースしていくことになる。
自分の実施コースにおいて光センサの値はおよそ[線外:55][線上:35][線の境目:45]を示すため、{光センサが線外(値が50以上)→線上に戻る} {光センサが線上(値が40以下)→線外に出る} {光センサが中間(値が40から50の間)→直進}のように動作を制御する。
ゆえに、左の境目をトレースしている場合、線上に戻る時は右に曲がり、線外に出る時は左に曲がる という動作を行い、右の境目をトレースしている場合はその逆の動作を行う。

線の拡大図 赤矢印:光センサの移動

また、交差点や急なカーブにおいては片方の前輪を動かすだけでは曲がり切れないため、曲がりたい方向の前輪を逆回転させることで、ロボットが急激に曲がるようにしている(旋回)。そのような道では直線や緩やかなカーブの道と比べ、光センサが線上または線外に時間的に長く ある。そのため旋回は一定時間以上光センサが線上か線外にあるときに行われるようにした。 加えて交差点と急なカーブでは、交差点の方がより長く光センサが線上にある。なので交差点判断として、旋回を行っても一定時間以上線外に光センサが出なければ、そこは交差点であると認識するようにしている。

障害物探知

今回はボールを当てる空き缶がロボットに一番近い障害物であるため、一度ロボットを旋回により一回転させ、その後一番近い障害物の方を向くような動作を行わせる。
ロボットを一回転させる方法として、まずロボットの前輪間の距離を直径とするような円を考えた。その円周を前輪がどれだけ回転したかで、ロボットが何度旋回するかがわかるので、その値が360度になるまで前輪を回転させることでロボットを一回転させた。
なお (タイヤ直径/前輪間の距離)*タイヤの回転角度=ロボットの旋回角度 である。

青線:前輪間の距離 赤線:前輪が通る円 黄線:旋回する方向

そのようにしてロボットを回転させていき超音波センサが物体を捉え、その距離が一番短かったのは前輪がどれだけ回転した時だったのかを記憶しておくことで、一回転終了後 その分 前輪を回転させることにより、一番近い物体の方を向くようにした。

使用プログラム

  • 使用マクロ
#define fw Off(OUT_BC);OnFwd(OUT_BC,40);
直進する
#define lt Off(OUT_BC);OnFwd(OUT_B,40);
左に曲がる
#define rt Off(OUT_BC);OnFwd(OUT_C,40);
右に曲がる
#define rrt Off(OUT_BC);OnFwd(OUT_C,25);OnFwd(OUT_B,-55);
右旋回
#define llt Off(OUT_BC);OnFwd(OUT_B,25);OnFwd(OUT_C,-55);
左旋回
#define throw_a RotateMotor(OUT_A,20,-40);Off(OUT_A);
アームを上げる
  • 定義関数
const float tire_diameter = 5.75;
前輪タイヤの直径
const float tire_axis = 11.5;
前輪タイヤ間の距離
long t0,t1,t00;
時間関数
long ang_min,angle;
角度関数

ライントレース

左の境目をトレースする動作をl_line_trace、右の境目をトレースする動作をr_line_traceとしている。
直進するたびに時間関数t0を更新することで曲がり始めの時間を記録している。

   void l_line_trace(long min){
       t1=CurrentTick(); // 経過時間
       t0=CurrentTick(); // 初期時間
       SetSensorLight(S1); // 光センサ定義
       SetSensorLowspeed(S2); //  超音波センサ定義
       while(t1-t0<250||t1-t00<min){ //  光センサが一方に0.25s以下ある(交差点判断) 又は 
                                 // 動き始めてからmin以下しか経過していないとき 繰り返す    
           if (SENSOR_1>50){ // 線外:白
               if (t1-t0>150){   // 光センサが0.15s以上線外にある時右旋回
                     rrt;
               }else{        // 右に曲がる
                     rt;}  
           }else if (SENSOR_1>40){ // 線の境目:灰
               fw;
               t0=CurrentTick(); // 曲がる時の初期時間の更新
           }else{                // 線上:黒
              if (t1-t0>150){ // 光センサが0.15s以上線上にある時左旋回        
                     llt;
	        }else{            // 左に曲がる
                     lt;} 
            }
       t1=CurrentTick();    //経過時間
       }
       Off(OUT_BC);
   }
   void r_line_trace(long min){
       t1=CurrentTick(); // 経過時間
       t0=CurrentTick(); // 初期時間
       SetSensorLight(S1); // 光センサ定義
       SetSensorLowspeed(S2); //  超音波センサ定義
       while(t1-t0<250||t1-t00<min){ //  光センサが一方に0.25s以下ある(交差点判断) 又は 
                 // 動き始めてからmin以下しか経過していないとき 繰り返す  
           if (SENSOR_1>50){ // 線外:白
               if (t1-t0>150){ // 光センサが0.15s以上線外にある時左旋回
                     llt;
	        }else{            // 左に曲がる
                     lt;}                 
           }else if (SENSOR_1>40){ // 線の境目:灰
               fw;
               t0=CurrentTick(); // 曲がる時の初期時間の更新
           }else{                // 線上:黒
               if (t1-t0>150){   // 光センサが0.15s以上線上にある時右旋回
                     rrt;
               }else{        // 右に曲がる
                     rt;}
            }
       t1=CurrentTick();    //経過時間
       }
       Off(OUT_BC);
   }

障害物探知及びボール投射

暫定的に物体までの距離の最小値[int d_min]を長めに取っておくことで、必ず更新されるようにしている。

   void search_throw(){
       SetSensorLowspeed(S2);
       int d_min=1000; //物体までの最小値

動作説明の通り(タイヤ間の距離[tire_diameter]/タイヤの直径[tire_axis])*タイヤの回転角度[モーターCの回転角度]=ロボットの旋回角度である

       ResetTachoCount(OUT_BC);  //回転角リセット
       OnFwdSync(OUT_BC,40,100); //時計回りに旋回
       while(((tire_diameter/tire_axis)*MotorTachoCount(OUT_C))<=360.0){ //ロボットが360度旋回するまで 繰り返す
           if(d_min>SensorUS(S2)){  //最小値が更新された時
               d_min=SensorUS(S2);  //最小値更新
               angle=MotorTachoCount(OUT_C);//タイヤ回転角更新
           }
       }
       Off(OUT_BC);

旋回開始を基準として、360度旋回するまでのタイヤの回転角度[MotorTachoCount(OUT_C)]から障害物を探知した時のタイヤの回転角度[angle]を引くことで、より旋回角度が小さくなるような前輪の回転角度[ang_min]で旋回するようにしている。

赤円:前輪が通る円 黄線:前輪が[angle]回転した時通る弧 青線:前輪が[ang_min]回転した時通る弧
       ang_min=MotorTachoCount(OUT_C)-angle; 
       ResetTachoCount(OUT_BC);
       RotateMotorEx(OUT_BC, 40, ang_min, -100, true, true);//物体の方を向く
       Off(OUT_BC);
       throw_a;   //ボールを投げる

向きをもとに戻すときには旋回時とタイヤの回転を逆にしているのでangleを使用している。

       ResetTachoCount(OUT_BC);
       RotateMotorEx(OUT_BC, 40, angle, -100, true, true);//向きを戻す。
       Off(OUT_BC);
   }

プログラム全体

   task main ()
   {
       t00=CurrentTick();    //最初期時間
       OnFwd(OUT_BC,20);    //X内から出る
       until(SENSOR_1<40);
       Off(OUT_BC);
       RotateMotor(OUT_BC,30,100);    //線AB上に乗る
       r_line_trace(7000);    //右の境目を伝ってBを曲がってKへ向かう(7秒間交差点判断をしない)
       llt;    //Hの方を向いているのでIの方を向くように調整
       until(SENSOR_1<40);
       Off(OUT_BC);
       Wait(1000);    //Kで一時停止
       fw;
       until(SENSOR_1>50);
       Off(OUT_BC);
       lt;     //Jの方を向く
       until(SENSOR_1<40);
       Off(OUT_BC);
       t00=CurrentTick();    //最初期時間を更新
       r_line_trace(6500);   //右の境目を伝って円を回る(Iを通りすぎるあたりまで)
       search_throw();   //障害物探知及びボール投射
       lt;    //左の境目に移動
       until(SENSOR_1<40);  //線上
       Off(OUT_BC);  
       lt;      
       until(SENSOR_1>50);  //線外
       Off(OUT_BC);
       t00=CurrentTick();
       l_line_trace(4000);    //左の境目を伝ってHを左折しGへ向かう
       Wait(1000);    //Gで一時停止
       fw;      //Gを左折
       until(SENSOR_1<40);
       Off(OUT_BC);
       rt;
       until(SENSOR_1>50);
       Off(OUT_BC);
       t00=CurrentTick();
       r_line_trace(26000);    //右の境目を伝って急カーブを曲がり、Fを曲がってEへ向かう
       Wait(1000);        //Eで一時停止
       t00=CurrentTick();
       r_line_trace(4000);    //右の境目を伝ってEを右折しLへ向かう(Lで一瞬止まる)
       lt;               //Y内に入るため向きを調整
       until(SENSOR_1<40);
       Off(OUT_BC);
       fw;    //Y内に入る
       Wait(1500);
       Off(OUT_BC);
   }

感想

前回の課題1に比べて順調に進み、発表にも間に合い成功できたので良かった。
電池出力変動によってロボットの速度が変化することで、{一定時間交差点判断を行わない}という条件の時間指定に難儀して、調整に手間取った。
ロボットを一回転旋回させるプログラムは相棒に頼り切りになってしまったが、全体を通しては良く協力できたように思う。
次回の課題はロボコンで、今回の課題の発展的なことを行うようなので、今回の成功を活かして頑張っていきたい。


添付ファイル: filerobot-b-r-m.jpg [詳細] filerbot-f-l-m.jpg [詳細] fileangle.jpg [詳細] fileline.jpg [詳細] fileline-trace.jpg [詳細] filerbot-f-l.jpeg [詳細] filerobot-over.jpeg [詳細] filethrow-after.jpeg [詳細] filethrow-befor.jpeg [詳細] filerobot-b-r.jpeg 1件 [詳細] filecourse-1.jpeg 1件 [詳細] filecourse.jpeg 1件 [詳細] file2018b-mission2.png 3件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-01-11 (金) 16:21:17 (5d)