Color sensor 컬러 센서 모듈
원문 : http://www.elecfreaks.com/1666.html
1. Color sensor
컬러센서에도 여러 종류가 있지만 여기서 소개하는 컬러센서는 TCS230/TCS3200 컬러 센서입니다. ADJD-S311 컬러 센서는 링크를 참고하세요. 컬러 센서를 직접 만드는 방법도 있습니다. 링크, 링크에서 확인하세요.
Chip: TCS230
Input voltage: DC 3 ~ 5V
Output frequency voltage: 0 ~ 5V
Use bright white LED lights
can be connected directly with Microcontroller
Static detection of the measured object color
Best detection distance: 10mm
PCB size: 31.6 (mm) x24.4 (mm)
2. 연결 방법
Color sensor – Arduino
GND & LED – GND ,
OE – GND,
VCC – VCC,
S0 – D6,
S1 – D5,
S2 – D4,
S3 – D3,
OUT – D2
OE 핀을 GND에 연결하면 항상 이 모듈을 enable 상태로 두겠다는 의미입니다. OE 핀을 digital 핀에 연결해서 digitalWrite(OE, LOW); 해도 같은 효과가 됩니다.
3. 동작 방법
주의!!! 3-4 챕터에 소개된 소스코드가 제대로 동작하지 않는 분은 마지막 챕터에 있는 DFRobot 코드를 이용해서 테스트 하세요. 구동하는 원리는 같습니다.
#define S0 6 #define S1 5 #define S2 4 #define S3 3 #define OUT 2
OUT(Signal) 핀은 빛의 세기에 비례하는 square wave (50% duty cycle) 가 출력되는 핀입니다. 즉, OUT 핀으로 High 상태가 얼마나 반복되는가를 카운트 하면 해당되는 주파수를 알 수 있습니다. Red, Green, Blue 모드 상태에서 한 번씩, 총 3번 OUT 핀으로 출력되는 주파수를 체크하면 R-G-B 파장별 빛의 세기를 알 수 있습니다.
보통 아두이노에서는 UNO 기준 2개의 interrupt 핀을 제공합니다. (Digital 2번, 3번) 여기서는 OUT 핀을 D2에 연결하고 RISING 상태 (HIGH로 변경되는 상태) 에서 자동으로 callback 함수가 호출되도록해서 카운트를 합니다.
일정 시간이 지나면 count 를 종료하고 결과를 저장한 뒤, R->G->B 순서대로 모드를 전환하도록 해야 합니다. 이를 위해 16비트 하드웨어 타이머를 지원하는 라이브러리를 사용합니다. 다음 링크에서 타이머 라이브러리를 받아서 설치해야 합니다. Timer1 Library.
초기화 코드
// Init TSC230 and setting Frequency. void TSC_Init() { pinMode(S0, OUTPUT); pinMode(S1, OUTPUT); pinMode(S2, OUTPUT); pinMode(S3, OUTPUT); pinMode(OUT, INPUT); digitalWrite(S0, LOW); // OUTPUT FREQUENCY SCALING 2% digitalWrite(S1, HIGH); }
S0, S1 핀은 OUT 핀으로 출력되는 주파수의 scale을 결정하는 핀입니다. S0-LOW, S1-HIGH 로 설정하면 2% scale로 설정됩니다. 측정 범위와 측정 능력을 micro-controller 보드에 따라 변경하기 위해 scaling을 합니다.
S2, S3 핀은 R-G-B 필터를 선택하는데 사용되는 핀입니다.
// Select the filter color void TSC_FilterColor(int Level01, int Level02) { if(Level01 != 0) Level01 = HIGH; if(Level02 != 0) Level02 = HIGH; digitalWrite(S2, Level01); digitalWrite(S3, Level02); } void TSC_Count() { g_count ++ ; } void TSC_Callback() { switch(g_flag) { case 0: Serial.println("->WB Start"); TSC_WB(LOW, LOW); //Filter without Red break; case 1: Serial.print("->Frequency R="); Serial.println(g_count); g_array[0] = g_count; TSC_WB(HIGH, HIGH); //Filter without Green break; case 2: Serial.print("->Frequency B="); Serial.println(g_count); g_array[1] = g_count; TSC_WB(LOW, HIGH); //Filter without Blue break; case 3: Serial.print("->Frequency G="); Serial.println(g_count); Serial.println("->WB End"); g_array[2] = g_count; TSC_WB(HIGH, LOW); //Clear(no filter) break; default: g_count = 0; break; } } void TSC_WB(int Level0, int Level1) //White Balance { g_count = 0; g_flag ++; TSC_FilterColor(Level0, Level1); Timer1.setPeriod(1000000); // set 1s period } void setup() { TSC_Init(); Serial.begin(9600); Timer1.initialize(); // defaulte is 1s Timer1.attachInterrupt(TSC_Callback); attachInterrupt(0, TSC_Count, RISING); delay(4000); for(int i=0; i<3; i++) Serial.println(g_array[i]); g_SF[0] = 255.0/ g_array[0]; //R Scale factor g_SF[1] = 255.0/ g_array[1] ; //G Scale factor g_SF[2] = 255.0/ g_array[2] ; //B Scale factor Serial.println(g_SF[0]); Serial.println(g_SF[1]); Serial.println(g_SF[2]); }
White Balancing은 시스템에게 어떤 값이 흰색이냐를 알려주는 과정입니다. 이론적으로는 RGB 가 동일한 값이면 흰색이라고 할 수 있지만 실제로는 TSC-230 모듈의 RGB 색상에 대한 sensitivity가 틀립니다. 따라서 사용전에 미리 WB를 맞춰줘야 정확한 결과를 얻을 수 있습니다.
WB 조정을 위해 고정된 시간 (여기서는 1초) 동안 RGB 색상별로 주파수를 측정합니다. 그리고 측정된 주파수 값이 0~255 사이의 색상 값으로 변환될 수 있도록 ScaleFactor 를 계산합니다. 실제 사용할 때는 측정 값에 Scale Factor를 곱해서 나온 값을 색상 값으로 사용하게 됩니다.
이상의 과정이 setup() 함수 안에서 이루어집니다. setup() 함수에서는 Timer1.attachInterrrupt(TSC_Callback) 을 실행해서 일정 시간마다 TSC_Callback() 함수를 호출하게 합니다. TSC_Callback() 함수는 RGB 색상값을 계산하고 다음 색상모드로 변경하는 역할을 합니다. setup() 함수는 attachInterrupt(0, TSC_Count, RISING) 호출을 통해 D2번 핀에 대한 인터럽트 함수를 등록합니다. D2 핀으로 들어오는 신호에서 HIGH 가 반복될 때 마다 count 가 증가하도록 합니다. RGB 모드별로 측정이 끝나면 g_array[] 배열에 색상별 주파수 값이 들어있습니다. g_SF[] 배열은 색상값을 만들기 위해 사용하는 Scale Factor 값을 저장하고 있습니다.
void loop() { g_flag = 0; for(int i=0; i<3; i++) Serial.println(int(g_array[i] * g_SF[i])); delay(4000); }
실제 컬러 측정은 위 코드에서와 같이 4초간 측정을 위한 대기시간을 가지면 됩니다. 4초간 대기가 끝나면 저장된 g_array[], g_SF 값을 곱해서 색상 값을 출력하면 됩니다. (혹은 1초 단위로 RGB 값을 순서대로 출력해봐도 됩니다.)
아래는 이상의 코드를 이용해서 결과를 출력한 화면입니다.
1번 박스의 값이 1초 동안 White Balancing 용으로 측정된 RGB 값입니다. (Red=1126 , Green=707 and Blue =774). 이 값으로 계산한 Scale Factor 가 2번 박스안에 있는 값입니다. 이제 측정되는 값은 3번 박스의 값이 최대값이 되도록 조정될 것입니다.
초기화 이후 컬러 센서로 측정된 결과는 다음과 같습니다.
4번 값이 측정된 결과 값입니다.
4. 소스 코드 (스케치)
위 설명에서 사용된 코드를 손봐서 사용해도 되지만, 불필요한 부분이 많습니다. 아래 코드가 좀 더 깔끔하게 다듬어진 코드입니다. 아래 코드에서는 타이머를 사용하긴 하지만 D2 핀을 이용한 interrupt를 사용하지 않음을 주의하세요!! (대신 일정 시간동안 while 루프를 돌면서 계속 OUT 핀의 값을 읽습니다.)
그리고 기본으로 지정된 핀이 D8~D13 핀입니다. 자신의 프로젝트에 맞게 수정해서 사용하세요.
/********************************************************************* ** Device: TCS230 ** ** File: EF_TCS230.pde ** ** ** ** Created by ElecFreaks Robi.W /24 Augest 2011 ** ** ** ** Description: ** ** This file is a sample code for your reference.It's the demo of ** ** TCS230-PROGRAMMABLE COLOR LIGHT-TO-FREQUENCY CONVERTER MODULE. ** ** ** ** This demo code is free software; you can redistribute it and/or ** ** modify it under the terms of the GNU Lesser General Public ** ** License as published by the Free Software Foundation; either ** ** version 2.1 of the License, or (at your option) ** ** any later version. ** ** ** ** Copyright (C) 2011 ElecFreaks Corp. ** ** ** ** ** ** http://www.elecfreaks.com ** *********************************************************************/ #include <TimerOne.h> #define OUT 8 #define S2 9 #define S3 10 #define S0 11 #define S1 12 #define OE 13 #define Filters_R 0 #define Filters_G 1 #define Filters_B 2 int Count[3] = {0}; int G_flag = 1; void setup() { TCS230_init(); Select_Filters(3); //default, no fiter Timer1.initialize(); // default 1S Timer1.attachInterrupt(callback); Serial.begin(9600); } void TCS230_init() { pinMode(OUT, INPUT); pinMode(S2, OUTPUT); pinMode(S3, OUTPUT); pinMode(S0, OUTPUT); pinMode(S1, OUTPUT); pinMode(OE, OUTPUT); digitalWrite(S0, LOW); // 2% of Output Frequence digitalWrite(S1, HIGH); digitalWrite(OE, LOW); } void Select_Filters(int RGB) { switch(RGB) { case Filters_R: //Red digitalWrite(S2, LOW); digitalWrite(S3, LOW); Serial.println("-----select Red color"); break; case Filters_G: //Green digitalWrite(S2, HIGH); digitalWrite(S3, HIGH); Serial.println("-----select Green color"); break; case Filters_B: //Blue digitalWrite(S2, LOW); digitalWrite(S3, HIGH); Serial.println("-----select Blue color"); break; default: //Clear(no filter) digitalWrite(S2, HIGH); digitalWrite(S3, LOW); Serial.println("-----no filter"); break; } } void Measure_Count(int RGB ) //For white balance correction { int tmp = 0; while(1) { if(digitalRead(OUT) == 1) { if(G_flag == 0) { Count[RGB] = tmp; Serial.print("tmp="); Serial.println(tmp); break; } tmp++; } } } void callback() { G_flag = 0; } void loop() { Timer1.restart(); for(int i=0; i<3; i++) { Select_Filters(i); Timer1.setPeriod(10000); //set 10ms Measure_Count(i); G_flag = 1; Serial.println(Count[i]); } delay(3000); }
5. 좀 더 쉬운 동작코드
앞선 예제의 코드가 제대로 동작하지 않는다면 아래 링크의 코드를 사용해보세요.
센서값 측정하는 방식은 앞서 설명한 예제들과 같습니다. 왜인지는 모르겠지만 앞선 코드들은 제가 가진 모듈에서는 제대로 동작하질 않던데 DFRobot 코드는 제대로 동작했습니다.
이 코드는 연결방법이 조금 다릅니다. 코드 최상단에 적혀져 있는대로 연결을 다시 해주던지 코드의 핀 값을 바꿔줘야 합니다.
OE 핀이 없는 모듈의 경우는 연결하지 않아도 됩니다.
LED 핀이 있는 경우 GND 핀에 연결해야 불이 켜지는 경우도 있고, LED 핀을 디지털핀에 연결해서 digitalWrite(LED_pin, HIGH) 해줘야 LED 가 켜지는 경우도 있습니다.