目次

画像処理スクリプト

 GameBoyCamera、BarCodeScannerが取得した画像情報を
 センサー情報に変換するため、作成したスクリプトを
 記しておきます。

 画像データとしては、次の内容を利用しました。



 MCRマシンを移動させる場合、必要なのは8ビット
 程度のライン情報です。

 ライン情報が、00011000であれば中央にラインが
 見えているとして、直進させます。



 GBC、BCSとも、上図の赤枠で囲んだ部分の中央しか
 見えていないので、見えている範囲で中央の白線が
 どこにあるかを情報として生成します。

 経験から、次のような密着型センサーを利用した場合と
 等価な情報を与えればよいと判断できます。



 全データを使ってセンサー情報を生成するのではなく
 バーコードのように横に並んだ白黒情報から、移動で
 使える情報を生成します。

 GBCからの画像情報をテキストファイルに入れてある
 ので、このファイルの情報を使い、センサー情報を
 生成するまでのプロセスを検討しました。

 検討過程を書き出して、備忘録とします。

 テキストファイルの内容を扱うには、コンパイラ型の
 プログラミング言語ではなく、スクリプト言語を利用
 する方が効率がよいため、Tcl/Tk、Pythonを利用する
 ことに。

 日本ではTcl/Tk、PythonよりもRubyがよいと助言を
 くれる知人もいましたが、Tcl/Tk、PythonはUNIXに
 標準バンドリングされているので、Rubyは使わない
 で済ませました。


