目次

走行パターン作成

 MCR_VCマシンであるmugen2017は、6種の走行テートで移動します。



 カメラセンサーユニット(Game Boy Camera unit)から取得できるのは
 次の13種のセンサー情報。

 センサー情報と走行ステートを組み合わせると、移動に
 必要となる左右モータのDUTY比を決定できます。

 配列を利用して、走行ステートとセンサー情報に応じた
 DUTY比を格納して利用します。

 センサー情報は、0から12の数値になっているので
 配列の添字として利用すれば、DUTY比を取得できる
 ようにしてみました。

UBYTE nldx[13];
UBYTE nrdx[13];
UBYTE cldx[13];
UBYTE crdx[13];
UBYTE rldx[13];
UBYTE rrdx[13];
UBYTE lldx[13];
UBYTE lrdx[13];
UBYTE chldx[13];
UBYTE chrdx[13];
UBYTE blldx[13];
UBYTE blrdx[13];

void  init_road_array()
{
  /* NORMAL */
  *(nldx+ALL_BLACK)   = 10 ; *(nrdx+ALL_BLACK)   = 10 ;
  *(nldx+ALL_WHITE)   = 30 ; *(nrdx+ALL_WHITE)   = 30 ;
  *(nldx+LEFT_WHITE)  = 10 ; *(nrdx+LEFT_WHITE)  = 10 ;
  *(nldx+RIGHT_WHITE) = 10 ; *(nrdx+RIGHT_WHITE) = 10 ;
  *(nldx+CENTER)      = 50 ; *(nrdx+CENTER)      = 50 ;
  *(nldx+TINY_RIGHT)  = 50 ; *(nrdx+TINY_RIGHT)  = 55 ;
  *(nldx+RIGHT)       = 50 ; *(nrdx+RIGHT)       = 60 ;
  *(nldx+BIG_RIGHT)   = 50 ; *(nrdx+BIG_RIGHT)   = 65 ;
  *(nldx+TINY_LEFT)   = 55 ; *(nrdx+TINY_RIGHT)  = 50 ;
  *(nldx+LEFT)        = 60 ; *(nrdx+RIGHT)       = 50 ;
  *(nldx+BIG_LEFT)    = 65 ; *(nrdx+BIG_RIGHT)   = 50 ;
  *(nldx+BOTH_WHITE)  = 10 ; *(nrdx+BIG_RIGHT)   = 10 ;
  *(nldx+ILLEAGAL)    = 10 ; *(nrdx+ILLEAGAL)    = 10 ;
  /* CRANK */
  *(cldx+ALL_BLACK)   = 10 ; *(crdx+ALL_BLACK)   = 10 ;
  *(cldx+ALL_WHITE)   = 10 ; *(crdx+ALL_WHITE)   = 10 ;
  *(cldx+LEFT_WHITE)  = 10 ; *(crdx+LEFT_WHITE)  = 10 ;
  *(cldx+RIGHT_WHITE) = 30 ; *(crdx+RIGHT_WHITE) = 30 ;
  *(cldx+CENTER)      = 30 ; *(crdx+CENTER)      = 35 ;
  *(cldx+TINY_RIGHT)  = 30 ; *(crdx+TINY_RIGHT)  = 40 ;
  *(cldx+RIGHT)       = 30 ; *(crdx+RIGHT)       = 45 ;
  *(cldx+BIG_RIGHT)   = 35 ; *(crdx+BIG_RIGHT)   = 30 ;
  *(cldx+TINY_LEFT)   = 40 ; *(crdx+TINY_LEFT)   = 30 ;
  *(cldx+LEFT)        = 45 ; *(crdx+LEFT)        = 30 ;
  *(cldx+BIG_LEFT)    = 10 ; *(crdx+BIG_LEFT)    = 10 ;
  *(cldx+BOTH_WHITE)  = 10 ; *(crdx+BOTH_WHITE)  = 10 ;
  *(cldx+ILLEAGAL)    = 10 ; *(crdx+ILLEAGAL)    = 10 ;
  /* ROTATE */
  *(rldx+ALL_BLACK)   = 10 ; *(rrdx+ALL_BLACK)   = 10 ;
  *(rldx+ALL_WHITE)   = 30 ; *(rrdx+ALL_WHITE)   = 30 ;
  *(rldx+LEFT_WHITE)  = 10 ; *(rrdx+LEFT_WHITE)  = 50 ;
  *(rldx+RIGHT_WHITE) = 50 ; *(rrdx+RIGHT_WHITE) = 10 ;
  *(rldx+CENTER)      = 30 ; *(rrdx+CENTER)      = 30 ;
  *(rldx+TINY_RIGHT)  = 30 ; *(rrdx+TINY_RIGHT)  = 35 ;
  *(rldx+RIGHT)       = 30 ; *(rrdx+RIGHT)       = 40 ;
  *(rldx+BIG_RIGHT)   = 30 ; *(rrdx+BIG_RIGHT)   = 45 ;
  *(rldx+TINY_LEFT)   = 35 ; *(rrdx+TINY_LEFT)   = 30 ;
  *(rldx+LEFT)        = 40 ; *(rrdx+LEFT)        = 30 ;
  *(rldx+BIG_LEFT)    = 45 ; *(rrdx+BIG_LEFT)    = 30 ;
  *(rldx+BOTH_WHITE)  = 25 ; *(rrdx+BOTH_WHITE)  = 25 ;
  *(rldx+ILLEAGAL)    = 10 ; *(rrdx+ILLEAGAL)    = 10 ;
  /* LANE */
  *(lldx+ALL_BLACK)   = 10 ; *(lrdx+ALL_BLACK)   = 10 ;
  *(lldx+ALL_WHITE)   = 30 ; *(lrdx+ALL_WHITE)   = 30 ;
  *(lldx+LEFT_WHITE)  = 10 ; *(lrdx+LEFT_WHITE)  = 50 ;
  *(lldx+RIGHT_WHITE) = 50 ; *(lrdx+RIGHT_WHITE) = 10 ;
  *(lldx+CENTER)      = 30 ; *(lrdx+CENTER)      = 30 ;
  *(lldx+TINY_RIGHT)  = 30 ; *(lrdx+TINY_RIGHT)  = 35 ;
  *(lldx+RIGHT)       = 30 ; *(lrdx+RIGHT)       = 40 ;
  *(lldx+BIG_RIGHT)   = 30 ; *(lrdx+BIG_RIGHT)   = 45 ;
  *(lldx+TINY_LEFT)   = 35 ; *(lrdx+TINY_LEFT)   = 30 ;
  *(lldx+LEFT)        = 40 ; *(lrdx+LEFT)        = 30 ;
  *(lldx+BIG_LEFT)    = 45 ; *(lrdx+BIG_LEFT)    = 30 ;
  *(lldx+BOTH_WHITE)  = 10 ; *(lrdx+BOTH_WHITE)  = 10 ;
  *(lldx+ILLEAGAL)    = 10 ; *(lrdx+ILLEAGAL)    = 10 ;
  /* CHANGE */
  *(chldx+ALL_BLACK)   = 10 ; *(chrdx+ALL_BLACK)   = 10 ;
  *(chldx+ALL_WHITE)   = 50 ; *(chrdx+ALL_WHITE)   = 50 ;
  *(chldx+LEFT_WHITE)  = 10 ; *(chrdx+LEFT_WHITE)  = 50 ;
  *(chldx+RIGHT_WHITE) = 50 ; *(chrdx+RIGHT_WHITE) = 10 ;
  *(chldx+CENTER)      = 50 ; *(chrdx+CENTER)      = 50 ;
  *(chldx+TINY_RIGHT)  = 55 ; *(chrdx+TINY_RIGHT)  = 50 ;
  *(chldx+RIGHT)       = 60 ; *(chrdx+RIGHT)       = 50 ;
  *(chldx+BIG_RIGHT)   = 65 ; *(chrdx+BIG_RIGHT)   = 50 ;
  *(chldx+TINY_LEFT)   = 50 ; *(chrdx+TINY_LEFT)   = 55 ;
  *(chldx+LEFT)        = 50 ; *(chrdx+LEFT)        = 60 ;
  *(chldx+BIG_LEFT)    = 50 ; *(chrdx+BIG_LEFT)    = 65 ;
  *(chldx+BOTH_WHITE)  = 10 ; *(chrdx+BOTH_WHITE)  = 10 ;
  *(chldx+ILLEAGAL)    = 10 ; *(chrdx+ILLEAGAL)    = 10 ;
  /* BLIND */
  *(blldx+ALL_BLACK)   = 10 ; *(blrdx+ALL_BLACK)   = 10 ;
  *(blldx+ALL_WHITE)   = 50 ; *(blrdx+ALL_WHITE)   = 50 ;
  *(blldx+LEFT_WHITE)  = 50 ; *(blrdx+LEFT_WHITE)  = 10 ;
  *(blldx+RIGHT_WHITE) = 10 ; *(blrdx+RIGHT_WHITE) = 50 ;
  *(blldx+CENTER)      = 50 ; *(blrdx+CENTER)      = 50 ;
  *(blldx+TINY_RIGHT)  = 55 ; *(blrdx+TINY_RIGHT)  = 50 ;
  *(blldx+RIGHT)       = 60 ; *(blrdx+RIGHT)       = 50 ;
  *(blldx+BIG_RIGHT)   = 65 ; *(blrdx+BIG_RIGHT)   = 50 ;
  *(blldx+TINY_LEFT)   = 50 ; *(blrdx+TINY_LEFT)   = 55 ;
  *(blldx+LEFT)        = 50 ; *(blrdx+LEFT)        = 60 ;
  *(blldx+BIG_LEFT)    = 50 ; *(blrdx+BIG_LEFT)    = 65 ;
  *(blldx+BOTH_WHITE)  = 10 ; *(blrdx+BOTH_WHITE)  = 10 ;
  *(blldx+ILLEAGAL)    = 10 ; *(blrdx+ILLEAGAL)    = 10 ;
}

 上のように定義して、利用するメモリの容量は、13x2x6=156バイト
 にしかなりません。実際に走行させ、左右のモータの固体差を吸収
 へと持ち込みます。

 少し冗長なので、次のように16ビットの配列で、左右のモータの
 DUTY比が一目でわかるようにしました。

