目次

カラーセンサー情報取得

 秋月電子で販売されているカラーセンサーを利用して
 ArduinoとProcessingの協調システムをつくります。

 カラーセンサーは、次のように半田付けしました。



 ArduinoとProcessingの役割分担を決めます。

 Arduino担当

  2つの機能を持たせます。

  自動計測では、3秒周期でデータを取得して
  色に関する情報を内部変数に格納します。

  ワンショット計測は、Processingコードからトリガー
  を受け取って、その場で色に関する情報を取得します。
  結果に関しても、Processingコードからの要求で
  出力します。

 Processing担当

  Arduinoにコマンドを送り、現在の色情報を取得します。
  同時に色情報の%を矩形で表示します。



  コマンドを決めます。

  ボタンの矩形領域を定義して、操作しやすくします。




Arduinoスケッチ

 Arduinoにカラーセンサーを接続するため、デジタルピンの  どこを利用するのかを決めます。  3秒ごとに自動でカラーセンサーから、情報取得するように  タイマー2で1.5秒ごとにカウンタをインクリメントします。  カウンタ値が奇数のときに、計測トリガーを出力します。 void update_trigger(void) { send_led( xcnt & ON ); xcnt++ ; if ( xcnt & ON ) { tflag = ON ; } }  1.5秒ごとにLEDの点灯、消灯を切換えると同時に、計測の  トリガーに利用します。LEDの点滅で、Arduinoが動作中と  判断できます。  コマンドを定義します。  コマンドを定義したなら、対応する処理を定義します。  help   Processingでは必要ありませんが、TeraTermのような端末ソフト   で動作テストするときに使います。関数でまとめます。 void show_help() { rs_puts("? help") ; crlf(); rs_puts("M one shot measure") ; crlf(); rs_puts("C show color values") ; crlf(); rs_puts("H high range") ; crlf(); rs_puts("L low range") ; crlf(); rs_puts("S show status") ; crlf(); }   関数を起動するのは、コマンドインタプリタを使います。 if ( cmd == '?' ) { show_help() ; }  one shot measure   計測すればよいので、関数を利用します。 void get_color(byte which,byte xd) { byte i ; long rgb[3] ; /* set RANGE */ put_range( which ) ; /* disable GATE and CK */ put_gate(OFF); put_ck(OFF); /* open GATE */ put_gate( ON ) ; delay(xd+2); put_gate(OFF); /* loop */ for ( i = 0 ; i < 3 ; i++ ) { /* interval */ delayMicroseconds(4); /* get RGB information */ *(rgb+i) = get_color_value() ; } } word get_color_value() { word result ; byte i ; /* clear */ result = 0 ; /* loop */ for ( i = 0 ; i < 12 ; i++ ) { /* shift */ result >>= 1 ; /* CK : H */ put_ck( ON ) ; /* delay */ delayMicroseconds(2); /* get data */ if ( PINC & 0x01 ) { result |= 0x800 ; } /* CK : L */ put_ck( OFF ) ; /* delay */ delayMicroseconds(2); } /* adjust */ result &= 0xfff ; return( result ); }   12ビットデータ入力を3回として、12ビットデータ入力は   独立した関数でまとめます。   コマンドインタプリタの扱いは、以下。 if ( cmd == 'M' ) { get_color(bflag,timcnt); }  show color values   各色は0から4095の値をとるので、10進数4桁を表示する   独立した関数を用意し、その関数をサブで利用します。 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 ; } /* show */ for ( j = 0 ; j < 4 ; j++ ) { rs_putchar( *(msg+j) ); } } void show_values() { /* copy */ rmdat = rxdat ; gmdat = gxdat ; bmdat = bxdat ; /* show */ rs_putchar('C'); show_digit4( rmdat ); show_digit4( gmdat ); show_digit4( bmdat ); /* new line */ crlf(); }   コマンドインタプリタの扱いは、以下。 if ( cmd == 'C' ) { show_values(); }  high range   フラグを用意してあるので、セットして対応。 if ( cmd == 'H' ) { bflag = ON ; }  low range   フラグを用意してあるので、リセットして対応。 if ( cmd == 'L' ) { bflag = OFF ; }  show status   計測しているかどうかは、変数値の奇数、偶数で   判断しています。 if ( cmd == 'S' ) { rs_putchar('S'); if ( xcnt & ON ) { rs_putchar('m'); } else { rs_putchar('i'); } crlf(); }  スケッチとしてまとめると、以下。 #include <MsTimer2.h> #define OFF 0 #define ON OFF+1 #define LD 0 #define HD 1 /* color sensor pin assignment */ #define RANGE_BIT 3 #define CK_BIT 2 #define GATE_BIT 1 #define DOUT_BIT 0 /* monitor LED */ #define LED_BIT 5 /* global variables */ byte tflag ; byte bflag ; byte uflag ; byte sindex ; byte sbuf[8] ; byte xcnt ; word rxdat ; word gxdat ; word bxdat ; word rmdat ; word gmdat ; word bmdat ; byte timcnt ; void send_led(byte x) { if ( x ) { PORTB |= (1 << LED_BIT) ; } else { PORTB &= ~(1 << LED_BIT) ; } } void update_trigger(void) { send_led( xcnt & ON ); xcnt++ ; if ( xcnt & ON ) { tflag = ON ; } } void rs_putchar(char x) { Serial.write(x); } void rs_puts(char *x) { while ( *x ) { rs_putchar( *x ) ; x++ ; } } void crlf() { rs_putchar('\r'); rs_putchar('\n'); } byte get_hex(char x) { byte result ; result = 0 ; if ( '0' <= x && x <= '9' ) { result = x - '0' ; } if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; } if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; } return result ; } 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 ; } /* show */ for ( j = 0 ; j < 4 ; j++ ) { rs_putchar( *(msg+j) ); } } void show_help() { rs_puts("? help") ; crlf(); rs_puts("M one shot measure") ; crlf(); rs_puts("C show color values") ; crlf(); rs_puts("H high range") ; crlf(); rs_puts("L low range") ; crlf(); rs_puts("S show status") ; crlf(); } void get_color(byte which,byte xd) { byte i ; long rgb[3] ; /* set RANGE */ put_range( which ) ; /* disable GATE and CK */ put_gate(OFF); put_ck(OFF); /* open GATE */ put_gate( ON ) ; delay(xd+2); put_gate(OFF); /* loop */ for ( i = 0 ; i < 3 ; i++ ) { /* interval */ delayMicroseconds(4); /* get RGB information */ *(rgb+i) = get_color_value() ; } } void put_range(byte x) { if ( x == ON ) { PORTC |= (1 << RANGE_BIT) ; } else { PORTC &= ~(1 << RANGE_BIT) ; } } void put_gate(byte x) { if ( x == HD ) { PORTC |= (1 << GATE_BIT) ; } else { PORTC &= ~(1 << GATE_BIT) ; } } void put_ck(byte x) { if ( x == ON ) { PORTC |= (1 << CK_BIT) ; } else { PORTC &= ~(1 << CK_BIT) ; } } word get_color_value() { word result ; byte i ; /* clear */ result = 0 ; /* loop */ for ( i = 0 ; i < 12 ; i++ ) { /* shift */ result >>= 1 ; /* CK : H */ put_ck( ON ) ; /* delay */ delayMicroseconds(2); /* get data */ if ( PINC & 0x01 ) { result |= 0x800 ; } /* CK : L */ put_ck( OFF ) ; /* delay */ delayMicroseconds(2); } /* adjust */ result &= 0xfff ; return( result ); } void show_values() { /* copy */ rmdat = rxdat ; gmdat = gxdat ; bmdat = bxdat ; /* show */ show_digit4( rmdat ); show_digit4( gmdat ); show_digit4( bmdat ); /* new line */ crlf(); } void setup() { /* initialize serial port */ Serial.begin(9600); sindex = 0 ; /* define digital pin */ PORTB = 0x00 ; PORTC = 0x03 ; PORTD = 0x01 ; /* set initial state */ DDRB = 0xff ; DDRC = 0xfc ; DDRD = 0xfe ; /* clear flags */ tflag = OFF ; bflag = OFF ; uflag = OFF ; /* initialize variables */ timcnt = 0 ; xcnt = 0 ; /* 1500ms period */ MsTimer2::set(1500,update_trigger); /* enable */ MsTimer2::start(); } void loop() { byte cmd ; /* timer handling */ if ( tflag == ON ) { /* clear flag */ tflag = OFF ; /* measure */ get_color(bflag,timcnt); } /* serial handling */ if ( uflag == ON ) { /* clear flag */ uflag = OFF ; /* new line */ crlf(); /* get command */ cmd = *(sbuf+0) ; /* help */ if ( cmd == '?' ) { show_help() ; } /* one shot measure */ if ( cmd == 'M' ) { get_color(bflag,timcnt); } /* show color values */ if ( cmd == 'C' ) { show_values(); } /* set Hight range */ if ( cmd == 'H' ) { bflag = ON ; } /* set Low range */ if ( cmd == 'L' ) { bflag = OFF ; } /* show status */ if ( cmd == 'S' ) { rs_putchar('S'); if ( xcnt & ON ) { rs_putchar('m'); } else { rs_putchar('i'); } crlf(); } } } /* 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 ; } } }

