2009a

目次

課題2/黒い線に沿って動くロボット

メンバー紹介

・つっちー…工学ノ人。脳ミソ(プログラミング)担当。

・ゆうき…教育ノ人。ボディ(ロボット構造)担当。

・ジェシー…課題2を達成するためにつっちーとゆうきに造られたロボット。

      性別は♀(誕生時は♂で名はヘラクレスだった)。

      7ARのウッディの許嫁。

課題内容

各チームで作成したコースを3周するロボットを製作せよ。 交差点のうちの一つには500mlの空の紙パックをおき、

次のような動作するプログラムを作成せよ。

(他のメンバーと重ならないように一人一つのプログラムを作成する)

1.紙パックを迂回する、あるいは紙パックをもとの位置に戻したのちコースに戻って進む (交差点を通過後、紙パックが元の位置にあればよい)

2.紙パックを次の交差点まで運んで行き、その交差点に紙パックを残してさらに黒い線に沿って進む

ただし、

•速さと正確さを追求すること

•コースを3周したら自動的に止まること

ロボットの作成

ベースの部分

どんな急なカーブにも対応できる=小回りがきく!!

…ということで今回はロボのベースをマニュアルとは違う構造にしてみました★

通常のロボより横幅が狭くなっています。

2hontai.jpg

光センサーの部分

センサー同士の幅が広くなってしまうと黒いラインを感知するに時間がかかってしまいコースアウトするリスクが上がってしまいます。

よりコース上を正確に走らせるためにセンサーの幅を極力狭くしました。

2sita.jpg

あと、ラインを正確に感知できるようにセンサーの高さを地面ギリギリにしました。

2sannsayokoup.jpg

タッチセンサーの部分

初期のままだとセンサが反応しない場合があったので梃の原理を利用してセンサが反応しやすいようにしました★

紙パックを挟む部分

ひとつのモーターを使って紙パックを挟む構造を採用しました。

2hasamiue.jpg

ギアを組み立ててハサミを開いたり閉じたりできるようにしました(・∀・)

2giamae.jpg

完成図

そして出来上がったのがこちら(*´∀`)ノ♥

2naname.jpg
2yoko.jpg
2ue.jpg

コース紹介

course_kousinn_mae.JPG

製作者によるとこのコースはト音記号をモチーフにしたそうです♪

急なカーブが多くなかなかに難関コースに仕上がりました(´*`;)

でも、難しすぎてこんなのできない! 堯福陰◆院─

course_kousinngo.JPG

ということで、上のシンプルなのに変えました

プログラミング

つっちー

→1.紙パックを迂回する、あるいは紙パックをもとの位置に戻したのちコースに戻って進む

int sem_2;                          //タスク制御の変数 詳しくは下で説明
int sem_3;                          //タスク制御の変数 詳しくは下で説明
int count;                          //交差点を数える
int dodge;                          //タスク制御の変数 詳しくは下で説明
int timer;                          //タイマー(0)の値を保存する
int timer_2;                        //タイマー(1)の値を保存する
int time;                           //避けるまでに進んだ時間を保存する
#define straight_time 130;
#define dodge_to_back Off(OUT_A+OUT_C);OnRev(OUT_A+OUT_C);Wait(100);Off(OUT_A+OUT_C);Wait(200);OnFwd(OUT_A+OUT_C);Wait(80);
//↑当たった時に後ろへ避ける
#define turn_left ClearTimer(0);OnFwd(OUT_A+OUT_C);Wait(time);sem_3=1;time=straight_time;OnFwd(OUT_A);OnRev(OUT_C);Wait(105);dodge -= 2;sem_3=0;
//↑前進して方向転換をする
#define turn_right sem_3=1;time=straight_time;OnRev(OUT_A);OnFwd(OUT_C);Wait(105);dodge -= 2;sem_3=0;     //方向転換をする
task main()
{
count=0;               //各変数の初期値を設定
sem_2=0;
sem_3=0;
dodge=10;
timer=0;
timer_2=0;
time=straight_time;
SetSensor(SENSOR_1, SENSOR_LIGHT);//センサー1と3を光センサーに
SetSensor(SENSOR_2, SENSOR_TOUCH);//センサー2をタッチセンサーに設定
SetSensor(SENSOR_3, SENSOR_LIGHT);//
start dodging;
start dodging_2;
Wait(100);                 //ボタンを押してから1秒待つ
while( sem_2 == 0 )
  {
while(true)
   {
     if (count >= 12)      //交差点の通った回数を数える
       {                   //12回通ったら
        sem_2=4;           //終りなので止まる
        StopAllTasks();
        Off(OUT_A+OUT_C);
       }
     else
       {
       OnFwd(OUT_A+OUT_C);
       }
     if (SENSOR_2 == 1)     //タッチセンサーが反応したら
       {                    //後ろに避けて止まる
       dodge_to_back;
       ClearTimer(0);
         until ((SENSOR_2 == 1) ||(Timer(0) == 20))   //もう一度前に出て
          {                                           
          OnFwd(OUT_A+OUT_C);Wait(20);Off(OUT_A+OUT_C) //また当たったら
          }
          if (SENSOR_2 == 1)                      //牛乳パックだと思われるので
          {
          Off(OUT_A+OUT_C);
          sem_3=1;                                //牛乳パック回避用にsem_2と
          sem_2=3;                                //sem_3の値を変更する
          }
       }  
     else                                       //当たらなかったら相手のNQCだったと
       {                         //思われるのでそのままライントレースを再開する
       
       }
     if ((SENSOR_1< 45 ) &&(SENSOR_3< 40))//光センサーが両方反応したら
       {                                  //交差点だと思われるので
       Off(OUT_A+OUT_C);
       Wait(30);
       count++;                           //countの値を1増やして前進
       OnFwd(OUT_A+OUT_C);
       Wait(30);
       }
     else
       {
         if (SENSOR_1< 45)                //左の光センサーが反応したら
           {                              //進路が右にズレているので
           OnRev(OUT_A);                  //左に修正
           }
         if (SENSOR_3< 40)                //右の光センサーが反応したら
           {                              //進路が左にズレているので
           OnRev(OUT_C);                  //右に修正
           } 
       }
   }
  }
}
       //ここから下は牛乳パックがあった時の避けるプログラム
