- 追加された行はこの色です。
- 削除された行はこの色です。
目次
#contents
*課題2:黒い線上を動くロボット [#s2a9e895]
次のような周回コース(黒い線)を動くロボットを作成せよ。
-通常の交差点が2箇所以上ある
-ロータリー型の交差点が1箇所以上ある (ロータリーでは反時計まわりに進む)
-直角に曲がるコーナーおよびそのコーナーをショートカットするコース(点線)が存在する
-急なヘアピンカーブが1箇所以上ある
-スタート地点に目印がある
-黒い線の幅は15〜20mm程度
センサー、モーターはいくつ使ってもよい。プログラムは次の2つを作成すること。
1. 直角のコーナーを通る
2. 直角のコーナーを通らない(近道する)
ただし互いに逆方向に周回すること。
*メンバー紹介 [#qf933802]
-イシイ(近道担当)
-ゆきち(直角コーナー担当)
*課題 [#q735ffe3]
**コースについて [#e3f78d38]
先生が例として挙げたコースとほとんど同じコースを作った。
コースの線の幅は15mmで統一した。
●コースの概要
#ref(course.jpg)
-イシイのコース
以下は、メンバーのロボットがたどるコース。
●イシイ(近道担当)のコース
#ref(course_ishii.jpg)
-ゆきちのコース
●ゆきち(直角コーナー担当)のコース
#ref(course_yukichi.JPG)
**ロボットについて [#ic2a75be]
**問題点について [#t0bab1b1]
ロボットは四輪の車体に光センサーを取り付けたシンプルな作りになった。
●全体
#ref(trace_robot.JPG)
●光センサー
シンプル、と言っても、光センサーの取り付け方には注意した。
#ref(sensor.JPG)
3センチという幅は組み立ての際に偶然たどり着いた値だが、広すぎず狭すぎない幅だった。広すぎればラインに対する反応が遅れ、カーブを曲がりきれない。また、狭すぎればロボットがコースの曲線に過剰に反応してしまい、一周を回るのにかかる時間が長くなると予想できる。
もう一点、光センサーとロボットを旋回させたときの回転軸との距離に注意した。
#ref(trace_robot_side.JPG)
この距離が長ければ、わずかに旋回しただけでも光センサーが大きく動くことになってしまい、急カーブでラインを追いかけることが難しくなると考えた。その点を意識してロボットを作った。
*プログラム [#o770212f]
**イシイ [#d645274a]
#ref(course_ishii.jpg)
#define go(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C); //直進
#define turn_r(t) OnFwd(OUT_A);OnRev(OUT_C);Wait(t);Off(OUT_A+OUT_C); //右旋回
#define turn_l(t) OnFwd(OUT_C);OnRev(OUT_A);Wait(t);Off(OUT_A+OUT_C); //左旋回
#define THRESHOLD 45 //閾値
task main()
{
SetSensor(SENSOR_1,SENSOR_LIGHT);
SetSensor(SENSOR_3,SENSOR_LIGHT);
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=500) //5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10); //センサー1が反応したら0.1秒左旋回
}
if(SENSOR_3<THRESHOLD)
{
go(20); //センサー3が反応したら0.2秒直進
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=800) //8秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_3<THRESHOLD)
{
turn_r(10); //センサー3が反応したら0.1秒右旋回
}
if(SENSOR_1<THRESHOLD)
{
go(20); //センサー1が反応したら0.2秒直進
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=150) //1.5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_3<THRESHOLD)
{
turn_r(10)
}
if(SENSOR_1<THRESHOLD)
{
go(50);
turn_r(70);
}
}
//1回目のロータリー
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=350) //3.5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10) //センサー1が反応したら0.1秒左旋回
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=250) //2.5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10); //センサー1が反応したら0.1秒左旋回
}
if(SENSOR_3<THRESHOLD)
{
go(50)
turn_r(60); //センサー3が反応したら
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=550) //5.5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_3<THRESHOLD)
{
turn_r(20);
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=300) //3秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_3<=THRESHOLD)
{
turn_r(10);
}
if(SENSOR_1<=THRESHOLD)
{
go(50);
turn_r(80);
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=350) //3.5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10)
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=250) //2.5秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10);
}
if(SENSOR_3<THRESHOLD)
{
go(50)
turn_r(100);
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=400) //4秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_3<=THRESHOLD)
{
turn_r(10);
}
if(SENSOR_1<=THRESHOLD)
{
go(25);
OnFwd(OUT_A);
Wait(20);
Off(OUT_A);
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=600) //6秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_3<=THRESHOLD)
{
OnRev(OUT_A+OUT_C);
Wait(10);
Off(OUT_A+OUT_C);
turn_r(20);
}
}
ClearTimer(0); //タイマーをリセット
while(FastTimer(0)<=400) //4秒後まで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10);
}
if(SENSOR_3<THRESHOLD)
{
go(25);
}
}
while(SENSOR_3<THRESHOLD) //センサー3が反応するまで繰り返し
{
OnFwd(OUT_A+OUT_C);
if(SENSOR_1<THRESHOLD)
{
turn_l(10);
}
}
Off(OUT_A+OUT_C);
}
**ゆきち [#i0f9386d]
#ref(course_yukichi.JPG)
-右カーブと左カーブのそれぞれを曲がるだけならば必要なセンサーがどちらか一方であることを考え、交差点などでのコースの誤認をかなり少なくできた。
-右カーブ、左カーブ、ロータリーを移動するプログラムのサブルーチンを定義し、プログラムを短くできた。
-タイマーをアバウトに使い、さらに光センサーによる判定を組み合わせることで、ライントレースの精度を高めることができた。
#define GO(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C); //前にt秒進む
#define THRESHOLD 45 //明かりを判定する基準値。
#define THRESHOLD 45 //明るさを判定する基準値。
sub RIGHT_CURVE() //コースが右にカーブしているときのプログラム
sub RIGHT_CURVE() //コースが右にカーブしているときのプログラム
{ //右側のセンサー3のみを考慮します。
if (SENSOR_3>THRESHOLD)//センサーに反応がなければ直進。
{
OnFwd(OUT_A+OUT_C);
}
if (SENSOR_3<THRESHOLD)//センサーに反応があれば、右にカーブします。
{
Off(OUT_C);
OnFwd(OUT_A);
}
}
sub LEFT_CURVE() //コースが左にカーブしているときのプログラム
sub LEFT_CURVE() //コースが左にカーブしているときのプログラム
{ //左側のセンサー1のみを考慮します。
if (SENSOR_1>THRESHOLD)//センサーに反応がなければ直進。
if (SENSOR_1>THRESHOLD) //センサーに反応がなければ直進。
{
OnFwd(OUT_A+OUT_C);
}
if (SENSOR_1<THRESHOLD)//センサーに反応があれば、左にカーブします。
if (SENSOR_1<THRESHOLD) //センサーに反応があれば、左にカーブします。
{
Off(OUT_A);
OnFwd(OUT_C);
}
}
sub ROTARY() //ロータリーのプログラム。
{ //ロータリーに入った時点から、このプログラムを使用します。
sub ROTARY() //ロータリーのプログラム。
{ //ロータリーに入った時点から、このプログラムを使用します。
GO(35);
OnFwd(OUT_A);OnRev(OUT_C);Wait(20)//ロボットの回転の中心がロータリーの黒線上に来るように移動。
OnFwd(OUT_A);OnRev(OUT_C);Wait(20) //ロボットの回転の中心がロータリーの黒線上に来るように移動。
while(SENSOR_1>THRESHOLD)
{
OnFwd(OUT_A);
OnRev(OUT_C);
}
Off(OUT_A+OUT_C);
OnFwd(OUT_A+OUT_C); //この時点で、ロータリーの黒線が二つのセンサーの間にあります。
ClearTimer(0);
while(FastTimer(0)<400) //4秒という時間は、一つ目の分岐を通りすぎるのに十分な時間です。
{
LEFT_CURVE(); //その間、ロータリーを左カーブとみなすことができます。
LEFT_CURVE(); //その間、ロータリーを左カーブとみなすことができます。
}
while(SENSOR_3>THRESHOLD) //4秒以降に3センサーが黒線を感知するとき、ロータリーの出口に達したことになります。
{
LEFT_CURVE(); //それまでは、ロータリーを左カーブとみなします。
}
Off(OUT_A+OUT_C);GO(35);
OnFwd(OUT_A);OnRev(OUT_C);Wait(20);//入ったときと同様に、ロボットの回転の中心がロータリーの黒線上にあるように移動します。
OnFwd(OUT_A);OnRev(OUT_C);Wait(20); //入ったときと同様に、ロボットの回転の中心がロータリーの黒線上にあるように移動します。
while(SENSOR_1>THRESHOLD)
{
OnFwd(OUT_A);OnRev(OUT_C);
} //この時点でロータリーの黒線は二つのセンサーの間にあります。
} //ロータリーを抜けました。
} //この時点でロータリーから伸びる黒線が二つのセンサーの間にあります。
} //ロータリーを抜けました。
task main()
{
SetSensor(SENSOR_1,SENSOR_LIGHT);
SetSensor(SENSOR_3,SENSOR_LIGHT);//センサー1、3を光センサーと定義。
SetSensor(SENSOR_3,SENSOR_LIGHT); //センサー1、3を光センサーと定義。
ClearTimer(0);
while(FastTimer(0)<=330) //最初はなだらかな右カーブ。
while(FastTimer(0)<=330) //最初はなだらかな右カーブ。
{
RIGHT_CURVE();
}
while(FastTimer(0)<=850) //ここは左の急カーブなので、別のプログラムを使います。
while(FastTimer(0)<=850) //ここは左の急カーブなので、別のプログラムを使います。
{
if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD))
{
OnFwd(OUT_A+OUT_C);
}
if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) //反対のタイヤを逆回転させることで、急カーブを回りきります。
if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD))
//反対のタイヤを逆回転させることで、急カーブを回りきります。
{
OnRev(OUT_A);
OnFwd(OUT_C);
}
}
while(FastTimer(0)<=1100) //緩やかな左カーブ
while(FastTimer(0)<=1100) //緩やかな左カーブ
{
LEFT_CURVE();
}
while(SENSOR_3>THRESHOLD) //ロータリーまで、左カーブが続きます。
while(SENSOR_3>THRESHOLD) //ロータリーまで、左カーブが続きます。
{
LEFT_CURVE();
}
Off(OUT_A+OUT_C); //ロータリー入り口で停止。
Off(OUT_A+OUT_C); //ロータリー入り口で停止。
ROTARY;
ClearTimer(0);
while(FastTimer(0)<300)
{
LEFT_CURVE();
}
GO(50); //近道を無視します。
GO(50); //近道を無視します。
while(FastTimer(0)<700||SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)//直角カーブを回るため、急カーブのときと同じプログラムを使用。
{ //ロータリーを感知するまでこのプログラムを継続します。
while(FastTimer(0)<700||SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
//直角カーブを回るため、急カーブのときと同じプログラムを使用。
{ //ロータリーを感知するまでこのプログラムを継続します。
if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD))
{
OnFwd(OUT_A+OUT_C);
}
if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD))
{
OnRev(OUT_A);
OnFwd(OUT_C);
}
}
Off(OUT_A+OUT_C); //ロータリー入り口。
ROTARY;
ClearTimer(0);
while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
{
LEFT_CURVE();
}
GO(15); //交差点を無視して進みます。
while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
{
LEFT_CURVE();
}
GO(10); //交差点を無視。
GO(10); //交差点を無視。
while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)//「どちらかが白である間、継続」つまり「ゴールの黒線を感知するまで継続」
while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
//「どちらかが白である間、継続」つまり「ゴールの黒線を感知するまで継続」
{
if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD))
{
OnFwd(OUT_A+OUT_C);
}
if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD))
{
OnRev(OUT_A);OnFwd(OUT_C);
}
if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD))
{
OnRev(OUT_C);OnFwd(OUT_A);
}
}
Off(OUT_A+OUT_C); //ゴール
Off(OUT_A+OUT_C); //ゴール
}
*感想 [#m39f9cd2]
-イシイ~
タイマーを上手く利用して動かすことができたが、時間の調整がとても大変だった。
-ゆきち~
*反省・感想 [#m39f9cd2]
-タイマーを上手く利用して動かすことができたが、時間の調整がとても大変だった。
-論理式を有効に活用することでコースの判定の精度を高めることができた。
-プログラムを短くするのが大変だった。
-プログラムには試行錯誤を繰り返したが、ロボットの改良はほとんどしなかった。先輩方のホームページを見ると、「光センサーと回転軸の距離」を詰めるためにロボットを大幅に改造したものもあり、次回の課題ではロボットとプログラムの二面から課題にアプローチしたいと感じた。
*コメントをお願いします [#d155cfe7]
#comment