Processingスケッチ

 スケッチを動かしたときのGUIを考えます。  ボタンを画像で用意していきます。  ボタンをクリックしたときの処理を定義していきます。  Exit   Exitの領域をクリックしたときは、終了させます。 if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,200+YBEGIN,200+YBEGIN+HEIGHT) ) { exit(); }  Measure   ボタン領域をクリックしたときは、ArduinoにコマンドMを送信。 if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,YBEGIN,YBEGIN+HEIGHT) ) { /* println("Measure"); */ cport.write('M'); cport.write('\r'); }  Color   ボタン領域をクリックしたときは、ArduinoにコマンドCを送信。 if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,30+YBEGIN,30+YBEGIN+HEIGHT) ) { /* println("Color"); */ cport.write('C'); cport.write('\r'); }  Status   ボタン領域をクリックしたときは、ArduinoにコマンドSを送信。 if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,60+YBEGIN,60+YBEGIN+HEIGHT) ) { /* println("Status"); */ cport.write('S'); cport.write('\r'); }  H range   ボタン領域をクリックしたときは、ArduinoにコマンドHを送信。 if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,100+YBEGIN,100+YBEGIN+HEIGHT) ) { /* println("range H"); */ cport.write('H'); cport.write('\r'); }  L range   ボタン領域をクリックしたときは、ArduinoにコマンドLを送信。 if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,130+YBEGIN,130+YBEGIN+HEIGHT) ) { /* println("range L"); */ cport.write('L'); cport.write('\r'); }  関数drawの内容を定義します。  バー描画   イベントフラグで通知されたなら、関数を呼び出します。 if ( dflag == true ) { /* clear flag */ dflag = false ; /* draw */ bar_draw(xr,xg,xb); }   実際のバー描画は、専用関数で実行。 void bar_draw(int rx,int gx,int bx) { /* red */ fill(255, 0, 0); rect(BSX, BSY,rx,BSHEIGHT); /* green */ fill( 0,255, 0); rect(BSX,BSHEIGHT+BSY,gx,BSHEIGHT); /* blue */ fill( 0, 0,255); rect(BSX,2*BSHEIGHT+BSY,bx,BSHEIGHT); }  データ入力   受信割込みから、データが入ったと通知がくるので   各色の成分値を計算します。 if ( uflag == true ) { /* clear flag */ uflag = false ; /* get command */ cmd = sbuf[0] ; /* get color values */ if ( cmd == 'C' ) { xr = 0 ; xg = 0 ; xb = 0 ; for ( int i = 1 ; i < 5 ; i++ ) { /* multiply */ xr *= 10 ; xg *= 10 ; xb *= 10 ; /* digit -> value */ xr += get_hex( sbuf[i] ) ; xg += get_hex( sbuf[i+4] ) ; xb += get_hex( sbuf[i+8] ) ; } /* send draw */ dflag = true ; }   受信バッファには、情報が数字で格納されているので   数値に変換します。 byte get_hex(byte x) { byte result ; /* default */ result = 0 ; /* judge */ if ( '0' <= x && x <= '9' ) { result = (byte)(x - 48) ; } if ( 'A' <= x && x <= 'F' ) { result = (byte)(x - 55) ; } if ( 'a' <= x && x <= 'f' ) { result = (byte)(x - 87) ; } return result ; }  スケッチとしてまとめると、以下。 PImage imgMeasure ; PImage imgColor ; PImage imgStatus ; PImage imgRH ; PImage imgRL ; PImage imgExit ; import processing.serial.*; Serial cport; /* button caption */ PImage imgMeasure ; PImage imgColor ; PImage imgStatus ; PImage imgRH ; PImage imgRL ; PImage imgExit ; /* frame rate */ int FRATE = 45 ; int WX = 320 ; int WY = 240 ; int XBEGIN = 0 ; int YBEGIN = 0 ; int WIDTH = 80 ; int HEIGHT = 24 ; int BSX = 100 ; int BSY = 30 ; int BSHEIGHT = 20 ; int xr ; int xg ; int xb ; boolean dflag ; byte[] sbuf ; byte sindex; boolean uflag ; byte cmd ; byte get_hex(byte x) { byte result ; /* default */ result = 0 ; /* judge */ if ( '0' <= x && x <= '9' ) { result = (byte)(x - 48) ; } if ( 'A' <= x && x <= 'F' ) { result = (byte)(x - 55) ; } if ( 'a' <= x && x <= 'f' ) { result = (byte)(x - 87) ; } return result ; } boolean isRangeOk(int x,int bx,int ex) { boolean result ; /* default */ result = false ; /* judge */ if ( bx <= x && x <= ex ) { result = true ; } return result ; } void bar_draw(int rx,int gx,int bx) { /* red */ fill(255, 0, 0); rect(BSX, BSY,rx,BSHEIGHT); /* green */ fill( 0,255, 0); rect(BSX,BSHEIGHT+BSY,gx,BSHEIGHT); /* blue */ fill( 0, 0,255); rect(BSX,2*BSHEIGHT+BSY,bx,BSHEIGHT); } void setup() { /* title caption */ frame.setTitle("Color sensor"); /* select framerate */ frameRate(FRATE); /* select displya dimension */ size(WX,WY); /* select back ground color with WHITE */ background(255); /* initialize serial port */ cport = new Serial(this,"COM1",9600); sindex = 0 ; dflag = false ; uflag = false ; /* get image */ imgMeasure = loadImage("measure.png"); imgColor = loadImage("color.png"); imgStatus = loadImage("status.png"); imgRH = loadImage("rh.png"); imgRL = loadImage("rl.png"); imgExit = loadImage("exit.png"); /* event flag */ lflag = false ; rflag = false ; /* test string */ textSize( 12 ); textAlign( LEFT ); } void draw() { /* */ fill(0,0,0); text("element",100,20); /* draw button */ image(imgMeasure,XBEGIN, 0+YBEGIN); image(imgColor ,XBEGIN, 30+YBEGIN); image(imgStatus ,XBEGIN, 60+YBEGIN); image(imgRH ,XBEGIN,100+YBEGIN); image(imgRL ,XBEGIN,130+YBEGIN); image(imgExit ,XBEGIN,200+YBEGIN); /* data handling */ if ( uflag == true ) { /* clear flag */ uflag = false ; /* get color values */ xr = 0 ; xg = 0 ; xb = 0 ; for ( int i = 1 ; i < 5 ; i++ ) { /* multiply */ xr *= 10 ; xg *= 10 ; xb *= 10 ; /* digit -> value */ xr += get_hex( sbuf[i] ) ; xg += get_hex( sbuf[i+4] ) ; xb += get_hex( sbuf[i+8] ) ; } /* send draw */ dflag = true ; } /* show bar */ if ( dflag == true ) { /* clear flag */ dflag = false ; /* draw */ bar_draw(xr,xg,xb); } /* command interpreter */ if ( uflag == true ) { /* clear flag */ uflag = false ; /* get command */ cmd = sbuf[0] ; /* status */ if ( cmd == 'S' ) { fill(0,0,0); if ( sbuf[1] == 'i' ) { text("idle",100,200); } if ( sbuf[1] == 'm' ) { text("measure",100,200); } } /* get color values */ if ( cmd == 'C' ) { xr = 0 ; xg = 0 ; xb = 0 ; for ( int i = 1 ; i < 5 ; i++ ) { /* multiply */ xr *= 10 ; xg *= 10 ; xb *= 10 ; /* digit -> value */ xr += get_hex( sbuf[i] ) ; xg += get_hex( sbuf[i+4] ) ; xb += get_hex( sbuf[i+8] ) ; } /* send draw */ dflag = true ; } } } void mouseClicked() { /* enable */ if ( mouseButton == LEFT ) { /* Measure */ if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,YBEGIN,YBEGIN+HEIGHT) ) { /* println("Measure"); */ cport.write('M'); cport.write('\r'); } /* Color */ if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,30+YBEGIN,30+YBEGIN+HEIGHT) ) { /* println("Color"); */ cport.write('C'); cport.write('\r'); } /* Status */ if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,60+YBEGIN,60+YBEGIN+HEIGHT) ) { /* println("Status"); */ cport.write('S'); cport.write('\r'); } /* range H */ if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,100+YBEGIN,100+YBEGIN+HEIGHT) ) { /* println("range H"); */ cport.write('H'); cport.write('\r'); } /* range L */ if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,130+YBEGIN,130+YBEGIN+HEIGHT) ) { /* println("range L"); */ cport.write('L'); cport.write('\r'); } /* Exit */ if ( isRangeOk(mouseX,XBEGIN,XBEGIN+WIDTH) && isRangeOk(mouseY,200+YBEGIN,200+YBEGIN+HEIGHT) ) { exit(); } } } void serialEvent(Serial p) { byte ch ; if ( cport.available() > 0 ) { ch = (byte)cport.read(); /* judge */ if ( ch == '\r' ) { uflag = true ; sindex = 0 ; } /* store */ sbuf[sindex] = ch ; /* update */ sindex++ ; } }

目次

inserted by FC2 system