網頁最後修改時間:2018/02/27
撰寫這篇網頁的目的是為了說明 TCS3200 顏色辨識感測模組如何進行白平衡校正,經由校正後的係數補償至物體取色過程中的誤差,得到接近物體色彩的目的,而取色的結果將使用 WS2812B RGB LED 顯示出來作為驗證。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
有購買商品的使用者,網頁中所需相關資料已放置於雲端硬碟,請自行下載使用!
其餘的使用者,程式碼都在網頁中,請自行複製貼上使用。
編譯環境:https://www.arduino.cc/en/Main/Software
Arduino IDE V1.6.5-r5;Arduino IDE V1.6.7
2018/02/27 更新:
新版本 TCS34725 顏色感測器有更好的效果,可至下面連結網頁看測試影片。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
*********************************************************************************
可使用於顯示全彩的可程式的 RGB LED 可至分類賣場購買:
*********************************************************************************
簡介:
一般所看到的物品顏色,實際上是物體吸收了照射在其表面的白光而反射出一部分可讓人眼反應看到的有色成分,任何一種顏色都可以利用 RGB 三原色依照不同的比例混合而成。若手邊有 RGB LED 的話,可以仔細一點看進去晶片裡面,就不難發現裡面會有三顆很小的發光晶片,而這三顆就是 紅色 (Red)、綠色 (Green) 和藍色 (Blue) LED 被封裝在一個區域裡面;當要發出白光時,就是將其全比例輸出而得,而其他顏色就是依照比例來得到。
WiKi:RGB color model
在這裡我們不深入去探討色彩,我們著重的是如何得到待測物體表面顏色,以及怎麼呈現相同的顏色。
硬體參考接線圖:
線路使用 Arduino UNO R3 ( 其他 Arduino 開發板也可以 )作為主控,VCC 和 GND 全部都是使用來自 UNO 的 +5V 電源 ( 板上有多個地方都有 +5V 可以接 )。
TCS3200 的 OUT 接 UNO D2;S0 - S4 分別接到 UNO D3 - D6。
WS2812B 使用 11 顆 ( 當使用顆數變多時,要考慮使用外接 +5V 電源;當然也可以使用其他的可定址的 RGB LED ... 等 ),DIN 控制輸入訊號接到 UNO D12。
硬體參考接線圖 |
要取得與待測物體接近的表面顏色,首先就是要建立取色基準,而這個基準的建立稱為白平衡;也就是要知道什麼才是 TCS3200 認定的白色。
白色的 RGB 混色就是全輸出,對於使用 8-bit 顏色分級就是 R:255, G:255, B:255。白平衡取得的 RGB 三原色的數值要再個別除以 255,以得到 RGB 之後取物體表面顏色的補償係數。
TCS3200 對於擷取的顏色,是以不同頻率的 ( 50% ) 方波輸出結果,而且分三次分別取得三原色 ( RGB )。三原色的取得不需要分順序,但是必須先設定要過濾取得的三原色 ( R、G 和 B ) 是哪一個 ? 顏色過濾的設定,使用模組上的 S2 和 S3 接腳,如下所示
S2
|
S3
|
過 濾 顏 色
|
L
|
L
|
Red
|
L
|
H
|
Blue
|
H
|
L
|
Clean ( 不過濾 )
|
H
|
H
|
Green
|
簡單取得頻率的方法:就是設定輸出截止時間為 1 秒,因為單位時間事件重複的次數就是頻率 (Hz)。
白平衡校正與取得物品表面顏色用的方法都是一樣的,只不過第一次物體取色是取白色!
取得的物體表面顏色頻率值乘上對應的白平衡 RGB 參數,就是可以用來輸出到 WS2812B RGB LED 上的 RGB 顏色值。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 白平衡校正說明:
進行白平衡校正之前,
- 請先準備一張白紙 ( 最好很白,越接近白色效果越好 ! )
- 安裝 Arduino 函式庫 TimerOne
- TimerOne.zip ( 下載後解壓至 libraries 目錄下 )
- Arduino IDE 選單:"Sketch / Include Library / Manager libraries...",輸入 TimerOner 選擇安裝
- 複製下面程式碼到 Arduino IDE,並存檔為喜歡的檔名
#include <TimerOne.h> #define S0 3 #define S1 4 #define S2 5 #define S3 6 #define OUT 2 int g_count = 0; // 頻率計算 int g_array[3]; // 儲存 RGB 值 int g_flag = 0; // RGB 過濾順序 float g_SF[3]; // 儲存白平衡計算後之 RGB 補償係數 // TCS3200 初始化與輸出頻率設定 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); } // 選擇過濾顏色 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); // Red break; case 1: Serial.print("->Frequency R="); Serial.println(g_count); g_array[0] = g_count; TSC_WB(HIGH, HIGH); // Green break; case 2: Serial.print("->Frequency G="); Serial.println(g_count); g_array[1] = g_count; TSC_WB(LOW, HIGH); // Blue break; case 3: Serial.print("->Frequency B="); 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) { g_count = 0; g_flag ++; TSC_FilterColor(Level0, Level1); Timer1.setPeriod(1000000); // us; 每秒觸發 } 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 補償係數 g_SF[1] = 255.0/ g_array[1] ; // G 補償係數 g_SF[2] = 255.0/ g_array[2] ; // B 補償係數 Serial.println(g_SF[0]); Serial.println(g_SF[1]); Serial.println(g_SF[2]); } void loop() { g_flag = 0; for(int i=0; i<3; i++) Serial.println(int(g_array[i] * g_SF[i])); delay(4000); }
將上述程式碼編譯後上傳到 Arduino 開發板。打開 Serial Monitor 並將白紙放置在四顆白光 LED 集中為一點時的位置。距離調整要看手上的模組而定,先將紙靠近 LED,然後再慢慢遠離,這時候就會看到原本在角落的四顆 LED 的燈光向中間集中,直到四點光集中至像下面照片一樣就可以;像下面這片就差不多是 6 公分。
白平衡校正方法 |
白平衡實際校正- 關掉其他燈光 |
259、219 和 265 是白紙擷取之後的 RGB 頻率值,將其除以 255 可得到 RGB 補償係數值 0.98、1.16 和 0.96,之後輸出的 255、255 和 255 就是反算的結果。之後只要拿個其他物體在前方就會出現該物品計算之後的 RGB 值。
白平衡校正輸出結果 |
小畫家編輯色彩畫面 |
上面的方法是一種方法,但是很麻煩!
下面介紹的方法,直接將白平衡校正之後取得的物體表面顏色輸出到 RGB LED 上,比較快也比較直覺!例如:WS2811、WS2812B 和 APA102 都可以直接拿來用,在這裡我們使用 WS2812B。使用之前請先安裝 Adafruit_Neopixel 函式庫,安裝方法請看上面 "白平衡校正說明" 小節,或是手動下載安裝。
下面的由上面的程式碼修改,主要是加入了對於 WS2812B RGB LED 的支援;兩者比較一下就不難發現之間的程式碼差異部分。
由於程式碼中以加入了註解,就不再細部說明。
在 Arduino IDE 開啟一新檔,複製 & 貼上上面程式碼,編譯後上傳。
#include <TimerOne.h> #include <Adafruit_NeoPixel.h> struct CRGB { union { struct { union { uint8_t r; uint8_t red; }; union { uint8_t g; uint8_t green; }; union { uint8_t b; uint8_t blue; }; }; uint8_t raw[3]; }; }; #define S0 3 #define S1 4 #define S2 5 #define S3 6 #define OUT 2 int g_count = 0; // 頻率計算 int g_array[3]; // 儲存 RGB 值 int g_flag = 0; // RGB 過濾順序 float g_SF[3]; // 儲存白平衡計算後之 RGB 補償係數 // 使用多少顆 WS2812B #define NUM_LEDS 11 // WS2812B DIN 接腳街道 UNO 的哪根接腳 #define DATA_PIN 13 // Parameter 1 = number of pixels in strip // Parameter 2 = pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) Adafruit_NeoPixel ws2812 = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); CRGB leds[NUM_LEDS]; // TCS3200 初始化與輸出頻率設定 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); } // 選擇過濾顏色 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); // Red break; case 1: Serial.print("->Frequency R="); Serial.println(g_count); g_array[0] = g_count; TSC_WB(HIGH, HIGH); // Green break; case 2: Serial.print("->Frequency G="); Serial.println(g_count); g_array[1] = g_count; TSC_WB(LOW, HIGH); // Blue break; case 3: Serial.print("->Frequency B="); 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); // us; 每秒觸發 } void setup() { TSC_Init(); Serial.begin(9600); ws2812.begin(); ws2812.show(); // Initialize all pixels to 'off' 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 補償係數 g_SF[1] = 255.0/ g_array[1] ; // G 補償係數 g_SF[2] = 255.0/ g_array[2] ; // B 補償係數 Serial.println(g_SF[0]); Serial.println(g_SF[1]); Serial.println(g_SF[2]); for(int i=0; i<3; i++) Serial.println(int(g_array[i] * g_SF[i])); Serial.println("Finish Calibration."); delay(4000); } void loop() { g_flag = 0; // R for( int i = 0; i < NUM_LEDS; i++ ) { leds[i].r = int(g_array[0] * g_SF[0]); leds[i].g = int(g_array[1] * g_SF[1]); leds[i].b = int(g_array[2] * g_SF[2]); ws2812.setPixelColor( i, leds[i].r, leds[i].g, leds[i].b ); } Timer1.stop(); Serial.println(leds[0].r); Serial.println(leds[0].g); Serial.println(leds[0].b); ws2812.show(); // Sends the value to the LED Timer1.resume(); delay(4000); }
程式碼上傳之後,就會先執行白平衡校正,所以
- 請先擺好白紙 (如上一節的校正方式)
- 打開 Serial Monitor
- 按下 UNO 的 RESET 按鈕,開始執行白平衡校正,直到 Serial Monitor 出現 "Finish Calibration" 的文字,表示完成白平衡校正。
白平衡校正輸出 |
剛好找到一個藍色的香水盒子擺了上去
source: www.lancome.com |
TCS3200 物體取色測試 - 開閃光燈 |
TCS3200 物體取色測試 - 關閃光燈 |
這個程式很方便地進行白平衡校正以及取得物體表面顏色,但每次重置或是重新通電都要做一次白平衡校正,很煩!不過當白平衡校正環境不變之下,可以將計算後的 RGB 補償係數寫死到程式碼中,這樣就不必每次都要進行白平衡校正。
再者,物體表面取色一次花費 4 秒鐘,很長!其中只要物體有一些變動情況產生,很容易造成 RGB 取值錯誤;因為現在為控制器處理的速度很快,因此使用者可以試著縮短 TimerOne 每次觸發的時間,來增加辨識的速度。
辨識之後的顯色,除了可用可定址控制的 RGB LED ( 如:WS2811, WS2812B, APA102 ) 等,也能改用其他可產生全彩的 RGB LED 晶片 !
結論:
白平衡的校正對於之後的物體表面顏色的取色過程非常重要,使用者在這過程中必須考慮到所有外在環境的影響,盡量讓影響降至最低;之後的取色過程也應該維持與校正環境相同的條件來處理,這樣才能讓取色後的 RGB 值儘量與物品表面顏色相近。
<<部落格相關網頁>>
你好,我是媒體設計系的學生,想要利用arduino + processing + tcs3200顏色感測器 做一個互動裝置
回覆刪除這個裝置是希望讓使用者可以戴上不同顏色的帽子
並用tcs3200去感測
當感測到rgb某範圍的數值時
processing會出現一個特定的圖片
例如:戴著黃色帽子,會出現小小兵的圖片
戴著紅色帽子,則會出現米奇的圖片
然而,在製作過程,我們遇到了一些問題
1.我們希望能讓顏色感測器不用碰到黃色帽子就能感測到,但rgb的數值跳動的幅度會很大,以至於圖片會有時出現有時沒出現ps:我們希望可在沒關燈的環境下,因此沒有關燈
2.我們希望能在感應到時,出現圖片,並且讓圖片可以停留大概三秒的時間,但是程式寫不出來,目前是寫這樣
if( (rgb[0] >-100 && rgb[0] <13) && (rgb[1] >-500 && rgb[1] <-450) && (rgb[2] >150 && rgb[2] <200))
{
image(img1, 0, 0);
}
if( (rgb[0] >80 && rgb[0] <100) && (rgb[1] >50 && rgb[1] <80) && (rgb[2] >260 && rgb[2] <280))
{
image(img2, 0, 0);
}
//delay(300);
}
希望您能告訴我遇到上述問題要如何解決
非常感謝~~
要在暗的環境之下,(四顆LED)才能產生單一的燈光,照樣才能正常的偵測到顏色。所以要先解決如何讓 color sensor 在偵測的時候是在一個暗的環境中,然後盡量維持依定的距離範圍,如此就能得到一個穩定的顏色值 !
刪除下面的網址對於增加 color sensor 的偵測距離有一些討論;其中,對於在不同距離中偵測相同顏色,就需要先對這幾個距離先進行校正動作,以得到這些距離對於 RGB 值的變化... 等有進行討論與有資料可以參考,相信會有所幫助
https://forum.arduino.cc/index.php?topic=447517.0
先能夠在戴上帽子之後,偵測到正確的值之後再來考慮其他的動作,這是最先要做到的事!
非常感謝您的回覆~
刪除我們後來有在color sensor外做一個遮罩的動作,盡量讓光線不要干擾到偵測,此外在看了您給的網址後,我們決定把裝置改成讓使用者戴好黃色帽子後,再拿桌上的黃色卡片靠緊遮罩偵測,以此讓環境光不要干擾
再次感謝您的幫助~
請問我將我的arduino uno r3接上了tcs3200顏色感測器後 我想利用辨識出來的顏色來做反應 例如感應到白色就向左靠 感應到黃色就向右靠 請問該怎麼做...?
回覆刪除用 if 去判斷得到的白色與黃色的顏色值再進行動作就可以了;但如果是在用在裝置行進之中,顏色判斷的時間就必須大幅縮短,不然撞上了都得不到顏色值!
刪除請問我想用三色LED模組,例感測到紅色就會亮紅燈,藍色就亮藍燈,要怎麼寫判斷...
回覆刪除對每一種顏色進行多次的辨識以得到相對應的 RGB 值,將這些 RGB 值做平均求得中間值並設定出上下邊限,規範出每種顏色的被偵測到的範圍,之後去比對每次辨識顏色之後的 RGB 值是落在哪個顏色的限定範圍內就可以作判斷。
刪除請問為甚麼我程式碼複製過去 接線也沒有錯 型號也是TCS3200 但RGB卻一直都是0呢?
刪除程式碼對、接線對、且正確的做好白平衡,就不會一直輸出都是 0
刪除完成白平衡後,程式會不斷運算,能使用紅外線感應器觸發運算嗎? 自己嘗試過但不成功
回覆刪除不要使用 Timer1 觸發,改用自己的方式就可以!
刪除抱歉我可否問個初淺的問題
回覆刪除我希望最後透過您寫的程式得到R G B 的三個數值之後能夠傳到RGB燈顯示出相應顏色
我在前端設定了三個RGB燈三個接腳與輸出設定
但我應該在您程式的哪裡填入亮燈的部分呢
因為我若在您程式的後面貼入如下,一開始亮白燈,之後不管如何都亮出紅燈或藍燈,雖然您程式的確會隨著我給予的東西更動白平衡後面的數值,但我的RGB不會更動哩。可否請教原因或如何置入呢
void loop()
{
g_flag = 0;
for(int i=0; i<3; i++)
{
Serial.println(int(g_array[i] * g_SF[i]));
Real[i] =int(g_array[i] * g_SF[i]); // 設定輸出RGB三個值
}
analogWrite(R,Real[0]); //設定R的數值
analogWrite(G,Real[1]); //設定G的數值
analogWrite(B,Real[2]); //設定B的數值
delay(4000);
}
你的程式在 loop() 中沒有再去取 TCS3200 的顏色值,所以會一直維持在 setup() 中所取得的資料值作為輸出。
刪除原始的程式移除 WS2812 的函式庫程式碼的部分,稍微改一下就可以用,
CRGB leds;
loop() {
g_flag = 0;
leds.r = int(g_array[0] * g_SF[0]);
leds.g = int(g_array[1] * g_SF[1]);
leds.b = int(g_array[2] * g_SF[2]);
Timer1.stop();
Serial.println(leds.r);
Serial.println(leds.g);
Serial.println(leds.b);
analogWrite( R, led.r);
analogWrite( G, led.g);
analogWrite( B, led.b);
Timer1.resume();
delay(4000);
}
版大您好,我自己將顏色辨識寫一個副程式出來,希望在判斷到某一個地方時才使用到顏色辨識。但是他一旦進到color_test回圈內就出不來了,可以請版大幫忙看一下我哪裡有疏漏嗎?
回覆刪除在此先感謝版大了~
void loop()
{
distance_test();
if(distance <= 9 ){
digitalWrite(TO,HIGH);
servobin.write(180);
delay(3000);
servobin.write(90);
delay(2000);
servobin.write(0);
delay(4000);
// color_test();
if(g_array[2] >= 270) {
servoup2.write(0);
delay(1300);
servoup2.write(180);
delay(1300);
Serial.print("白色蛋");
}
else if(g_array[2] < 182 && g_array[2] >= 150) {
Serial.print("褐色蛋");
servoup1.write(180);
delay(1300);
servoup1.write(0);
delay(1300);
}
detachInterrupt(0);
digitalWrite(TO,LOW);
}
}
void color_test(){
ws2812.begin();
ws2812.show(); // Initialize all pixels to 'off'
Timer1.initialize(); // defaulte is 1s
Timer1.attachInterrupt(TSC_Callback);
attachInterrupt(0, TSC_Count, RISING);
for(int i=0; i<3; i++)
Serial.println(g_array[i]);
// Timer1.stop();
delay(1000);
detachInterrupt(0);
}
你的程式一直重複在 loop() 裡面設定 Timer1 和 中斷作初始化設定,這不對!
刪除用原本的程式就能達到你的要求,只要插入程式碼在 loop() 就可以,其他細部在自己做調整。
loop() {
if( 條件成立 ) {
//
//** 前面指令....
//
/* 取色 */
delay(4000); // 確保至少取到一次完成的顏色,否則有可能取到前一個值
g_flag = 0;
for(int i=0; i<3; i++)
Serial.println(int(g_array[i] * g_SF[i]));
//
//** 後面指令....
//
}
}
Servo 函式庫用到 Timer1。如果是用 UNO 就避開 D9 和 D10 改用其他 PWM 接腳。
刪除其他的看 https://www.pjrc.com/teensy/td_libs_TimerOne.html 網頁裡面的說明。
您好 請問Tcs3200加 LED燈 當感測器感應到紅色物體和綠色物體LED燈暗掉 感應藍色物體 LED亮白光 這種要怎麼寫判斷
回覆刪除看這一篇 http://ruten-proteus.blogspot.com/2018/02/arduino-tcs34725-led-show-demo.html?showComment=1560847586845#c5313005786880268038 裡的回答。
刪除