UWORD ndx[13];
UWORD cdx[13];
UWORD rdx[13];
UWORD ldx[13];
UWORD chdx[13];
UWORD bldx[13];

void  init_road_array()
{
  /* NORMAL */
  *(ndx+ALL_BLACK)   = (10 << 8) | 10 ;
  *(ndx+ALL_WHITE)   = (30 << 8) | 30 ;
  *(ndx+LEFT_WHITE)  = (10 << 8) | 10 ;
  *(ndx+RIGHT_WHITE) = (10 << 8) | 10 ;
  *(ndx+CENTER)      = (50 << 8) | 50 ;
  *(ndx+TINY_RIGHT)  = (50 << 8) | 55 ;
  *(ndx+RIGHT)       = (50 << 8) | 60 ;
  *(ndx+BIG_RIGHT)   = (50 << 8) | 65 ;
  *(ndx+TINY_LEFT)   = (55 << 8) | 50 ;
  *(ndx+LEFT)        = (60 << 8) | 50 ;
  *(ndx+BIG_LEFT)    = (65 << 8) | 50 ;
  *(ndx+BOTH_WHITE)  = (10 << 8) | 10 ;
  *(ndx+ILLEAGAL)    = (10 << 8) | 10 ;
  /* CRANK */
  *(cdx+ALL_BLACK)   = (10 << 8) | 10 ;
  *(cdx+ALL_WHITE)   = (10 << 8) | 10 ;
  *(cdx+LEFT_WHITE)  = (10 << 8) | 10 ;
  *(cdx+RIGHT_WHITE) = (10 << 8) | 10 ;
  *(cdx+CENTER)      = (30 << 8) | 30 ;
  *(cdx+TINY_RIGHT)  = (30 << 8) | 35 ;
  *(cdx+RIGHT)       = (30 << 8) | 40 ;
  *(cdx+BIG_RIGHT)   = (30 << 8) | 45 ;
  *(cdx+TINY_LEFT)   = (35 << 8) | 30 ;
  *(cdx+LEFT)        = (40 << 8) | 30 ;
  *(cdx+BIG_LEFT)    = (45 << 8) | 30 ;
  *(cdx+BOTH_WHITE)  = (10 << 8) | 10 ;
  *(cdx+ILLEAGAL)    = (10 << 8) | 10 ;
  /* ROTATE */
  *(rdx+ALL_BLACK)   = (10 << 8) | 10 ;
  *(rdx+ALL_WHITE)   = (30 << 8) | 30 ;
  *(rdx+LEFT_WHITE)  = (10 << 8) | 50 ;
  *(rdx+RIGHT_WHITE) = (50 << 8) | 10 ;
  *(rdx+CENTER)      = (30 << 8) | 30 ;
  *(rdx+TINY_RIGHT)  = (30 << 8) | 35 ;
  *(rdx+RIGHT)       = (30 << 8) | 40 ;
  *(rdx+BIG_RIGHT)   = (30 << 8) | 45 ;
  *(rdx+TINY_LEFT)   = (35 << 8) | 30 ;
  *(rdx+LEFT)        = (40 << 8) | 30 ;
  *(rdx+BIG_LEFT)    = (45 << 8) | 30 ;
  *(rdx+BOTH_WHITE)  = (25 << 8) | 25 ;
  *(rdx+ILLEAGAL)    = (10 << 8) | 10 ;
  /* LANE */
  *(ldx+ALL_BLACK)   = (10 << 8) | 10 ;
  *(ldx+ALL_WHITE)   = (30 << 8) | 30 ;
  *(ldx+LEFT_WHITE)  = (10 << 8) | 50 ;
  *(ldx+RIGHT_WHITE) = (50 << 8) | 10 ;
  *(ldx+CENTER)      = (30 << 8) | 30 ;
  *(ldx+TINY_RIGHT)  = (30 << 8) | 35 ;
  *(ldx+RIGHT)       = (30 << 8) | 40 ;
  *(ldx+BIG_RIGHT)   = (30 << 8) | 45 ;
  *(ldx+TINY_LEFT)   = (35 << 8) | 30 ;
  *(ldx+LEFT)        = (40 << 8) | 30 ;
  *(ldx+BIG_LEFT)    = (45 << 8) | 30 ;
  *(ldx+BOTH_WHITE)  = (10 << 8) | 10 ;
  *(ldx+ILLEAGAL)    = (10 << 8) | 10 ;
  /* CHANGE */
  *(chdx+ALL_BLACK)   = (10 << 8) | 10 ;
  *(chdx+ALL_WHITE)   = (50 << 8) | 50 ;
  *(chdx+LEFT_WHITE)  = (10 << 8) | 50 ;
  *(chdx+RIGHT_WHITE) = (50 << 8) | 10 ;
  *(chdx+CENTER)      = (50 << 8) | 50 ;
  *(chdx+TINY_RIGHT)  = (55 << 8) | 50 ;
  *(chdx+RIGHT)       = (60 << 8) | 50 ;
  *(chdx+BIG_RIGHT)   = (65 << 8) | 50 ;
  *(chdx+TINY_LEFT)   = (50 << 8) | 55 ;
  *(chdx+LEFT)        = (50 << 8) | 60 ;
  *(chdx+BIG_LEFT)    = (50 << 8) | 65 ;
  *(chdx+BOTH_WHITE)  = (10 << 8) | 10 ;
  *(chdx+ILLEAGAL)    = (10 << 8) | 10 ;
  /* BLIND */
  *(bldx+ALL_BLACK)   = (10 << 8) | 10 ;
  *(bldx+ALL_WHITE)   = (50 << 8) | 50 ;
  *(bldx+LEFT_WHITE)  = (10 << 8) | 50 ;
  *(bldx+RIGHT_WHITE) = (50 << 8) | 10 ;
  *(bldx+CENTER)      = (50 << 8) | 50 ;
  *(bldx+TINY_RIGHT)  = (55 << 8) | 50 ;
  *(bldx+RIGHT)       = (60 << 8) | 50 ;
  *(bldx+BIG_RIGHT)   = (65 << 8) | 50 ;
  *(bldx+TINY_LEFT)   = (50 << 8) | 55 ;
  *(bldx+LEFT)        = (50 << 8) | 60 ;
  *(bldx+BIG_LEFT)    = (50 << 8) | 65 ;
  *(bldx+BOTH_WHITE)  = (10 << 8) | 10 ;
  *(bldx+ILLEAGAL)    = (10 << 8) | 10 ;
}

 行数は同じですが配列の個数が減るのと、左右で
 DUTY比がわかるので、こちらの方がよいと判断。

 スプレッドシートを利用すれば、変数名、文字列、左右のDUTY比を
 書いてCSV形式で出力すれば、すぐに生成できるでしょう。

 スプレッドシートを使うまでもないとして、次のAWKのスクリプトで
 コードを生成しました。