task dodging()
{
   while(sem_2 == 3)
   {
     Off(OUT_A+OUT_C);
     if (dodge == 10)
        {
        OnRev(OUT_A+OUT_C); //ちょっと下がって
        Wait(30);            //                         ■---牛乳パック
        sem_3=0;             //                         ←
        turn_right;          //方向転換して前進     ↑   
        }
     if (dodge == 8)
        {
        turn_left;            //方向転換して    ↑■
        OnFwd(OUT_A+OUT_C);   //前進        ↑←
        Wait(120);
        }
     if (dodge == 6)
        {                   //                        ↑→
        turn_left;          //方向転換して前進    ↑■
        }
     if (dodge == 4)
        {
        ClearTimer(0);           //                      ↑
        turn_right;              //方向転換       ■
        dodge = 10;
        }
     sem_2=0;                     //避け終わったのでsem_2を0にする
   }
}//牛乳パックを避けているときに相手と当たったときのプログラム
task dodging_2()
{
  while(true)
   {
      while(sem_2 == 3)
      {
         while(sem_3 == 0)
         {
            if (SENSOR_2 == 1)
               {
               stop dodging;
               ClearTimer(1);
               timer=Timer(0);
               dodge_to_back;
               timer_2=Timer(1);
               time=straight_time-10-timer-timer_2;//避けた時間を計算して再設定 なぜか0.1秒ずれてしまうので修正します
               start dodging;
               }
         }
      }
   }
}
プログラム中で説明しにくかったところについて
sem_2,sem_3について
この二つの変数は今、ロボットがどのような状態であるかを認識するために使いました
sem_2が0の時→通常時(ラインの上を走っているとき)
sem_2が3の時→牛乳パックを避けているとき
sem_2が4の時→全部のプログラムが止まる(終了時)
sem_3が0の時→通常時(ラインの上を走っているとき)
sem_3が1の時→牛乳パックを避けている最中の方向転換しているとき
変数の組み込み方
whileのカッコの中に変数を入れひとかたまりのプログラムを囲います。
その値によって例えば「ラインの上を走るプログラム」だけを止めたりします。
値はセンサーが反応した直後に変え、
ひとかたまりのプログラムの最後に元に戻します。
このやり方のメリット
これを使うと例えば「ラインの上を走りながら、タッチセンサーだけは止める」といったことが簡単にできるようになりました。
また、whileのカッコの中に 〜以上 などの条件を入れるとSetPriorityを使わずにプログラムの優先順位が決められるようになります。
さらにSetPriorityのように優先順位を決めるだけでなくロボットの状態に合わせて、一部のタスクだけを動かすことができます。
例えば、牛乳パックを避けているときは光センサーもタッチセンサーも無視して
牛乳パックを避けるプログラムだけを動かすことができます。
このほかに、タスクに分けてなくても使えるという利点もあります。
使用例
これらを使うと、例えば、変数(sem)の値が0から大きいほど優先順位が高く、
特別な条件のとき大きい数字を使う というふうにするとこんなことができます。
ただひたすら前進するプログラム→while(sem <= 0)
光センサーが反応したら方向修正するプログラム→while(sem <= 1)
タッチセンサーが反応したら下がるプログラム→while(sem <= 2)
一周し終わってて止まるプログラム→while(sem <= 3)
牛乳パックを避けるプログラム→while(sem == 10)
このようにすると普段は前進していて、光センサーが反応したら方向修正、
もし方向修正中に何かに当たったら下がり、
牛乳パックだったら避けるプログラムだけを動かす。
そして、一周したら終了 といったことができます。
ちなみに変数にsemを使っている理由は特にありません。
ついでに上の例が最初にこのやり方を思いついた時の理想の形でした。
デメリット
これをやるとプログラムが少し複雑になります
(特にプログラムの最後のほうに }←これが何個必要なのかわからなくなります)
また、変数が全体にまたがるのでエラーやロボットが予想外の動きをしたとき
原因がわかりにくくなります。
(このため変数が変わったときに音を鳴らすとわかりやすくなります)
別にこのやり方をしなくても、start(タスク名)やstop(タスク名)を使えば長くなるけど、
できないことは無い(ただしタスクを分けたとき限定) 
dodgeについて
dodgeは牛乳パックを避けているとき、どこまで避けたかを示す変数
10→牛乳パック正面 
8→牛乳パックの横を移動中 
6→牛乳パックの反対側を移動中
4→ラインを光センサーの間に入れる
タスクを複数にした理由について
今回、プログラムを複数のタスクに分け、このような変数を使ったのは、今回のプログラムがとても長くなってしまったため、
見たときわかりずらく、またエラーが出たとき、どこが間違っているのかもわかりずらかったからです。
そこで、ロボットの動きごとにタスクを分け、プログラムをわかりやすくました。
さらに、エラーが解決できないときには、タスクごとに確かめれば良いので楽になりました。
また、牛乳パックを避けるときタスク一つでやる方法があまりピンとこなかったので
タスクを分けました
実際に、同時にタスクが動くところも、その必要性もあまりないかもしれません。
ここに出す前のプログラムではタスクは5個あり、そのときは、同時に動くところも、必要性もありました。
ただ、多すぎて逆にあわせるのが大変だったり、わかりずらかったので今回のに、改良しました。
このあたりが今回のプログラミングの反省点になります。

