- 追加された行はこの色です。
- 削除された行はこの色です。
[[2017a/Member]]
#contents
* 課題内容 [#mb855a0c]
今回の課題は、光センサを使用して図のコース上を指定の経路で走るという内容である。
~ 詳しい内容は[[2017a/Mission2]]を参照してほしい。
#ref(./課題2 コース.jpg,80%,コースの図)
** 走行コース [#cf89eeb5]
「E地点直進コース」と「E地点右折コース」の内、「E地点右折コース」を走るロボットを作成したため、以下の順番で走行するようになっている。
~ E→P→Q→R→T→T→H→G→S→P→Q→F→E→A
* ロボット本体 [#p0da3634]
ロボット本体はできるだけシンプルに、かつコンパクトになるようにした。
#ref(./ロボット全体.jpg,8%,ロボット全体の写真)
ロボット本体を組み立てるのに当たって、できるだけ小回りがきくようなロボットにしようと考えた。そこで、タイヤの間隔を極力狭くし、モーター2つとギアの幅だけにすることで旋回半径をできるだけ小さくしている。
~ また、はじめはセンサーとタイヤとの距離を少し遠く配置していたのだが、必ずHーG地点間のS字カーブやEーF地点間のカーブで旋回しきれずにコースアウトしてしまい、正しくラインをトレースしてくれなかった。そこで、センサとタイヤの距離をできるだけ短くし、より正かくに黒線に沿って走行できるようにもしている。
#ref(./タイヤ・センサ距離.jpg,80%,タイヤとセンサの距離の説明)
* プログラム [#d31854c8]
** 定数・マクロ定義・グローバル変数 定義 [#z84376a1]
/*---------- 定数・マクロ 定義 -----------*/
#define LINE_BLACK 38 //黒
#define THRESHOLD_LOW 40 //閾値最小(黒より)
#define THRESHOLD_HIGH 47 //閾値最大(白より)
#define LINE_WHITE 49 //白
#define FOWORD OnFwd(OUT_AC); //直進
#define BACK OnRev(OUT_AC); //後退
#define STOP Off(OUT_AC); //停止
#define TURN_LEFT OnFwd(OUT_C); OnRev(OUT_A); //左旋回
#define TURN_RIGHT OnFwd(OUT_A); OnRev(OUT_C); //右旋回
#define CURVE_LEFT OnFwd(OUT_C); Off(OUT_A); //左折
#define CURVE_RIGHT OnFwd(OUT_A); Off(OUT_C); //右折
#define TIME_MAX_S 26 //直線走行時の黒線判定までの時間
#define TIME_MAX_CO 30 //カーブ(外回り)走行時の黒線判定までの時間
#define TIME_MAX_CI 33 //カーブ(内回り)走行時の黒線判定までの時間
#define TIME_MAX_N 26 //T→G間以外での交差点判定までの時間
#define TIME_MAX_TG 33 //T→G間での交差点判定までの時間
/*----------- グローバル変数 定義 ----------*/
int timer = 0; //タイマー0 格納用変数
int timer = 0; //黒反応時間
int time_max = 0; //交差点判定用
ライントレースをする際に、黒線と白線が境界できっちり分かれているわけではなく、どちらでもない中間の範囲が存在する。そこで、どこからが黒でどこからが白なのか、またそのどちらでもない範囲で中央はどこになるのかを"LINE_BLACK"、"THRESHOLD_LOW"、"THRESHOLD_HIGH"、"LINE_WHITE"という4つの値を設定し、黒から白の間を5つに分けることで判別している。
#ref(./閾値説明図.jpg,30%,閾値説明図)
** サブルーチン [#ye8c85a8]
サブルーチンは、黒線をトレースするためのものを"Follow_Line_R()"と"Follow_Line_L()"として左右で設定している。
/*---------- ラインの右側を走行 ----------*/
sub Follow_Line_R()
{
while(timer < time_max){
if(SENSOR_2 > LINE_WHITE){
TURN_LEFT;
ClearTimer(0);
}
else if(SENSOR_2 > THRESHOLD_HIGH){
CURVE_LEFT;
ClearTimer(0);
}
else if(SENSOR_2 > THRESHOLD_LOW){
FOWORD;
ClearTimer(0);
}
else if(SENSOR_2 > LINE_BLACK){
CURVE_RIGHT;
ClearTimer(0);
}
else{
TURN_RIGHT;
}
timer = FastTimer(0);
}
timer = 0;
}
/*---------- ライン左側を走行 ----------*/
sub Follow_Line_L()
{
while(timer < time_max){
if(SENSOR_2 > LINE_WHITE){
TURN_RIGHT;
ClearTimer(0);
}
else if(SENSOR_2 > THRESHOLD_HIGH){
CURVE_RIGHT;
ClearTimer(0);
}
else if(SENSOR_2 > THRESHOLD_LOW){
FOWORD;
ClearTimer(0);
}
else if(SENSOR_2 > LINE_BLACK){
CURVE_LEFT;
ClearTimer(0);
}
else{
TURN_LEFT;
}
timer = FastTimer(0);
}
timer = 0;
}
~ 閾値によって黒と白とその境目を5つに分けているため、それぞれの場所に応じて動作を設定している。光センサの値が"THRESHOLD_LOW"から"THREHOLD_HIGH"の間は、区分分けの中央になるため左右どちらのサブルーチンでも「直進」するようになっている。"THRESHOLD_LOW"より小さい場合と"THRESHOLD_HIGH"より大きい場合は左右で動作が逆になってはいるが、"LINE_BLACK"や"LINE_WHITE"を超えるまでは「タイヤを片方停止してのターン」、超えたら「片方は正転、反対側は逆転しての旋回」を行うようにしている。
#ref(./動作説明図.jpg,30%,動作説明図)
~ また、光センサの値が"LINE_BLACK"より小さい(黒色を検知している)間、タイマーで時間を計測し変数"timer"にその値を渡している。この"timer"を"time_max"(メインタスクで設定)を比較して大きい場合はループから抜けることで交差点を判断している。
** メインタスク [#w913d29c]
/*---------- メインタスク ----------*/
task main()
{
/* センサ・モータパワー 設定 */
SetSensor(SENSOR_2 , SENSOR_LIGHT);
SetPower(OUT_AC , 3);
/* 動作部分 */
// A→E ----------------------------------------
time_max = TIME_MAX_N;
Follow_Line_R();
// E地点 到達
// SOUND_UP & 右折
PlaySound(SOUND_UP);
TURN_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
// E→P ----------------------------------------
Follow_Line_R();
// P地点 到達 (一時停止)
// SOUND_DOWN & 左折
PlaySound(SOUND_DOWN);
STOP;
Wait(100);
TURN_LEFT;
until(SENSOR_2 > THRESHOLD_HIGH);
// P→Q ----------------------------------------
Follow_Line_L();
// Q地点 到達
// SOUND_DOWN & 直進(効率化のため右折による横断)
PlaySound(SOUND_UP);
CURVE_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
STOP;
// Q→R ----------------------------------------
Follow_Line_L();
// R地点 到達
// SOUND_UP & 左折
PlaySound(SOUND_UP);
TURN_LEFT;
until(SENSOR_2 > THRESHOLD_HIGH);
// R→T ----------------------------------------
Follow_Line_L();
// T地点 到達(一時停止)
// SOUND_DOWN & 直進
PlaySound(SOUND_DOWN);
STOP;
Wait(100);
FOWORD;
until(SENSOR_2 > THRESHOLD_HIGH);
// T→T ----------------------------------------
time_max = TIME_MAX_TG;
Follow_Line_L();
// T地点 到達(一時停止)
// SOUND_DOWN & 直進(ライン右側へ移動)
PlaySound(SOUND_DOWN);
STOP;
Wait(100);
CURVE_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
until(SENSOR_2 < THRESHOLD_LOW);
until(SENSOR_2 > THRESHOLD_HIGH);
// T→H ----------------------------------------
Follow_Line_R();
// H地点 到達
// SOUND_UP & 右折
PlaySound(SOUND_UP);
CURVE_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
// H→G ----------------------------------------
Follow_Line_R();
// G地点 到達
// SOUND_UP & 直進
PlaySound(SOUND_UP);
FOWORD;
until(SENSOR_2 > THRESHOLD_HIGH);
// G→S ----------------------------------------
time_max = TIME_MAX_N;
Follow_Line_L();
// S地点 到達(一時停止)
// SOUND_DOWN & 左折
PlaySound(SOUND_DOWN);
STOP;
Wait(100);
TURN_LEFT;
until(SENSOR_2 > THRESHOLD_HIGH);
// S→P ----------------------------------------
Follow_Line_L();
// P地点 到達
// SOUN_UP & 直進(効率化のために右折による横断)
PlaySound(SOUND_UP);
CURVE_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
// P→Q ----------------------------------------
Follow_Line_L();
// Q地点 到達
// SOUND_UP & 左折(ライン右側へ移動)
PlaySound(SOUND_UP);
CURVE_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
// Q→F ----------------------------------------
Follow_Line_R();
// F地点 到達
// SOUND_UP & 左折(直進によってライン横断)
PlaySound(SOUND_UP);
FOWORD;
until(SENSOR_2 > THRESHOLD_HIGH);
// F→E ----------------------------------------
Follow_Line_L();
// E地点 到達
//(直進による横断)
FOWORD;
until(SENSOR_2 > THRESHOLD_HIGH);
// E→A ----------------------------------------
Follow_Line_L();
// A地点 到達
// ライン横断後、A地点内で停止
PlaySound(SOUND_DOWN);
CURVE_RIGHT;
until(SENSOR_2 > THRESHOLD_HIGH);
FOWORD;
Wait(70);
STOP;
//ゴール
}
* まとめ [#x28c86bc]