{
  printf("*(%s+%s) = (%d << 8) | %d ;\n",$1,$2,$3,$4)
}

 AWKのスクリプトに与える内容は、次のリストでテキストファイルに。

bldx ALL_BLACK 10 10
bldx ALL_WHITE 50 50
bldx LEFT_WHITE 10 50
bldx RIGHT_WHITE 50 10
bldx CENTER 50 50
bldx TINY_RIGHT 55 50
bldx RIGHT 60 50
bldx BIG_RIGHT 65 50
bldx TINY_LEFT 50 55
bldx LEFT 50 60
bldx BIG_LEFT 50 65
bldx BOTH_WHITE 10 10
bldx ILLEAGAL 10 10

 スプレッドシートを立ち上げる時間が勿体ないので
 6種のテキストファイルを用意して、一気にコード
 を生成できました。

 走行ステートに合わせたDUTY比を設定しているので
 個別の走行ステートの移動をテストできます。
 大きなコースを持たないでも、移動テストができる
 という長所あり。

 センサー情報との連携を考えると、基板上にある2つのLEDを使い
 ALL_WHITE、LEFT_WHITE、RIGHIT_WHITEを表示します。



 DUTY比とセンサー値の方は、8個のLEDを1セットとして2セット
 あるので表示して、走行しているときの状態がわかるようにします。




 DUTY比は、左右で0から99までの数値として定義されるので
 8で割ったときの商を求め、左右のLED4個で表示。8で割る
 のは右に3ビットシフトなので、計算時間を短くできます。




 DUTY比の他に、走行モードを音で出力します。
 音を出すとうるさいので、AMワイヤレスマイクを使い
 AMラジオに送信。



 4番ピンはリセットなので、音声周波数帯の信号を入れて
 変調します。無変調でも、雑音くらいは聞こえますが。

 送信範囲は半径10m四方であればよいので、1mくらいの
 ビニル線を接続してアンテナとしておきます。

 回路は、単純で発振ICの定番555を利用。




 530kHzから880kHzまで可変できるので、札幌、大阪で
 ラジオ局の周波数が異なっても、送信周波数を変えて対応可能
 にしました。

 電波法にかからないようにして、次のレシーバで音を捕捉。




 ゲルマニウムダイオードを利用し、トランジスタ一石で増幅。
 クリスタルイアフォンで聞けます。

 スピーカで聞きたい場合には、次のアンプを追加。



 マシン上のコンピュータは、走行モードにあわせたデータを
 取り出す処理が必要になりますが、次のように単純。