ゆうき

→2.紙パックを次の交差点まで運んで行き、その交差点に紙パックを残してさらに黒い線に沿って進む

 int a;
 #define BORDER 45     //閾値を45に定義
 int flag = 0;
 task main ()
 {
 a=0;	
	SetSensor ( SENSOR_1, SENSOR_LIGHT );
	SetSensor ( SENSOR_2, SENSOR_TOUCH );
	SetSensor ( SENSOR_3, SENSOR_LIGHT );     //1と3→光センサ、2→タッチセンサ
	
	Wait ( 100 );     //起動してから1秒待機	
	
	
	while ( flag < 13 ){     //交差点を13回通るまでのループ	
		
		if ( SENSOR_2 == 1 ){ if (a == 0){     //タッチセンサが反応したら		
			OnRev(OUT_A+OUT_C);
			Wait(50);     //いったん緊急回避して		
			Off(OUT_A+OUT_C);
			Wait(300);     //3秒待機して			
			OnFwd(OUT_A+OUT_C);
			Wait(30);     //もとの場所に戻る
			ClearTimer(0);
			until ((SENSOR_2==1) || (Timer(0)>2 ))OnFwd(OUT_A+OUT_C);}
			if(SENSOR_2==1){a=1;     //タッチセンサが再び反応したら
			             OnFwd(OUT_B);
			             Wait(50);     //ハサミ起動☆
			             }
			             else if(SENSOR_2==0){
			             if(SENSOR_1 > BORDER ){
			                     if( SENSOR_3 > BORDER ){
			                                OnFwd(OUT_A+OUT_C);
			                      }
			                      else{
			                                 OnFwd(OUT_A);
			                                 Wait(5);
			                                 OnRev(OUT_C);
			                                 Wait(5);
			                       }
			            }
			            else{
			                         if(SENSOR_3 > BORDER){
			                                      OnRev(OUT_A);
			                                      Wait(5);
			                                      OnFwd(OUT_C);
			                                      Wait(5);
			                         }
			                         else{
			                                    Off(OUT_A+OUT_C);
			                                    Wait(150);
			                                    OnRev(OUT_B);
			                                    Wait(50);
			                                    Off(OUT_B);
			                                    OnRev(OUT_A+OUT_C);
			                                    Wait(100);
			                                    Off(OUT_A+OUT_C);
			                                    OnFwd(OUT_A);
			                                    Wait(50);
			                                    Off(OUT_A);
			                                    OnFwd(OUT_C);
			                                    Wait(150);
			                                    Off(OUT_C);
			                                    OnFwd(OUT_A);
			                                    Wait(50);
			                                    Off(OUT_A);a=0;
			                             }
			                       }
			                }
			              
			                                    					
		}
		else{					
			
			if ( SENSOR_1 > BORDER ){     //右センサが白で		
				if ( SENSOR_3> BORDER ){     //左センサも白なら(L1 R1)	
					OnFwd(OUT_A+OUT_C);     //直進する	
				}
				else {     //左センサが黒なら(L0 R1)				
					OnFwd(OUT_A);
					Wait(5);
					OnRev(OUT_C);
					Wait(5);     //左に曲がる		
				}
			}
			else {     //右センサが黒でで					
				if ( SENSOR_3> BORDER ){     //左センサが白なら(L1 R0)	
					OnRev (OUT_A);
					Wait(5);
					OnFwd(OUT_C);
					Wait(5);    //右に曲がる		
				}
				else {     //両センサが黒なら(L1 R1)				
					Off(OUT_A+OUT_C);     //交差点と思われるので止まって	
					Wait(50);     //0.5秒待機して		
					OnFwd(OUT_A+OUT_C);     //直進し始めて	
					Wait(20);     //0.2秒直進して		
					flag++;     //交差点カウンタに1足す			
				}
			}
		}
	
	}
	Off(OUT_A+OUT_C);	

}

