目次
#contents
*課題について [#xd5df109]
下のような図をチームごとに作成し、黒い線の上を走るようなロボットを作成する。
#ref(2019a/Member/Gouki/Mission2/2019a-mission2.png,70%);
**課題の詳細 [#f419cc01]
A地点を出発し、次の経路を黒い線にそって動き、最後にピンポン球をゴールに入れるロボットを作成する
#ref(2019a/Member/Gouki/Mission2/Inked2019a-mission2_LI.jpg,70%);
��A地点から出発
��Bを直進
��Cを直進
��Dを一時停止の後に直進
��Eを直進
��Fを直進
��Gを一時停止の後に右折
��Hを直進
��Iを直進
��Jを右折
��Kを左折
��Lでピンポン玉をつかむ
��Kを直進
��Mで一時停止
��シュート
��A地点に入る(ゴール)
*ロボット本体について [#d3ddfb99]
**ロボット全体 [#f2f596ad]
#ref(2019a/Member/Gouki/Mission2/line_175788711878042.jpg,30%);
今回の機体を制作するにあたり、図上できちんと小回りがきくように、なるべく小さいロボットにした。~
**光センサー部分 [#z7f7e944]
#ref(2019a/Member/Gouki/Mission2/line_175812470413242.jpg,30%);
光センサーの場所は、近すぎず遠すぎずなるべく正確な値を図れるようにした。
**タイヤ部分 [#o8ddbba8]
#ref(2019a/Member/Gouki/Mission2/line_175792940901791.jpg,30%);
タイヤはなるべく光センサーに近くなるように設計した。~
理由としては、光を検知し、タイヤをいち早く検知した光の値の時のプログラムを実行させ、動作する上での誤差をなくすためだ。
**つかむ機構 [#q8a37cf4]
#ref(2019a/Member/Gouki/Mission2/line_175760293908939.jpg,30%);
#ref(2019a/Member/Gouki/Mission2/Inkedline_175750132339776_LI.jpg,30%);
アームの開閉の構造は図を見てもらった方が分かりやすいが、~
�.癲璽拭爾鮓�かって上から上方向に回すとアームを開く~
�▲癲璽拭爾鮓�かって上から下方向に回すとアームが閉じる~
*個々のプログラムについて [#x8c757c8]
**ライントレース [#ja65743e]
今回は、黒い線を追従するライントレースのプログラミングを作らなければならない。~
まずは光の値を測る。私たちは「完全に真っ白」、「白と境目の間」、「境目」、「黒と境目の間」、~
「完全に黒」の5つの部分に色を分けて測った。~
それらの値は以下の図のようになった。
#ref(2019a/Member/Gouki/Mission2/Hikarinoatai.png,30%);
プログラミングでは、それぞれの値を以下のように定義する。
#define black 20
#define white 50
#define lightgray 40
#define darkgray 28
#define center 35
明かるさの値を5段階に分け、それらに対応する5つの動作を振り分ける。~
下の図がその動作であり、明るさや場合によってどの動きになるかは異なる。
#ref(2019a/Member/Gouki/Mission2/ugokuhoukou.png,30%);
以下がその動作を定義したプログラミングである。
#define turn_right OnFwd(OUT_C,25);OnRev(OUT_B,15);//��
#define turn_left OnFwd(OUT_B,25);OnRev(OUT_C,15);//��
#define rotate_right OnFwd(OUT_C,20);OnRev(OUT_B,20);//��
#define rotate_left OnFwd(OUT_B,20);OnRev(OUT_C,20);//��
#define go_straight OnFwd(OUT_BC,20);//��
#define go_straight2 OnFwd(OUT_BC,15);//�イ僚侘呂鮠�し下げたもの
***左側のライントレース [#ye3aa3a8]
右側と左側とでのライントレースではプログラミングが異なってくるため~
それぞれ分けて考える。
sub followline_L(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){
if(SENSOR_1<black){
rotate_left; //明るさが20より小さいとき�△瞭虻�
}else if(SENSOR_1<darkgray){
turn_left; //明るさが28より小さいとき�い瞭虻�
}else if(SENSOR_1>lightdark){
turn_right; //明るさが35より小さいとき��の動作
}else if(SENSOR_1<center){
go_straight; //明るさが40より大きいとき�イ瞭虻�
}else{
rotate_right; //明るさが50より大きいとき�,瞭虻�
}
}
}
水色の矢印がプログラミングで動作する方向である。
#ref(2019a/Member/Gouki/Mission2/InkedHikarinoatai_LI.jpg,30%);
***右側のライントレース [#ga54f680]
左側のライントレースと同様に右側のライントレースも考える。
sub followline_R(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){
if(SENSOR_1<black){
rotate_right; //明るさが20より小さいとき�,瞭虻�
}else if(SENSOR_1<darkgray){
turn_right; //明るさが28より小さいとき��の動作
}else if(SENSOR_1>lightdark){
turn_left; //明るさが35より小さいとき�い瞭虻�
}else if(SENSOR_1<center){
go_straight; //明るさが40より大きいとき�イ瞭虻�
}else{
rotate_left; //明るさが50より大きいとき�△瞭虻�
}
}
}
#ref(2019a/Member/Gouki/Mission2/Inkedhikari2_LI.jpg,30%);
赤色の矢印がプログラミングで動作する方向である。
**交差点認識 [#pf6b85ac]
ライントレースをする際に途中で交差点にさしかかる。そのままライントレースをしてしまうと角に沿ってそのまま曲がっていってしまう。~
そのために交差点を認識するプログラミングを作成する。それは、ライントレース中に特定の動作を指定した何秒間か行った場合にライントレースを終了させるというものだ。
又、今回は交差点を認識した際に、数秒間停止しなければならないので、数秒間停止するプログラミングもライントレースの中に付け加える。
***左側のライントレースの交差点認識 [#o18ba70d]
左側のライントレースの場合、「黒」と「黒と境目の間」の�△鉢い瞭虻遒�~
連続で何秒間か動作したときに、止まるようにする。
始めにt0=CurrentTickとおき、それぞれの変数の値の差(CurrentTick()-t0)は0である。t0=CurrentTickを下のプログラムのように~
ifやelse ifのなかにいれ、それをロボットが認識するたびにこの変数の値の差は0(to=CurrentTick)となる。それは~
to=CurrentTickと入れていないとそれぞれの変数の差は0に更新されず増え続けることになる。~
すなわちifやelse ifの中にto=CurrentTickといれないならば、ロボットはto=CurrentTickを認識することは~
出来ず、それぞれの変数の差は0にならずto=CurrentTickと入っていないifやelse ifの動作を実行している際は~
この変数の値(CurrentTick)は増え続けているのである。そして、それぞれの変数の差(CurrentTick()-t0)に下記のプログラムのstop_timeのように上限を設け、stop_timeには特定の値を入れる。こうすることで、CurrentTick()-t0~
がstop_timeに入れた値の時間分を超すとwhileの動作を停止し、次の動作であるOff(OUT_BC);Wait(1000);~
を実行し、ロボットは1秒間止まる。これがプログラム中のt0=CurrentTick()と(CurrentTick()-t0<stop_time~
の意味合いとなる。
の意味合いとなる。~
そして左側のライントレースの場合 if(SENSOR_1<black)とelse if(SENSOR_1<darkgray)に~
t0=CurrentTick();が入っておらずblackすなわち20より小さい値、darkgrayすなわち28より小さい値~
を検知した時間がstop_timeの値の時間分を超過した場合にはwhileの動作を停止し、次の動作であるOff(OUT_BC);Wait(1000);~
を実行し、ロボットは1秒間止まる
sub followline_L(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){ //stop_timeにいれた値を超過すると次のプログラムへ
if(SENSOR_1<black){ //blackすなわち20より小さい値を検知すると左へ旋回
rotate_left; //この動作が連続すると止まる
}else if(SENSOR_1<darkgray){ //darkgrayすなわち28より小さい値を検知すると左へ
turn_left; //この動作が連続すると止まる
}else if(SENSOR_1>lightdark){ //lightdrayすなわち40より大きい値を検知すると右へ曲がる
turn_right; //この動作中はライントレースし続ける
t0=CurrentTick();
}else if(SENSOR_1<center){ //centerすなわち35より小さい値を検知すると直進する
go_straight; //この動作中はライントレースし続ける
t0=CurrentTick();
}else{ //whiteすなわち50より大きい値を検知すると右へ旋回
rotate_right; //この動作中はライントレースし続ける
t0=CurrentTick();
}
}
Off(OUT_BC);
Wait(1000);
}
***右側のライントレースの交差点認識 [#z33fa8be]
右側のライントレースの場合、「白」と「白と境目の間」の�,鉢�の動作が~
右側のライントレースの場合、「黒」と「黒と境目の間」の�,鉢�の動作が~
連続で何秒間か動作したときに、止まるようにする。~
この原理は左側のライントレースの場合と同じとなる。
sub followline_R(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){ //stop_timeにいれた値を超過すると次のプログラムへ
if(SENSOR_1<black){ //blackすなわち20より小さい値を検知すると右へ旋回
rotate_right; //この動作が連続すると止まる
}else if(SENSOR_1<darkgray){ //darkgrayすなわち28より小さい値を検知すると右へ
turn_right; //この動作が連続すると止まる
}else if(SENSOR_1>lightdark){ //lightdrayすなわち40より大きい値を検知すると左へ曲がる
turn_left; //この動作中はライントレースし続ける
t0=CurrentTick();
}else if(SENSOR_1<center){ //centerすなわち35より小さい値を検知すると直進する
go_straight; //この動作中はライントレースし続ける
t0=CurrentTick();
}else{ //whiteすなわち50より大きい値を検知すると左へ旋回
rotate_left; //この動作中はライントレースし続ける
t0=CurrentTick();
}
}
Off(OUT_BC);
Wait(1000);
}
又、コースの途中のkからLに向かい、Lで止まるプログラミングを考えた結果、~
右側のライントレースで「白」と「白の境目」の�△鉢い瞭虻遒鯱�続で行うと~
止まるプログラミングが完成した。
この原理は左側のライントレースの場合と同じとなる。
この場合else if(SENSOR_1>lightdark) とelseに~
t0=CurrentTick();が入っておらずlightdrayすなわち40より大きい値、whiteすなわち50より大きい値~
を検知した時間がstop_timeの値の時間分を超過した場合にはwhileの動作を停止し、次の動作であるOff(OUT_BC);Wait(1000);~
を実行し、ロボットは1秒間止まる。
#ref(2019a/Member/Gouki/Mission2/Inked2019a-mission23_LI.jpg,70%);
sub followline_R2(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){ //stop_timeにいれた値を超過すると次のプログラムへ
if(SENSOR_1<black){ //blackすなわち20より小さい値を検知すると右へ旋回
rotate_right; //この動作中はライントレースし続ける
t0=CurrentTick();
}else if(SENSOR_1<darkgray){ //darkgrayすなわち28より小さい値を検知すると右へ
turn_right; //この動作中はライントレースし続ける
t0=CurrentTick();
}else if(SENSOR_1>lightdark){ //lightdrayすなわち40より大きい値を検知すると左へ曲がる
turn_left; //この動作が連続すると止まる
}else if(SENSOR_1<center){ //centerすなわち35より小さい値を検知すると直進する
go_straight2; //この動作中はライントレースし続ける
t0=CurrentTick();
}else{ //whiteすなわち50より大きい値を検知すると左へ旋回
rotate_left; //この動作が連続すると止まる
}
}
Off(OUT_BC);
Wait(2000);
}
**交差点横断 [#z69f3aff]
交差点を認識した後、直進、左折、右折の動作をしなければならない。~
そこで私たちは、ある値を検知するまで一定の動作を行い続けるプログラミングを作った。
○直進~
28より小さい値を検知している時は直進し、~
28より大きい値を検知したら止まる。
→黒い線上では直進
sub Blackto_White()
{
while(SENSOR_1<darkgray){ //darkdrayすなわち28より小さい値を検知すると直進する
OnFwd(OUT_BC,15);
}
Off(OUT_BC);
}
○右折~
40より小さい値を検知している時は右折し、~
40より大きい値を検知したら止まる。
→黒い戦場では右折
sub Blackto_White_R()
{
while(SENSOR_1<lightgray){ //lightdrayすなわち40より小さい値を検知すると右へ旋回
OnFwd(OUT_C,20);
OnRev(OUT_B,20);
}
Off(OUT_BC);
}
○左折~
40より小さい値を検知している時は左折し、~
40より大きい値を検知したら止まる。
→黒い戦場では左折
sub Blackto_White_L()
{
while(SENSOR_1<lightgray){ //lightdrayすなわち40より小さい値を検知すると左へ旋回
OnFwd(OUT_B,20);
OnRev(OUT_C,20);
}
Off(OUT_BC);
}
**ボール [#m8834b2f]
今秋の課題ではコースの途中でボールをつかみ、~
ボールを運んで、最後にゴールしなければいけないので~
つかむためのプログラムとゴールするためのプログラムを作成する。
***ボールをとるためのプログラム [#e0f200a7]
#define catch OnRev(OUT_A,25);Wait(500);Off(OUT_A);
***ボールを離し、ゴールするためのプログラム [#da74ff35]
ゴールする方法は、ボールを離した際に本体でコツンと押し出すというものだ。~
そのため最後の動作の出力は大幅に上げてある。~
#define release OnFwd(OUT_A,25);Wait(500);Off(OUT_A);
#define osidasi OnFwd(OUT_BC,100);Wait(100);Off(OUT_BC);
***ボールをとった後 [#uc47bf2f]
ボールをとったらある程度左に旋回させ、右側のライントレースにつなげるようにする。
#define turn OnFwd(OUT_B,25);OnRev(OUT_C,25);Wait(1500);Off(OUT_BC);
*コースを動く流れ [#f050659c]
最終的には下記のような流れで動作を行う。
#ref(2019a/Member/Gouki/Mission2/Inked2019a-mission234_LI.jpg,70%);
task main()
{
SetSensorLight(S1);
followline_L(200); //1
Blackto_White(); //2
followline_L(150); //3
Blackto_White_R(); //4
followline_R(200); //5
Blackto_White_R(); //6
followline(150); //7
Blackto_White_R(); //8
followline(150); //9
Blackto_White_R(); //10
followline(150); //11
Blackto_White(); //12
followline_R2(200); //13
catch; //ボールをつかむ
turn; //左に旋回する
followline_R(150); //14
Blackto_White(); //15
followline_R(150); //16
Blackto_White_L(); //17
followline_R(150); //18
release; //ボールを離す
osidasi; //ゴールする
}
*全体のプログラム [#t0578dcf]
#define turn_right OnFwd(OUT_C,25);OnRev(OUT_B,15);
#define turn_left OnFwd(OUT_B,25);OnRev(OUT_C,15);
#define rotate_right OnFwd(OUT_C,20);OnRev(OUT_B,20);
#define rotate_left OnFwd(OUT_B,20);OnRev(OUT_C,20);
#define go_straight OnFwd(OUT_BC,20);
#define go_straight2 OnFwd(OUT_BC,15);
#define turn OnFwd(OUT_B,25);OnRev(OUT_C,25);Wait(1500);Off(OUT_BC);
#define catch OnRev(OUT_A,25);Wait(500);Off(OUT_A);
#define release OnFwd(OUT_A,25);Wait(500);Off(OUT_A);
#define osidasi OnFwd(OUT_BC,100);Wait(100);Off(OUT_BC);
#define black 20
#define white 50
#define lightgray 40
#define darkgray 28
#define center 35
sub followline_L(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){
if(SENSOR_1<black){
rotate_left;
}else if(SENSOR_1<darkgray){
turn_left;
}else if(SENSOR_1>lightdark){
turn_right;
t0=CurrentTick();
}else if(SENSOR_1<center){
go_straight;
t0=CurrentTick();
}else{
rotate_right;
t0=CurrentTick();
}
}
Off(OUT_BC);
Wait(1000);
}
sub followline_R(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){
if(SENSOR_1<black){
rotate_right;
}else if(SENSOR_1<darkgray){
turn_right;
}else if(SENSOR_1>lightdark){
turn_left;
t0=CurrentTick();
}else if(SENSOR_1<center){
go_straight;
t0=CurrentTick();
}else{
rotate_left;
t0=CurrentTick();
}
}
Off(OUT_BC);
Wait(1000);
}
sub followline_R2(int stop_time)
{
long t0=CurrentTick();
while(CurrentTick()-t0<stop_time){
if(SENSOR_1<black){
rotate_right;
t0=CurrentTick();
}else if(SENSOR_1<darkgray){
turn_right;
t0=CurrentTick();
}else if(SENSOR_1>lightdark){
turn_left;
}else if(SENSOR_1<center){
go_straight2;
t0=CurrentTick();
}else{
rotate_left;
}
}
Off(OUT_BC);
Wait(2000);
}
sub Blackto_White()
{
while(SENSOR_1<darkgray){
OnFwd(OUT_BC,15);
}
Off(OUT_BC);
}
sub Blackto_White_R()
{
while(SENSOR_1<lightgray){
OnFwd(OUT_C,20);
OnRev(OUT_B,20);
}
Off(OUT_BC);
}
sub Blackto_White_L()
{
while(SENSOR_1<lightgray){
OnFwd(OUT_B,20);
OnRev(OUT_C,20);
}
Off(OUT_BC);
}
task main()
{
SetSensorLight(S1);
followline_L(200);
Blackto_White();
followline_L(150);
Blackto_White_R();
followline_R(200);
Blackto_White_R();
followline(150);
Blackto_White_R();
followline(150);
Blackto_White_R();
followline(150);
Blackto_White();
followline_R2(200);
catch;
turn;
followline_R(150);
Blackto_White();
followline_R(150);
Blackto_White_L();
followline_R(150);
release;
osidasi;
}
*まとめ [#y2be8016]
今回の課題では、ミスをせずきちんと完走させ、ゴールすることが出来た。~
ロボットの機体としての出来もよくきちんと走ってくれたが、所々電池のせいなのか~
動きが鈍くなる時があった。
結果だけを見ると良かったものの、まだプログラミングにかける時間が長く~
余計なプログラムもある。
今々考えてみると、途中の左旋回はいらなくて、そのままライントレース~
させればプログラムがもっと短くなると思った。~
まだまだ、プログラムの面で余計なところがあると思うので、~
次の課題ではそのようなミスを減らして、簡潔でよりよいプログラムに~
仕上げられるようにしたいと思う。