#define MASKFF 0xff

  UBYTE xmul ;
  UBYTE flag ;
  UBYTE xsensor ;
  UWORD tmp ;
  /* default */
  flag = OFF ;
  /* show state */
  mstate = 1 ;
  show_state( mstate );
  /* get sensor */
  xsensor = get_sensor();
  /* update motor duty ratio */
  tmp = *(ndx+xsensor);
  left  = (tmp >> 8) & MASKFF ;
  right = tmp & MASKFF ;
  /* default */
  *(dir+0) = DIR_CENTER ;
  *(dir+1) = DIR_CENTER ;
  /* get sensor */
  if ( xsensor == CENTER ) {
    /* climb hill or down hill */
    if ( sloap ) {
      xmul = *(sloapt+sloap) ;
      left  = (UBYTE)( xmul * left * 1.0 / 100 );
      right = (UBYTE)( xmul * right * 1.0 / 100 );
    }
  }
  /* update */
  send_dc(left,right);
  /* judge */
  if ( xsensor == ALL_WHITE ) {
    rsm_tsk(CRANK);
    flag = ON ;
  }
  if ( xsensor == LEFT_WHITE ) {
    *(dir+0) = DIR_LEFT ;
    *(dir+1) = DIR_RIGHT ;
    rsm_tsk(LANE);
    flag = ON ;
  }
  if ( xsensor == RIGHT_WHITE ) {
    *(dir+0) = DIR_RIGHT ;
    *(dir+0) = DIR_LEFT ;
    rsm_tsk(LANE);
    flag = ON ;
  }
  /* cyclic */
  if ( flag == ON ) {
    flag = OFF ;
    slp_tsk();
  } else {
    wai_tsk( 10 );
  }

 走行モードを表示するには、関数show_stateを利用しますが
 該当するLEDを点灯するだけで対応可能。

