2019a/Member

目次

課題2

A地点を出発し、次の経路を黒い線にそって動くロボットを作成する

C89E0517-4D44-4BA2-93FE-8E5EB0C2BE11.png

経路は以下の通り。

・A地点から出発 → M → K(直進) → L(ピンポン玉をつかむ) → K(右折) → J(一時停止の後、左折) → I(直進) → H(直進) → G(左折) → F → E → D(一時停止の後、直進) → C(直進) → B(一時停止) → シュート→ A地点に入る(ゴール)

ロボットの説明

ロボットの全体像は次の写真の通り。

C20D770E-F322-488A-8F4E-E988D1FD551C.jpeg

これより下に各部位の説明をする。

ボールキャッチの部分

ボールを掴み、離す部分は以下の通り。

E6CF5DE4-1B71-4B94-BF14-41589B72E747.jpeg

モーターを回すことで写真の左を部分が回転するようになっている。 写真で見て反時計回りに回せばキャッチ、時計回りに回せばリリースというふうになっている。 ボールは3点で支え、ロボットが動いても離すことなく、安定したリリースを行えるようになっている。

車輪の部分

車輪の部分は以下の通り。

B48B744B-0F1E-4967-8171-701D5167D9A2.jpeg

安定感を増すために四輪ではなく二輪にした。光センサーの左右にある黒い棒は、ボールをキャッチするために取り付けたものである。写真の左奥の部分(上の写真では見えていない部分)については次の写真を用いて説明する。

03CC224D-FBB7-4ED6-A7A1-19C46E30BA7E.jpeg

手前にある灰色のT字のパーツは、ロボットが車輪を軸としてシーソーのようにならないため、また安定した動きを行うために、バランスを取れる位置に取り付けた。これにより少ないパーツでロボットを安定させた。

プログラムの説明

プログラムは全体を通して線の境界をトレースするようにしてある(線の境界をトレースする方法はこの後の説明に載せる)。そのなかで、交差点の判別して止まる、止まったところから交差点を越えるプログラムをサブルーチンにし、主にその2種類のサブルーチンを並べて、プログラムを構成している。 また、プログラム全体で以下のようにマクロを定義した。

#define turn_left OnFwd(OUT_C);Off(OUT_A);
#define turn_right OnFwd(OUT_A);Off(OUT_C);
#define circling_left OnFwd(OUT_C);OnRev(OUT_A);
#define circling_right OnRev(OUT_C);OnFwd(OUT_A);
#define go_ahead OnFwd(OUT_AC);

turnは片方の車輪を止め、もう片方の車輪を動かすことで、leftなら左回り、rightなら右回りに回転する。 circlingは二つの車輪をそれぞれ前転、後転させることで、二つのタイヤの中点を中心として、leftなら反時計回りに旋回、rightなら時計回りに旋回する。 go_aheadは直進する。

サブルーチンについて

サブルーチンは線の境界をトレースし交差点で止まるものと、交差点で止まった後、線を越えるもの、の二つを使用した。

線の境界をトレースし、交差点で止まるプログラム

黒線の左側の境界を使用する。光センターの感知する色が、真っ黒なら左旋回、それより少し白くなったら左回転、黒と白の中間(これを灰とする)なら直進、白よりの灰なら右回転、真っ白なら右旋回、となるようにプログラムを組む。そして、左旋回(真っ黒)の続く時間によって交差点の判別を行い、左旋回がある一定時間続いたら止まるようにする。

またwhileを使うことで、交差点まではトレースし続けることが出来る。

Timer(0)で、グローバル変数tを使って、左旋回(真っ黒)が続いた時間を測る。左旋回以外の四つの挙動にはClearTimer(0);を入れることで左旋回の時間だけを計測している。

実際に光センサーを使って値を測定し、プログラムにしたものが下のプログラムである。グローバル変数tはプログラム冒頭に、int t;で指定する。tを変えることで、交差点判別の時間をその都度変えることが出来る。

sub follow_line()
{
SetSensor(SENSOR_2,SENSOR_LIGHT);
ClearTimer(0);
while((FastTimer(0)<t)){
  if(SENSOR_2<40){circling_left;}
  else if(SENSOR_2<43){turn_left;ClearTimer(0);}
  else if(SENSOR_2<48){go_ahead;ClearTimer(0);}
  else if(SENSOR_2<50){turn_right;ClearTimer(0);}
  else if(SENSOR_2<55){circling_right;ClearTimer(0);}
  }
Off(OUT_AC);
}