創意工夫した点

・急なカーブがまがれない。→ 小回りがきくように本体を一回り小さくした。

・紙パックを移動させるときにずれる。→ハサミで挟みこんで固定。

・相手のロボと紙パックの判別ができない。→いったんさがる。→ロボだったらいなくなってるからそのまま前進/紙パックだったらまたタッチセンサが反応して、

ハサミが起動&タッチセンサoffで次の交差点まで前進★

感想

つっちー

最初はタスクを五個使っていたのですが、うまくいかなかったので三個に減らしました。

タスクの優先順位はSetPriorityを知らなかったので変数を利用し、制御してみました。

そのせいでかなりプログラムがわかりにくくなってしまいました。

また、牛乳パックを避けている最中に、相手に当たったときのプログラムがなかなか大変でした。

実際必要なのか怪しいですが、入れておきました。

ゆうき

ライントレースまではうまくいったのですが、紙パックを運ぶプログラムは苦労しました。

タッチセンサの作動がなかなかに大変でした。 課題2をやるうえで、つっちーとリナにはいっぱい迷惑かけました(Θ*Θ)ホントにすんません、

ありがとm(_ _)m★

コメント

このページに関する御意見•御感想などありましたら、お書きくださいm(_ _)m また、☆をとるためになにかアドバイスがありましたら、お願いします

  • 私の環境だとコースの画像が見られません…(?_?)プログラムでかなり高度なことをしているようなので、もっと説明を入れていただかないとさっぱり…taskを利用されているようですが、どんなときに、どのtaskが同時に動くのでしょう?(同時に動くtaskがないのなら、taskにする意味はあまりありません…。) -- こさか? 2009-07-02 (木) 22:29:31
  • 全体的にきちんと書いているとい思います。二人目のプログラムに説明を入れてください。 -- FI? 2009-07-03 (金) 03:51:54
  • taskの動きがよくわかりました。状態をあらわす変数の使い方をもう少し工夫したら、ifの{}を減らせるかもしれません。全体的に高度なプログラムと詳しい説明があって高評価です。 -- こさか? 2009-07-10 (金) 12:29:43


添付ファイル: filecourse_kousinn_mae.JPG 219件 [詳細] filecourse_kousinngo.JPG 281件 [詳細] file2yoko.jpg 215件 [詳細] file2ue.jpg 223件 [詳細] file2sita.jpg 200件 [詳細] file2sennsayoko.jpg 108件 [詳細] file2sannsayokoup.jpg 201件 [詳細] file2naname.jpg 221件 [詳細] file2mae.jpg 107件 [詳細] file2hontai.jpg 192件 [詳細] file2hasamiup.jpg 107件 [詳細] file2hasamiue.jpg 247件 [詳細] file2giamae.jpg 240件 [詳細] file2densetu.jpg 113件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-07-10 (金) 12:29:44 (3699d)