目次
前
次
画像処理スクリプト
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 ;
}
}
}
目次
前
次