画像情報解析

 テキストファイルに入っている情報は、数値なので  最大値、最小値を求め、2数の相加平均を閾値にし  2値化して、どんな具合に見えるのか表示します。  結果は、次のようになりました。 1111111111111111111111111111111111111111111111100000000000000000 1111111111111111111111111111111111111111111111110000000000000000 1111111111111111111111101111111111111111111111110000000000000000 0000000000011110000000000000001111111111111111110000000000000000 0000000000000000000000000000001111111111111111110000000000000000 0000000000000000000000000000001111111111111111110000000000000000 0000000000000000000000000000001111111111111111111000000000000000 0000000000000000000000000000001111111111111111111000000000000000 0000000000000000000000000000011111111111111111111000000000000000 0000000000000000000000000000011111111111111111111100000000000000 0000000000000000000000000000011111111111111111111100000000000000 0000000000000000000000000000011111111111111111111100000000000000 0000000000000000000000000000011111111111111111111100000000000000 0000000000000000000000000000011111111111111111111100000000000000 0000000000000000000000000000111111111111111111111110000000000000 0000000000000000000000000000111111111111111111111100000000000000 0000000000000000000000000000111111111111111111111110000000000000 0000000000000000000000000000111111111111111111111110000000000000 0000000000000000000000000000111111111111111111011010000000000000 0000000000000000000000000000111111111111111111000000000000000000 0000000000000000000000000000111111111111111111000000000000000000 0000000000000000000000000000111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000011111111111111111111100000000000000000 0000000000000000000000000011111111111111111111100000000000000000 0000000000000000000000000011111111111111111111100000000000000000 0000000000000000000000000011111111111111111111110000000000000000 0000000000000000000000000011111111111111111111110000000000000000 0000000000000000000000000011111111111111111111110000000000000000 0000000000000000000000000011111111111111111111110000000000000000 0000000000000000000000000111111111111111111111110000000000000000 0000000000000000000000000111111111111111111111110000000000000000 0000000000000000000000000111111111111111111111110000000000000000 0000000000000000000000000111111111111111111111110000000000000000 0000000000000000000000000111111111111111111111111000000000000000 0000000000000000000000000111111111111111111111111000000000000000 0000000000000000000000000111111111111111111111111000000000000000 0000000000000000000000000111111111111111111111111000000000000000 0000000000000000000000000111111111111111111111111000000000000000 0000000000000000000000001111111111111111111111111000000000000000 0000000000000000000000001111111111111111111111111000000000000000 0000000000000000000000001111111111111111111111111000000000000000 0000000000000000000000001111111111111111111111111000000000000000 0000000000000000000000001111111111111111111111111000000000000000 0000000000000000000000001111111111111111111111111100000000000000 0000000000000000000000001111111111111111111111111100000000000000 0000000000000000000000001111111111111111111111111100000000000000 0000000000000000000000001111111111111111111111111100000000000000 0000000000000000000000001111111111111111111111111100000000000000 0000000000000000000000011111111111111111111111111100000000000000 0000000000000000000000011111111111111111111111111100000000000000 0000000000000000000000011111111111111111111111111100000000000000 0000000000000000000000011111111111111111111111111100000000000000 0000000000000000000000011111111111111111111111111100000000000000  スクリプトの内容は、以下。 #!/usr/bin/tclsh # set file descripter set fname "mgtst.txt" # pseudo set xmin 1023 set xmax 0 set zero 0 set one 1 # open set fd [open $fname] # ? maximum and minimum while { [gets $fd line] >= 0 } { # update foreach e $line { if { $xmax < $e } { set xmax $e } if { $xmin > $e } { set xmin $e } } } # close close $fd # calculate threshold set xth [expr ($xmax+$xmin) / 2] # set file descripter set fd [open $fname] # convert while { [gets $fd line] >= 0 } { # get size set last [llength $line] # diet 64 pixels set sidx [expr $last / 2 - 32] set fidx [expr $last / 2 + 31] set line [lrange $line $sidx $fidx] # get size set last [llength $line] # clear strings set xout "" # generate binary code foreach e $line { if { $e > $xth } { set xout "$xout$one" } else { set xout "$xout$zero" } } puts $xout } # close $fd  やっていることは、単純です。  テキストファイルの内容を読み込んで、最大値、最小値を  求め、閾値を最大値、最小値の相加平均とする。  同じテキストファイルの内容を読み込んで、閾値より大きい  数値であれば1、それ以外は0とし、1行の文字列を生成。  文字列は最大64文字とすべく、中央にある64データだけを  対象とします。  2値化画像データを見ると、上にある情報は、センサーから  遠いため、正確に取れていないようです。また、台形の状態  でコース面のセンターラインが見えます。  黒白が明確にわかるのは、縦方向に見ての中央付近  なので、中央近辺の情報を2値化して表示します。  中央近辺は、10ライン程度とします。  スクリプトは、次のように修正しました。 #!/usr/bin/tclsh # set file descripter set fname "mgtst.txt" # pseudo set xmin 1023 set xmax 0 set zero 0 set one 1 set ln 0 # open set fd [open $fname] # ? maximum and minimum while { [gets $fd line] >= 0 } { # update foreach e $line { if { $xmax < $e } { set xmax $e } if { $xmin > $e } { set xmin $e } } # line number increment incr ln } # close close $fd # calculate threshold set xth [expr ($xmax+$xmin) / 2] # set file descripter set fd [open $fname] # set sln [expr $ln / 2 - 5] set fln [expr $ln / 2 + 5] set ln 0 # convert while { [gets $fd line] >= 0 } { # get size set last [llength $line] # increment incr ln # diet 64 pixels set sidx [expr $last / 2 - 32] set fidx [expr $last / 2 + 31] set line [lrange $line $sidx $fidx] # get size set last [llength $line] # clear strings set xout "" # generate binary code foreach e $line { if { $e > $xth } { set xout "$xout$one" } else { set xout "$xout$zero" } } # targer line if { $ln >= $sln && $ln < $fln } { puts $xout } } # close $fd  修正スクリプトで、2値化した内容を表示すると  次のようになります。 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000001111111111111111111100000000000000000 0000000000000000000000000011111111111111111111100000000000000000 0000000000000000000000000011111111111111111111100000000000000000 0000000000000000000000000011111111111111111111100000000000000000 0000000000000000000000000011111111111111111111110000000000000000 0000000000000000000000000011111111111111111111110000000000000000  64ピクセルの情報を8ビットのセンサー情報にします。  1ブロック=8ピクセルとして、8ブロックに分けて  代表値を求め縮退します。 *** 00000000 00000000 00000000 00011111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00011111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00011111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00011111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00011111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00111111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00111111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00111111 11111111 11111110 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00111111 11111111 11111111 00000000 00000000 => 00011100 *** 00011100 *** 00000000 00000000 00000000 00111111 11111111 11111111 00000000 00000000 => 00011100 *** 00011100  1ブロック=8ピクセル中の1の個数を数えて  5個以上になっていれば1としています。  スクリプトは以下。 #!/usr/bin/tclsh # set file descripter set fname "mgtst.txt" # pseudo set xmin 1023 set xmax 0 set zero 0 set one 1 set ln 0 # open set fd [open $fname] # ? maximum and minimum while { [gets $fd line] >= 0 } { # update foreach e $line { if { $xmax < $e } { set xmax $e } if { $xmin > $e } { set xmin $e } } # line number increment incr ln } # close close $fd # calculate threshold set xth [expr ($xmax+$xmin) / 2] # set file descripter set fd [open $fname] # set sln [expr $ln / 2 - 5] set fln [expr $ln / 2 + 5] set ln 0 # convert while { [gets $fd line] >= 0 } { # get size set last [llength $line] # increment incr ln # diet 64 pixels set sidx [expr $last / 2 - 32] set fidx [expr $last / 2 + 31] set line [lrange $line $sidx $fidx] # get size set last [llength $line] # clear strings set xout "" # generate binary code foreach e $line { if { $e > $xth } { set xout "$xout$one" } else { set xout "$xout$zero" } } # targer line if { $ln >= $sln && $ln < $fln } { # separate set yout "" for {set j 0} {$j < 8} {incr j} { set bx [expr 8 * $j] set fx [expr $bx + 7] set yout "$yout [string range $xout $bx $fx]" } # generate set zout "" foreach e $yout { # separate set x [split $e ""] # count set zc 0 foreach ee $x { if { $ee == 1 } { set zc [expr $zc + 1] } } # judge if { $zc > 4 } { set zout "$zout$one" } else { set zout "$zout$zero" } } puts "***$yout => $zout ***" puts $zout } } # close $fd  8ビットの情報だけにすると、次のようになります。 00011100 00011100 00011100 00011100 00011100 00011100 00011100 00011100 00011100 00011100  2値化すると、白が連続している部分が  必ず出てくると仮定して処理しています。  実際には、レーンチェンジやクランクで  すべて黒の場合があるので、その判断は  どう走行するのかを担当する戦略コード  に任せます。  Tcl/Tkのスクリプトで記述した内容を、Pythonの  スクリプトに変換します。ひとつのスクリプトで  見落としていた内容を見出せることもあるので  必要な作業と考えています。  Pythonのスクリプトは、以下。 #!/usr/bin/python # define counter def cmdCNT(x): # loop result = 0 for e in range(0,len( x )) : if x[e] == '1' : result = result + 1 return result # open fin = open('mgtst.txt','r') # get line = fin.read() # close fin.close() # generate list glist = line[:-1].split('\n'); # calculate threshold xlist = [] for e in glist : ee = e.split() for x in ee : xlist.append(int(x)) xth = (max(xlist)+min(xlist)) >> 1 # binary conversion xstr = "" for e in xlist : if e > xth : xstr += "1" else : xstr += "0" # generate sensor data for e in range(0,60) : # separate x = xstr[80 * e + 8:80 * e + 72] # result = "" for ee in range(0,8) : # judge if cmdCNT( x[8*ee:8*(ee+1)] ) > 4 : result += "1" else : result += "0" # show print e," ",result  生成したセンサーデータは、全体で次の  ようになります。 0 11111100 1 11111100 2 11111100 3 00001100 4 00001100 5 00001100 6 00001100 7 00001100 8 00001100 9 00001100 10 00001100 11 00001100 12 00001100 13 00001100 14 00001100 15 00001100 16 00001100 17 00001100 18 00001100 19 00001100 20 00001100 21 00001100 22 00011100 23 00011100 24 00011100 25 00011100 26 00011100 27 00011100 28 00011100 29 00011100 30 00011100 31 00011100 32 00011100 33 00011100 34 00011100 35 00011100 36 00011100 37 00011100 38 00011100 39 00011100 40 00011100 41 00011100 42 00011100 43 00011100 44 00011100 45 00011100 46 00011100 47 00011100 48 00011100 49 00011100 50 00011100 51 00011100 52 00011100 53 00011100 54 00011100 55 00011100 56 00011100 57 00011100 58 00011100 59 00011100  縦方向に見て、たくさんあるラインのどれを利用  するかは、マシンに取り付けるセンサーの位置に  より異なるので、スクリプト言語によるセンサー  データ生成は、ここまでにします。  64ピクセルのデータがあるとして、センサーデータ  生成がどんな具合になっているのかを乱数を利用し  シミュレーションしてみました。  1が始まるピクセル位置と持続数を乱数を利用して  生成し、そのパラメータで64ピクセルデータを作り  8ビットのセンサーデータに変換すると以下。 0000000000000000000111111111111111111111111100000000000000000000 -> 00111000 0000000000000000000000000011111111111111110000000000000000000000 -> 00011000 0000000000000000111111111100000000000000000000000000000000000000 -> 00100000 0000000000000000000000000000000000000000000000000000001111111111 -> 00000001 0000000000000001111111111111111111000000000000000000000000000000 -> 00110000 0000000000000000000000000001111110000000000000000000000000000000 -> 00010000 0000011111111111111111111100000000000000000000000000000000000000 -> 01100000 0000000000000000000000000000000000000000000000000000011111111111 -> 00000001 0001111111111111111111111000000000000000000000000000000000000000 -> 11100000 0000000000000000000000000000000000000000000000000000000001111111 -> 00000001  データ生成は、次のPythonスクリプトを利用。 #!/usr/bin/python import random # define line code generator def genLine(xl,xw): # range startp = xl endp = xl + xw # generate result = "" for e in range(0,64) : if e >= startp and e < endp : result += "1" else : result += "0" return result # define counter def cmdCNT(x): # loop result = 0 for e in range(0,len( x )) : if x[e] == '1' : result = result + 1 return result # define block counter def genSensorData(x): # split xx = [] for e in range(0,8) : startp = e << 3 endp = (e+1) << 3 xx.append( cmdCNT(x[startp:endp]) ) # generate sensor data result = "" for e in range(0,8): if xx[e] > 4 : result += "1" else: result += "0" # return result # main for e in range(0,10) : pl = random.uniform(0,64) pw = random.uniform(0,32) x = genLine(pl,pw) print x,"->",genSensorData(x)  Pythonスクリプトを使えないので、C/C++でGameBoyCameraの  画像処理ファームウエアを考えていきます。