void show_state(UBYTE x)
{
  UBYTE result;
  /* generate code */
  result = (1 << x);
  /* impress */
  P4DR = result ^ MASKFF ;
}

 DUTY比の表示は、次の処理にパラメータを渡すだけ。

void show_duty(UBYTE ldx,UBYTE rdx)
{
  UBYTE result ;
  /* clear */
  P3DR = 0x00 ;
  /* clear */
  result = 0 ;
  /* upper */
  result |= ((ldx >> 3) << 4) ;
  /* lower */
  result |= (rdx >> 3) ;
  /* send */
  P3DR = result ^ MASKFF ;
}

 左右のDUTY比は、変数left、rightに格納されているので
 それらを関数show_dutyに与えるだけで充分。

 路面状態は、配列にパターンを格納してLEDに転送する
 ことで対応します。

UBYTE road_pat[13] ;

void init_road_pat(void)
{
  *(road_pat+ALL_BLACK)   = 0x00 ; *(road_pat+ALL_WHITE)   = 0xff ;
  *(road_pat+LEFT_WHITE)  = 0xf0 ; *(road_pat+RIGHT_WHITE) = 0x0f ;
  *(road_pat+CENTER)      = 0x18 ; *(road_pat+TINY_RIGHT)  = 0x0c ;
  *(road_pat+RIGHT)       = 0x06 ; *(road_pat+BIG_RIGHT)   = 0x03 ;
  *(road_pat+TINY_LEFT)   = 0x30 ; *(road_pat+LEFT)        = 0x60 ;
  *(road_pat+BIG_LEFT)    = 0xc0 ; *(road_pat+BOTH_WHITE)  = 0xc3 ;
  *(road_pat+ILLEAGAL)    = 0x5a ;
}

void show_road(UBYTE x)
{
  UBYTE result ;
  /* clear */
  PADR = 0x00 ;
  /* get pattern */
  result = *(road_pat+x) ;
  /* send */
  PADR = result ^ MASKFF ;
}

 音で走行モードを提示するには、周波数の変更が必要なので
 発振ICの555の発振周波数を変更して対応。

 RC発振回路の抵抗分Rをアナログスイッチで切り替えます。



 コンピュータからは、どの周波数を利用するのかを
 3ビットの選択信号で指定するだけ。


目次

inserted by FC2 system