ただし、実際に動かしたプログラムは、大部分は似ているが、上のものではない。上のものを使わなかった理由や、実際に使ったプログラムは次で説明する。

sub follow_line1()
{
SetSensor(SENSOR_2,SENSOR_LIGHT);
ClearTimer(0);ClearTimer(1);
while((FastTimer(0)<t1)&&(FastTimer(1)<t2)){
  if(SENSOR_2<40){circling_left;}
  else if(SENSOR_2<43){turn_left;ClearTimer(0);}
  else if(SENSOR_2<48){go_ahead;ClearTimer(0);}
  else if(SENSOR_2<50){turn_right;ClearTimer(0);}
  else if(SENSOR_2<55){circling_right;ClearTimer(0);}
  }
Off(OUT_AC);
}
sub follow_line2()
{
SetSensor(SENSOR_2,SENSOR_LIGHT);
ClearTimer(0);ClearTimer(1);
while((FastTimer(0)<t1)||(FastTimer(1)<t2)){
  if(SENSOR_2<41){circling_left;}
  else if(SENSOR_2<43){turn_left;ClearTimer(0);}
  else if(SENSOR_2<48){go_ahead;ClearTimer(0);}
  else if(SENSOR_2<55){circling_right;ClearTimer(0);}
  }
Off(OUT_AC);
}

実際には、follow_line1とfollow_line2という二つのサブルーチンを場合に応じて使い分けてた。

1と2の違いはwhileの二つの条件が「かつ」か「または」かの違いだけである。

この二つに分けた理由は、交差点ではなくても止まって欲しい点(コース上の点Lや、点Lから向かう時の点K)、交差点でも止まって欲しくない点(コース上の点Eや点F)、交差点の止まり方によって、交差点でなくても止まってしまう箇所(点Iから点Hに向かうところなど)が存在し、そこも含めて全て2つのサブルーチンで制御したいと思ったからである。

follow_line1を使えば、交差点ではないところでも止めることが出来る。

follow_line2を使えば、交差点でも止まらなくすることが出来る。

follow_Line1もfollow_line2も二つ目のタイマーであるTimer(1)を使う。

二つのグローバル変数はそれぞれ、int t1;とint t2;で指定する。t1には交差点判別の時間、t2ではそのサブルーチンが始まってからの時間を入れる。

Timer(1)を必要としない過程では、follow_line2を使い、t2=0にすれば、交差点を判別し止まるサブルーチンとなり、プログラムを出来るだけ視覚的に判別出来るようにした。

交差点で止まった後、線を越えるサブルーチン

このサブルーチンも二つ使用した。使用した二つのサブルーチンは以下の通り。

sub cross_line1()
{
 SetSensor(SENSOR_2,SENSOR_LIGHT);
 while(SENSOR_2<48)
 {
 go_ahead;
 }
 Off(OUT_AC);Wait(100);
 while(SENSOR_2>47)
 {
 turn_right;
 }
 Off(OUT_AC);
}
sub cross_line2()
{
 SetSensor(SENSOR_2,SENSOR_LIGHT);
 while(SENSOR_2<48)
 {
 go_ahead;
 }
 Off(OUT_AC);Wait(100);
 while(SENSOR_2>47)
 {
 circling_right;
 }
 Off(OUT_AC);
}

二つの違いは、黒線を越え、回転する時に、右回転するか、右旋回するかの違いだけである。基本的にはcross_line1を使う。

しかし、点Hや点Iで止まった後にcross_line1を使うと、他の黒線を捉えてしまうことと、進みすぎて交差点でも止まらなくなってしまったためである。

前文の「進みすぎて止まらなくなってしまう」場合とはどういう場合なのか、わかりづらいため説明する。

この状況は主に点Iで止まり、越えた後に起こる。まず点Jから点 Iに向かう時に、点Iに到達し交差点を判別して、ロボットが止まる。その後、黒線が途切れるまで直進する。ここで右回転してしまうと、点Hにかなり近い点でfollow_line2を始めてしまう時がある。この時、角度が小さいために、交差点と判別しない事態が発生し、コースから外れて、点Hから点Cへ向かってしまう。「進みすぎて止まらなくなってしまう」とはこの現象のことである。

