目次

走行パターン生成

 カメラから画像データを入力し、センサーデータを生成後
 走行パターンを作ります。

 無計画にセンサーデータを判断しても、スパゲッティコードに
 なるので、次の3状態に分割して、動作を解析します。

 考えやすくするために、センサーデータを1個とします。

 NORMAL
  ラインに沿いながらの移動です。
  常にラインがあるので、直線、ワインディングコースを走行します。

 CRANK
  クランク指示の白線を検出し、クランクで90度曲がり
  再びラインに沿って走行するまでの状態です。

 LANE
  車線変更指示の片側白線を検出し、ラインなし路面を移動し
  再びラインに沿って走行するまでの状態です。

 この3状態の中で、どう走るのかを考えます。

 状態を切り替えるには、条件が必要です。
 その条件を考えて、状態を切り替えると下図になります。



 大雑把ですが、この状態遷移を基に、ファームウエアを作成すると
 考えやすくなります。

 3状態を、さらに細かく分けてみます。


NORMAL

 NORMALは、ラインに沿いながら移動します。  ラインを忠実に追って、走行するが基本です。  はじめに、NORMALから他の状態にうつる条件を考えます。  NORMAL→CRANK   路面全体に広がる白線(all white)を検出したなら、CRANKに状態を変えます。  NORMAL→LANE   路面中央から左に引いた白線(left white)か右に引いた白線(right white)を   検出したなら、LANEに状態を変えます。  状態遷移図のままでは、コードにできないので、シーケンスを書きます。
  1. センサーデータ取得
  2. センサーデータがall whiteなら、CRANKに遷移
  3. センサーデータがleft whiteなら、LANEに遷移
  4. センサーデータがright whiteなら、LANEに遷移
  5. NORMAL処理
  6. 1に戻る
 NORMALでは、直線、ワインディングコース走行です。  直線と直線でない場合、どのように動くか考えます。  センサーデータが、どんな状態を示すかリストします。  コース上を滑らかに移動する場合は、もう少し状態を増やさ  なければなりませんが、逸脱してコースから転落しなければ  よいと考えて、7つの状態にします。  それぞれの状態で、どのように制御するか決めます。  center検出   左右モータの回転数を上げて移動   1秒経過後、もとの回転数に戻す  little left検出   右モータの回転数を5%下げて移動   1秒経過後、もとの回転数に戻す  left検出   右モータの回転数を10%下げて移動   1秒経過後、もとの回転数に戻す  big left検出   右モータの回転数を20%下げて移動   1秒経過後、もとの回転数に戻す  little right検出   左モータの回転数を5%下げて移動   1秒経過後、もとの回転数に戻す  right検出   左モータの回転数を10%下げて移動   1秒経過後、もとの回転数に戻す  big right検出   左モータの回転数を20%下げて移動   1秒経過後、もとの回転数に戻す  まとめると、以下となります。  処理内容から、次の関数が必要になります。  ぞれぞれの内容をまとめて、switchで記述します。 dtim = 1000 ; state = 0 ; while (1) { /* get sensor data */ sensor_data = get_sensor(); /* state machine */ switch ( state ) { case 0 : /* judge */ state = 0 ; if ( sensor_data == ALL_WHITE ) { state = 100 ; } if ( sensor_data == LEFT_WHITE ) { state = 200 ; } if ( sensor_data == RIGHT_WHITE ) { state = 200 ; } if ( sensor_data == CENTER ) { state = 10 ; } if ( sensor_data == LITTLE_LEFT ) { state = 20 ; } if ( sensor_data == LEFT ) { state = 30 ; } if ( sensor_data == BIG_LEFT ) { state = 40 ; } if ( sensor_data == LITTLE_RIGHT ) { state = 50 ; } if ( sensor_data == RIGHT ) { state = 60 ; } if ( sensor_data == BIG_RIGHT ) { state = 70 ; } break ; /* CENTER */ case 10 : state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left <<= 3 ; dc_left /= 10 ; dc_right <<= 3 ; dc_right /= 10 ; update_motor(dc_left,dc_left); break ; /* LITTLE_LEFT (move center) */ case 20 : state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left *= 95 ; dc_left /= 100 ; update_motor(dc_left,dc_left); break ; /* LEFT (move center) */ case 30 : state = 80 ; do_left = dc_left ; do_right = dc_right ; do_right *= 9 ; do_right /= 10 ; update_motor(dc_left,dc_left); break ; /* BIG_LEFT (move center) */ case 40 : state = 80 ; do_left = dc_left ; do_right = dc_right ; do_right <<= 3 ; do_right /= 10 ; update_motor(dc_left,dc_left); break ; /* LITTLE_RIGHT (move center) */ case 50 : state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left *= 95 ; dc_left /= 100 ; update_motor(dc_left,dc_left); break ; /* RIGHT (move center) */ case 60 : state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left *= 9 ; dc_left /= 10 ; update_motor(dc_left,dc_left); break ; /* BIG_RIGHT (move center) */ case 70 : state = 80 ; do_left = dc_left ; do_right = dc_right ; do_left <<= 3 ; do_left /= 10 ; update_motor(dc_left,dc_left); break ; /* delay */ case 80 : state = 90 ; delay_ms( dtim ) ; break ; /* return */ case 90 : state = 0 ; dc_left = do_left ; dc_right = do_right ; break ; /* CRANK */ case 100 : state = 0 ; break ; /* LANE */ case 200 : state = 0 ; break ; }

CRANK

 CRANK状態での走行を考えます。  右クランクの移動シーケンスは、次のようにします。
  1. 右クランク(crank_right)を検出するまで、低速直線走行
  2. 右に60度回転
  3. 中央白線(center)を検出するまで、右に回転
  4. 1秒低速直線走行
  5. NORMALに戻る
 右クランク走行と同様に、左クランクの移動シーケンスを考えます。
  1. 左クランク(crank_left)を検出するまで、低速直線走行
  2. 左に60度回転
  3. 中央白線(center)を検出するまで、左に回転
  4. 1秒低速直線走行
  5. NORMALに戻る
 クランクまでは、低速で移動し、クランクを見つけたなら、右か左に  大きく回転します。  その後、centerを見つけるまで、少しずつ回転します。  移動シーケンスから、回転が必要になります。  回転をrotateで表現すると、次のステートマシンを実行すれば  CRANK状態の移動ができます。 /* slow move */ case 100 : state = 100 ; update_motor(20,20); delay_ms(1000); if ( sensor_data == CRANK_RIGHT ) { state = 110 ; angle0 = -60 ; angle1 = -5 ; } if ( sensor_data == CRANK_LEFT ) { state = 110 ; angle0 = 60 ; angle1 = 5 ; } break ; /* rotate */ case 110 : state = 120 ; rotate(angle0); delay_ms(3000); break ; /* rotate (bit by bit) */ case 120 : state = 120 ; if ( sensor_data == CENTER ) { state = 130 ; } else { rotate(angle1) ; delay_ms(100); } break ; /* slow move */ case 130 : state = 140 ; update_motor(20,20); delay_ms(1000); break ; /* return NORMAL */ case 150 : state = 0 ; break ;

LANE

 LANE状態での走行を考えます。  右の車線変更移動シーケンスは、次のようにします。
  1. 黒路面(all_black)を検出するまで、低速直線走行
  2. 右に30度回転
  3. 中央白線(center)を検出するまで、中速直線走行
  4. 左に30度回転
  5. 1秒低速直線走行
  6. NORMALに戻る
 右車線変更と同様に、左車線変更の移動シーケンスを考えます。
  1. 黒路面(all_black)を検出するまで、低速直線走行
  2. 左に60度回転
  3. 中央白線(center)を検出するまで、中速直線走行
  4. 右に30度回転
  5. 1秒低速直線走行
  6. NORMALに戻る
 all_blackまでは、低速で移動し、all_blackを見つけたなら、右か左に  小さく回転します。  回転後、centerを見つけるまで、中速で直線走行します。 NORMALからLANEに状態遷移するとき、どちらに白線があったのかを  記憶しておきます。  次のステートマシンを実行すると、LANE状態の移動ができます。 case 200 : /* slow move */ state = 200 ; update_motor(20,20); delay_ms(1000); if ( sensor_data == ALL_BLACK ) { state = 210 ; angle0 = -30 ; angle1 = 30 ; if ( lane_direction == LANE_LEFT ) { angle0 *= -1 ; angle1 *= -1 ; } } break ; case 210 : /* rotate */ state = 220 ; rotate(angle0); delay_ms(1000); break ; case 220 : /* move */ state = 220 ; if ( sensor_data == CENTER ) { state = 230 ; } else { update_motor(40,40); delay_ms(1000); } break ; case 230 : /* roate (reverse) */ state = 240 ; rotate(angle1); delay_ms(1000); break ; case 240 : /* slow move */ state = 250 ; update_motor(20,20); delay_ms(1000); break ; case 250 : /* return NORMAL */ state = 0 ; break ;

ソースコード

 まとめると、走行パターン生成は、以下となります。 UWORD state ; UBYTE sensor_data ; UWORD dtim ; UBYTE dc_left,dc_right; UBYTE do_left,do_right; SBYTE angle0,angle1; UBYTE lane_direction ; dc_left = 30 ; dc_right = 30 ; angle0 = 0 ; angle1 = 0 ; state = 0 ; dtim = 1000 ; lane_direction = LANE_RIGHT ; while (1) { /* get sensor data */ sensor_data = get_sensor(); switch ( state ) { case 0 : /* judge */ state = 0 ; if ( sensor_data == ALL_WHITE ) { state = 100 ; } if ( sensor_data == LEFT_WHITE ) { state = 200 ; lane_direction = LANE_LEFT ; } if ( sensor_data == RIGHT_WHITE ) { state = 200 ; lane_direction = LANE_RIGHT ; } if ( sensor_data == CENTER ) { state = 10 ; } if ( sensor_data == LITTLE_LEFT ) { state = 20 ; } if ( sensor_data == LEFT ) { state = 30 ; } if ( sensor_data == BIG_LEFT ) { state = 40 ; } if ( sensor_data == LITTLE_RIGHT ) { state = 50 ; } if ( sensor_data == RIGHT ) { state = 60 ; } if ( sensor_data == BIG_RIGHT ) { state = 70 ; } break ; case 10 : /* CENTER */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left <<= 3 ; dc_left /= 10 ; dc_right <<= 3 ; dc_right /= 10 ; update_motor(dc_left,dc_left); break ; case 20 : /* LITTLE_LEFT (move center) */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_right *= 95 ; dc_right /= 100 ; update_motor(dc_left,dc_left); break ; case 30 : /* LEFT (move center) */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_right *= 9 ; dc_right /= 10 ; update_motor(dc_left,dc_left); break ; case 40 : /* BIG_LEFT (move center) */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_right <<= 3 ; dc_right /= 10 ; update_motor(dc_left,dc_left); break ; case 50 : /* LITTLE_RIGHT (move center) */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left *= 95 ; dc_left /= 100 ; update_motor(dc_left,dc_left); break ; case 60 : /* RIGHT (move center) */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left *= 9 ; dc_left /= 10 ; update_motor(dc_left,dc_left); break ; case 70 : /* BIG_RIGHT (move center) */ state = 80 ; do_left = dc_left ; do_right = dc_right ; dc_left <<= 3 ; dc_left /= 10 ; update_motor(dc_left,dc_left); break ; case 80 : /* delay */ state = 90 ; delay_ms( dtim ) ; break ; case 90 : /* return */ state = 0 ; dc_left = do_left ; dc_right = do_right ; break ; case 100 : /* slow move */ state = 100 ; update_motor(20,20); delay_ms(1000); if ( sensor_data == CRANK_RIGHT ) { state = 110 ; angle0 = -60 ; angle1 = -5 ; } if ( sensor_data == CRANK_LEFT ) { state = 110 ; angle0 = 60 ; angle1 = 5 ; } break ; case 110 : /* rotate */ state = 120 ; rotate(angle0); delay_ms(3000); break ; case 120 : /* rotate (bit by bit) */ state = 120 ; if ( sensor_data == CENTER ) { state = 130 ; } else { rotate(angle1) ; delay_ms(100); } break ; case 130 : /* slow move */ state = 140 ; update_motor(20,20); delay_ms(1000); break ; case 150 : /* return NORMAL */ state = 0 ; break ; case 200 : /* slow move */ state = 200 ; update_motor(20,20); delay_ms(1000); if ( sensor_data == ALL_BLACK ) { state = 210 ; angle0 = -30 ; angle1 = 30 ; if ( lane_direction == LANE_LEFT ) { angle0 *= -1 ; angle1 *= -1 ; } } break ; case 210 : /* rotate */ state = 220 ; rotate(angle0); delay_ms(1000); break ; case 220 : /* move */ if ( sensor_data == CENTER ) { state = 230 ; } else { update_motor(40,40); delay_ms(1000); } break ; case 230 : /* roate (reverse) */ state = 240 ; rotate(angle1); delay_ms(1000); break ; case 240 : /* slow move */ state = 250 ; update_motor(20,20); delay_ms(1000); break ; case 250 : /* return NORMAL */ state = 0 ; break ; } }
目次

inserted by FC2 system