センサーデータ生成アルゴリズム

 2つのスクリプト言語による処理で、同じ結果が得られたので  コンパイラ言語でセンサーデータを生成していきます。  閾値計算   閾値は、1ライン(128ピクセル)中の最大値、最小値を求め   その相加平均とします。   配列gbcに、1ラインの情報が含まれているとし、コードを記述します。 xmax = 0 ; xmin = 1023 ; for ( i = 0 ; i < 128 ; i++ ) { if ( xmin > *(gbc+i) ) { xmin = *(gbc+i) ; } if ( *(gbc+i) > xmax ) { xmax = *(gbc+i) ; } } xth = (xmax + xmin) >> 1 ;  2値化   64ピクセル分を2値化し、0か1を配列gbcbinに保存します。 for ( i = 0 ; i < 128 ; i++ ) { /* judge */ bn = 0 ; if ( *(gbc+i) > xth ) { bn = 1 ; } /* store */ if ( i >= 32 && i < 96 ) { *(gbcbin+i-32) = bn ; } }  ブロックごとの1の個数計算   64ピクセルを8ブロックに分割し、その中にある1の   個数を求めます。 for ( i = 0 ; i < 8 ; i++ ) { *(cnt+i) = 0 } for ( i = 0 ; i < 8 ; i++ ) { if ( *(gbcbin+i ) == 1 ) { *(cnt+0) = *(cnt+0) + 1 ; } if ( *(gbcbin+i+ 8) == 1 ) { *(cnt+1) = *(cnt+1) + 1 ; } if ( *(gbcbin+i+16) == 1 ) { *(cnt+2) = *(cnt+2) + 1 ; } if ( *(gbcbin+i+24) == 1 ) { *(cnt+3) = *(cnt+3) + 1 ; } if ( *(gbcbin+i+32) == 1 ) { *(cnt+4) = *(cnt+4) + 1 ; } if ( *(gbcbin+i+40) == 1 ) { *(cnt+5) = *(cnt+5) + 1 ; } if ( *(gbcbin+i+48) == 1 ) { *(cnt+6) = *(cnt+6) + 1 ; } if ( *(gbcbin+i+56) == 1 ) { *(cnt+7) = *(cnt+7) + 1 ; } }  センサーデータ生成   8ブロックの各ブロックの1の個数を利用して   センサーデータを合成します。 sensor = 0 ; for ( i = 0 ; i < 8 ; i++ ) { if ( *(cnt+i) > 4 } { sensor |= (1 << (7-i)) ; } }  ここまでの内容をArduinoスケッチにまとめると、以下。 #include <MsTimer2.h> #define OFF 0 #define ON OFF+1 #define TARGETLINE 40 #define BMAX 8192 #define LINESIZE 64 #define SLOPEOFFSET 128*4 /* Game Boy Camera pin assignment */ #define GBC_START_BIT 7 #define GBC_SIN_BIT 6 #define GBC_LOAD_BIT 5 #define GBC_XRST_BIT 4 #define GBC_XCK_BIT 3 #define GBC_READ_BIT 2 /* monitor LED */ #define LED_BIT 5 /* sensor data */ #define ALL_BLACK 0 #define ALL_WHITE 1 #define LEFT_WHITE 2 #define RIGHT_WHITE 3 #define CENTER 4 #define BIG_RIGHT 5 #define RIGHT 6 #define TINY_RIGHT 7 #define TINY_LEFT 8 #define LEFT 9 #define BIG_LEFT 10 #define BOTH_WHITE 11 #define ILLEAGAL 12 /* global variables */ byte tline ; /* target line */ word tpixelb ; /* start pixel */ word tpixelf ; /* exit pixel */ byte gbcpam[8] ; byte rflag ; byte uflag ; byte tflag ; byte sindex ; byte sbuf[8] ; word gcnt ; byte xgcnt ; word gbcrawx[LINESIZE]; word gbcrawy[LINESIZE]; byte gbcbinx[LINESIZE]; byte gbcbiny[LINESIZE]; word xmin ; word xmax ; word xth ; word bmin[3] ; word bmax[3] ; word bth[3] ; byte sft_sel ; word sensor ; byte mode ; byte rcnt ; byte bcnt ; byte statex ; byte statey ; byte xcnt ; void send_led(byte x) { if ( x ) { PORTB |= (1 << LED_BIT) ; } else { PORTB &= ~(1 << LED_BIT) ; } } void update_trigger(void) { tflag = ON ; send_led( xcnt & ON ); xcnt++ ; } word get_ad(void) { return( analogRead(0) ); } byte is_target(byte which,word x) { byte result ; word bx ; word by ; /* default */ result = OFF ; /* adjust */ bx = tpixelb ; by = tpixelf ; if ( which ) { bx += SLOPEOFFSET ; by += SLOPEOFFSET ; } /* judge */ if ( bx < x && x < by ) { result = ON ; } return result ; } byte is_target_out(word x) { byte result ; /* default */ result = OFF ; /* judge */ if ( x > tpixelf+SLOPEOFFSET ) { result = ON ; } return result ; } void rs_putchar(char x) { Serial.write(x); } void rs_puts(char *x) { while ( *x ) { rs_putchar( *x ) ; x++ ; } } void show_digit4(word x) { byte j ; char msg[4] ; /* separate */ for ( j = 0 ; j < 4 ; j++ ) { *(msg+3-j) = x % 10 + '0' ; x /= 10 ; } /* zero suppress */ if ( *(msg+0) == '0' ) { *(msg+0) = ' ' ; if ( *(msg+1) == '0' ) { *(msg+1) = ' ' ; if ( *(msg+2) == '0' ) { *(msg+2) = ' ' ; } } } /* show */ for ( j = 0 ; j < 4 ; j++ ) { rs_putchar( *(msg+j) ); } } void show_help() { rs_puts("? help"); crlf(); rs_puts("R reset and initialize"); crlf(); rs_puts("E execute"); crlf(); rs_puts("P show graphic parameters"); crlf(); rs_puts("S show raw values"); crlf(); rs_puts("B show binary values"); crlf(); } void send_xck(byte x) { if ( x ) { PORTD |= (1 << GBC_XCK_BIT); //delayMicroseconds(1); } else { PORTD &= ~(1 << GBC_XCK_BIT); } } void send_sin(byte x) { if ( x ) { PORTD |= (1 << GBC_SIN_BIT); } else { PORTD &= ~(1 << GBC_SIN_BIT); } } void send_load(byte x) { if ( x ) { PORTD |= (1 << GBC_LOAD_BIT); } else { PORTD &= ~(1 << GBC_LOAD_BIT); } } void send_rst_primitive(byte x) { if ( x ) { PORTD |= (1 << GBC_XRST_BIT); } else { PORTD &= ~(1 << GBC_XRST_BIT); } } void send_start_primitive(byte x) { if ( x ) { PORTD |= (1 << GBC_START_BIT); } else { PORTD &= ~(1 << GBC_START_BIT); } } void send_gbc(word x) { word px ; byte i ; /* generate code */ px = x ; /* disable LOAD */ send_load( OFF ); /* transfer */ for ( i = 0 ; i < 11 ; i++ ) { /* enable LOAD */ if ( i == 10 ) { send_load( ON ); } /* impress bit data */ send_sin( OFF ) ; if ( px & 0x400 ) { send_sin( ON ) ; } /* CLOCK : H */ send_xck( ON ) ; /* shift */ px <<= 1 ; /* CLOCK : L */ send_xck( OFF ) ; } /* return initial logic state */ send_sin( OFF ) ; send_load( OFF ); } void send_rst() { /* enable RESET */ send_rst_primitive( OFF ) ; /* CLOCK : H */ send_xck( ON ) ; /* CLOCK : L */ send_xck( OFF ) ; /* disable */ send_rst_primitive( ON ) ; } void send_start() { /* enable */ send_start_primitive( ON ); /* CLOCK : H */ send_xck( ON ) ; /* CLOCK : L */ send_xck( OFF ) ; /* disable */ send_start_primitive( OFF ); } void init_gbc() { byte i ; /* reset */ send_rst() ; /* send parameters */ for ( i = 0 ; i < 8 ; i++ ) { send_gbc( (i << 8) | *(gbcpam+i) ); } } char get_asc(byte x) { char result ; result = '0' ; if ( x > 10 ) { result = x - 10 + 'A' ; } else { result = x + '0' ; } return result ; } void show_gbc_param() { byte i ; byte tmp ; char msg[2] ; for ( i = 0 ; i < 8 ; i++ ) { /* register number */ rs_putchar( i + '0' ) ; rs_putchar(' '); /* get parameter */ tmp = *(gbcpam+i) ; *(msg+0) = get_asc( (tmp >> 4) & 15 ) ; *(msg+1) = get_asc( tmp & 15 ) ; /* show */ rs_putchar( *(msg+0) ); rs_putchar( *(msg+1) ); /* new line */ crlf() ; } } void crlf() { rs_putchar('\r'); rs_putchar('\n'); } byte get_read_state() { byte result ; /* default */ result = OFF ; /* judge */ if ( PIND & (1 << GBC_READ_BIT) ) { result = ON ; } return result ; } void gbc_sampling() { word ii ; word cmax ; word cmin ; byte rflagx ; word cth ; /* default */ cmax = 0 ; cmin = 1023 ; /* read flag */ rflagx = OFF ; /* send start */ send_start(); /* reading */ gcnt = 0 ; xgcnt = 0 ; for ( ii = 0 ; ii < BMAX ; ii++ ) { /* send XCK : H */ send_xck( ON ) ; /* check READ */ if ( rflagx == OFF ) { rflagx = get_read_state() ; } /* send XCK : L */ send_xck( OFF ) ; /* store */ if ( rflagx == ON ) { /* target line */ if ( is_target(OFF,gcnt) ) { /* get data */ sensor = get_ad() ; /* store */ *(gbcrawx+xgcnt) = sensor ; /* increment */ xgcnt++ ; /* max */ if ( cmax < sensor ) { cmax = sensor ; } /* min */ if ( cmin > sensor ) { cmin = sensor ; } } } /* judge */ if ( is_target_out( ii ) == ON ) break ; } /* calculate threshold */ cth = ((cmax+cmin) >> 1) ; /* store */ *(bmax+bcnt) = cmax ; *(bmin+bcnt) = cmin ; *(bth+bcnt) = cth ; /* binary conversion */ for ( ii = 0 ; ii < LINESIZE ; ii++ ) { *(gbcbinx+ii) = 0 ; if ( *(gbcrawx+ii) > cth ) { *(gbcbinx+ii) = 1 ; } } } byte generate_sensor_data(byte x) { byte result ; byte cnt[8] ; byte i ; byte j ; byte k ; byte tmp ; /* default */ result = 0 ; /* clear counter */ for ( i = 0 ; i < 8 ; i++ ) { *(cnt+i) = 0 ; } /* block counter */ for ( i = 0 ; i < 8 ; i++ ) { for ( j = 0 ; j < 8 ; j++ ) { /* calculate pointer */ k = i + (j << 3) ; /* get target data */ tmp = *(gbcbinx+k) ; if ( x == ON ) { tmp = *(gbcbiny+k) ; } /* count */ if ( tmp == 1 ) { *(cnt+j) = *(cnt+j) + 1 ; } } } /* generate */ for ( i = 0 ; i < 8 ; i++ ) { j = 7 - i ; if ( *(cnt+i) > 4 ) { result |= (1 << j); } } return result ; } byte convert_sensor_data(byte x) { byte result ; /* default */ result = ILLEAGAL ; /* all black */ if ( x == 0 ) { result = ALL_BLACK ; } /* half white */ if ( x == 0x70 ) { result = LEFT_WHITE ; } if ( x == 0xf0 ) { result = LEFT_WHITE ; } if ( x == 0xf8 ) { result = LEFT_WHITE ; } if ( x == 0x07 ) { result = RIGHT_WHITE ; } if ( x == 0x0f ) { result = RIGHT_WHITE ; } if ( x == 0x1f ) { result = RIGHT_WHITE ; } /* both white */ if ( x == 0x81 ) { result = BOTH_WHITE ; } if ( x == 0xc1 ) { result = BOTH_WHITE ; } if ( x == 0x83 ) { result = BOTH_WHITE ; } if ( x == 0xc3 ) { result = BOTH_WHITE ; } /* all white */ if ( x == 0xff ) { result = ALL_WHITE ; } /* center line */ if ( x == 0x10 ) { result = CENTER ; } if ( x == 0x08 ) { result = CENTER ; } if ( x == 0x18 ) { result = CENTER ; } if ( x == 0x1c ) { result = CENTER ; } if ( x == 0x38 ) { result = CENTER ; } /* left */ if ( x == 0xc0 ) { result = BIG_LEFT ; } if ( x == 0x60 ) { result = LEFT ; } if ( x == 0x30 ) { result = TINY_LEFT ; } /* right */ if ( x == 0x03 ) { result = BIG_RIGHT ; } if ( x == 0x06 ) { result = RIGHT ; } if ( x == 0x0c ) { result = TINY_RIGHT ; } return 0 ; } void show_raw_data() { byte i ; byte j ; word tmp ; for ( j = 0 ; j < 2 ; j++ ) { for ( i = 0 ; i < LINESIZE ; i++ ) { /* raw value */ tmp = *(gbcrawx+i) ; if ( j ) { tmp = *(gbcrawy+i) ; } /* show */ show_digit4( tmp ) ; rs_putchar(' ') ; /* new line */ if ( (i % 16) == 15 ) { crlf() ; } } /* new line */ crlf(); } } void show_binary_data() { byte i ; byte j ; byte bn ; byte tmp ; for ( j = 0 ; j < 2 ; j++ ) { /* target line */ for ( i = 0 ; i < LINESIZE ; i++ ) { /* get value */ tmp = *(gbcbinx+i) ; /* target line */ if ( j > 0 ) { tmp = *(gbcbiny+i) ; } /* slope line */ /* set code */ bn = '0' ; if ( tmp == 1 ) { bn = '1' ; } /* show */ rs_putchar(bn) ; } /* new line */ crlf() ; } } void send_state(byte x) { byte xportb ; /* clear lower nibble */ xportb = PORTB & 0xf0 ; /* set lower nibble */ xportb |= (x & 15) ; /* impress */ PORTB = xportb ; } void setup() { /* initialize serial port */ Serial.begin(9600); /* define digital pin */ PORTB = 0x10 ; PORTC = 0x0a ; PORTD = 0x15 ; /* set initial state */ DDRB = 0x2f ; DDRC = 0xfc ; DDRD = 0xfa ; /* initialize GBC */ init_gbc(); /* clear flags */ uflag = OFF ; tflag = OFF ; /* initialize variables */ mode = 0 ; rcnt = 0 ; gcnt = 0 ; xgcnt = 0 ; bcnt = 0 ; /* clear shift registers */ sft_sel = 0 ; /* target line */ tline = TARGETLINE - 1 ; tpixelb = (tline << 7) + 32; tpixelf = tpixelb + LINESIZE ; /* command interpreter buffer */ sindex = 0 ; /* set GBC parameters */ *(gbcpam+0) = 0x80 ; *(gbcpam+1) = 0x00 ; *(gbcpam+2) = 0x00 ; *(gbcpam+3) = 0x80 ; *(gbcpam+5) = 0x00 ; *(gbcpam+6) = 0x01 ; *(gbcpam+7) = 0x00 ; *(gbcpam+8) = 0x01 ; /* 50ms period */ MsTimer2::set(50,update_trigger); /* enable */ MsTimer2::start(); /* rapid ADC */ byte tmp ; tmp = ADCSRA & 0xf8 ; tmp |= 0x05 ; ADCSRA = tmp ; } void loop() { byte sflag ; byte bn ; byte cmd ; /* get initial threshold */ if ( bcnt < 3 ) { /* sampling */ gbc_sampling(); /* increment */ bcnt++ ; /* calculate */ if ( bcnt == 3 ) { xmax = bmax[0] + bmax[1] + bmax[2] ; xmax /= 3 ; xmin = bmin[0] + bmin[1] + bmin[2] ; xmin /= 3 ; xth = bth[0] + bth[1] + bth[2] ; xth /= 3 ; } } /* switch handling */ { /* shift */ sft_sel <<= 1 ; /* mask */ sft_sel &= 0x03 ; /* update LSB state */ if ( PINB & 0x10 ) { sft_sel |= ON ; } /* impress */ if ( sft_sel == 3 ) { send_state( statey ) ; } if ( sft_sel == 0 ) { send_state( statex ) ; } } /* trigger */ if ( tflag == ON ) { /* clear flag */ tflag = OFF ; /* execute */ if ( mode < 2 ) { mode = 2 ; } } /* reset and initialize */ if ( mode == 1 ) { /* reset and send parameters */ init_gbc() ; rs_puts("RESET") ; crlf(); rs_puts("set parameters") ; crlf(); /* return first mode */ mode = 0 ; } /* start */ if ( mode == 2 ) { /* start */ send_start() ; rs_puts("START") ; crlf(); /* prepare */ rflag = OFF ; rcnt = 0 ; /* CLK state */ gcnt = 0 ; /* global graphic data counter */ xgcnt = 0 ; /* local graphic data counter */ /* next */ mode = 3 ; } /* get graphic data */ if ( mode == 3 ) { /* ? READ */ if ( rflag == OFF ) { rflag = get_read_state() ; } /* XCK */ if ( rcnt == 0 ) { /* XCK : H */ send_xck( ON ) ; } else { /* XCK : L */ send_xck( OFF ) ; /* get and store */ if ( rflag == ON ) { /* ? target line and target pixel */ sflag = 0 ; if ( is_target(OFF,gcnt) == ON ) { sflag = 1 ; } if ( is_target(ON ,gcnt) == ON ) { sflag = 2 ; } /* store */ if ( sflag > 0 ) { /* get */ sensor = get_ad() ; /* store raw data */ if ( sflag == 1 ) { *(gbcrawx+xgcnt) = sensor ; } if ( sflag == 2 ) { *(gbcrawy+xgcnt) = sensor ; } /* binary conversion */ bn = 0 ; if ( sensor > xth ) { bn = 1 ; } if ( sflag == 1 ) { *(gbcbinx+xgcnt) = bn ; } if ( sflag == 2 ) { *(gbcbiny+xgcnt) = bn ; } /* increment */ xgcnt++ ; xgcnt &= 0x3f ; } /* increment */ gcnt++ ; } } /* increment */ rcnt++ ; rcnt &= ON ; /* judge */ if ( is_target_out(gcnt) == ON ) { /* convert */ statex = convert_sensor_data( generate_sensor_data(OFF) ) ; /* convert */ statey = convert_sensor_data( generate_sensor_data(ON) ) ; /* return first state */ mode = 0 ; } } /* serial handling */ if ( uflag == ON ) { /* clear flag */ uflag = OFF ; /* new line */ crlf(); /* get command */ cmd = *(sbuf+0) ; /* judge */ if ( cmd == '?' ) { show_help() ; } /* reset and initialize */ if ( cmd == 'R' ) { mode = 1 ; } /* execute */ if ( cmd == 'E' ) { mode = 2 ; } /* calculate maximum and minimum */ if ( cmd == 'P' ) { /* parameters */ show_gbc_param(); /* show */ rs_puts("MIN : "); show_digit4( xmin ) ; crlf() ; rs_puts("MAX : "); show_digit4( xmax ) ; crlf() ; rs_puts("threshold : "); show_digit4( xth ) ; crlf(); } /* show raw values */ if ( cmd == 'S' ) { show_raw_data() ; } /* show binary values */ if ( cmd == 'B' ) { show_binary_data() ; } } } /* receive interrupt */ void serialEvent() { char ch; if ( Serial.available() > 0 ) { /* get 1 character */ ch = Serial.read(); /* store */ *(sbuf+sindex) = ch ; /* increment */ sindex++ ; /* judge */ if ( ch == '\r' ) { sindex = 0 ; uflag = ON ; } } }
目次

inserted by FC2 system