ではこの問題を解決するために交差点を判別する時間を短くすればいいと思うかもしれないが、短くすると今度は境界をトレースしなくなる。上手くいく時間を探すのが困難であるため、cross_line2を導入することでその問題を解決した。

そしてさらに、cross_line2を使うと、今度は黒線に対して直角に近い角度からfollow_lineを始める時があり、交差点でもないのに止まってしまう、という問題が発生する。この問題は、follow_line2のt2を設定することで、通常交差点と認識する所でも、t2で指定した時間の間は、止まることなく境界をトレースし続けるため、解決出来た。

follow_lineもcross_lineも二つ導入することで、このような問題を全て解決することが出来た。

実際に使用したプログラム(全体)

最終的に使用したのは以下のプログラムである。ただし、このページの「プログラムの説明」で既に説明している、マクロ、サブルーチン、変数の定義については省略し、メインプログラムのみ書く。

task main()
{
SetPower(OUT_AC,4);
go_ahead;Wait(70);Off(OUT_AC);//  M到達
t1=15;t2=700;follow_line2();//  K到達
cross_line1();//  K越え
t1=10000;t2=100;follow_line1();//  L到達
OnRev(OUT_B);Wait(30);Off(OUT_B);Wait(100);//  ピンポン玉掴む
t1=25;t2=400;follow_line1();Wait(100);//  K到達
circling_right;Wait(40);Off(OUT_AC);//  
t1=15;t2=0;follow_line2();//  J到達
t1=10;t2=150;follow_line2();//  I到達
cross_line2();//  I越え
t1=10;t2=150;follow_line2();//  H到達
cross_line2();//  H越え
t1=15;t2=100;follow_line2();//  G到達
t1=20;t2=300;follow_line2();//  D到達
cross_line1();//  D越え
t1=20;t2=0;follow_line2();//  C到達
cross_line1();//  C越え
t1=20;t2=0;follow_line2();//  B到達
circling_right;Wait(10);Off(OUT_B);//  ロボットの角度を調節
OnFwd(OUT_B);Wait(50);Off(OUT_B);//  ピンポン玉リリース
go_ahead;Wait(50);Off(OUT_AC);//  A到達
}

「(アルファベット)到達」は、点A以外はその点で止まったことを示し、点Aは、コースのAの領域に到達したことを示している。また、「(アルファベット)越え」は、その交差点を越えたことを示している。また、,函E到達とF到達がないこと、その二つについて説明する。

,砲弔い得睫世垢襪、その前に,里垢鮎紊K到達について説明する。ピンポン玉を掴んだ後は、時間を測って点Kで止めているため、点K付近で止まるものの、毎度正確には止まれなかった。それを踏まえた上で,砲弔い董バラついていても毎度コースをトレースするために、ここの部分だけはサブルーチンを使わなかった。点K付近で止まった後、旋回し、次のfollow_line2を始めることでコースに復帰するようにした。

E到達とF到達がないことについて説明する。点Gから点F、点E、点Dに順に向かう際に、プログラムにある通り、follow_line2を使い、t2を点Eを曲がりきった後から、点Dに到達する前迄の間の時間に調整しておけば、点E、点Fは交差点と同じ形でも止まることなく、トレースすることが出来る。なのでプログラム中に点Eと点Fが登場しないのである。

反省

プログラムの反省

点A(最初)→点J、点J→点A(最後)のそれぞれは上手くいったが、二つを繋げた時には上手くいかなかった。原因を探ったがなかなか見つからなかったため、挫折した。全てを繋げるのではなく、例えば点L→点Dなどで、二つの成功したものの繋ぎの確認をすればよかった。

ロボットの反省

ロボットは四輪から二輪に変えたことでひとつひとつの挙動が制御しやすくなった。ロボットについてはなかなか上手く作れたのではないかと思う。


添付ファイル: file03CC224D-FBB7-4ED6-A7A1-19C46E30BA7E.jpeg 4件 [詳細] fileB48B744B-0F1E-4967-8171-701D5167D9A2.jpeg 3件 [詳細] fileE6CF5DE4-1B71-4B94-BF14-41589B72E747.jpeg 4件 [詳細] fileC20D770E-F322-488A-8F4E-E988D1FD551C.jpeg 9件 [詳細] fileC89E0517-4D44-4BA2-93FE-8E5EB0C2BE11.png 8件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-08-06 (火) 10:05:13 (12d)