Parçalar · 10 dk okuma

TCS3200 Renk Sensörü: Arduino ile Renk Algılama ve Kalibrasyon

TCS3200 renk sensörü nasıl çalışır? S0–S3 ayarları, pulseIn ile R, G, B okuma, beyaz-siyah kalibrasyonu, renk ayırma algoritması, ESP32, Pico ve TCS34725 kodu.

TCS3200 renk sensörü, önündeki yüzeyin rengini kırmızı, yeşil ve mavi bileşenlerine ayırarak ölçen ve Arduino projelerinde en çok kullanılan renk algılama modülüdür. Bir fotodiyot dizisinin yakaladığı ışığı doğrudan frekansa çevirir: yüzey ne kadar çok kırmızı ışık yansıtırsa kırmızı kanalın frekansı o kadar yükselir. Analog okuma ya da özel bir haberleşme protokolü gerekmez; Arduino'nun pulseIn() komutuyla birkaç satırda R, G ve B değerlerini okuyabilirsin. Renkli şeker ayıran makineler, renk tanıyan robotlar, yerdeki renkli işaretlere göre yön değiştiren araçlar ve önüne tutulan nesnenin rengini kopyalayan lambalar bu sensörle yapılır.

Bu rehberde sensörün içinde neler olduğunu, S0–S3 pinlerinin ne işe yaradığını, Arduino Uno, ESP32 ve Raspberry Pi Pico bağlantısını, ham okumayı, beyaz-siyah kalibrasyonunu ve okunan değerden hangi renk olduğunu bulan bir algoritmayı adım adım göreceksin. Ardından renklerine göre nesne ayıran bir makinenin mantığını kuracak, son olarak da I2C ile çalışan TCS34725 sensörüyle karşılaştırma yapacağız.

TCS3200 renk sensörü modülü
TCS3200 renk sensörü modülü: ortada 8 bacaklı TCS3200 yongası, dört köşede yüzeyi aydınlatan beyaz LED'ler; bir yanda S0, S1, OE, GND, diğer yanda VCC, OUT, S2, S3 pinleri.

TCS3200 renk sensörü nedir, nasıl çalışır?

Modülün kalbi olan TCS3200 yongasının (eski sürümünün adı TCS230) yüzeyinde 8×8 düzende 64 fotodiyot bulunur. Bunların 16'sının üzerinde kırmızı, 16'sının üzerinde yeşil, 16'sının üzerinde mavi filtre vardır; kalan 16'sı ise filtresizdir (clear) ve ışığın toplam miktarını görür. Aynı renkteki 16 fotodiyot birbirine paralel bağlıdır ve hangi grubun ölçüleceğini S2 ile S3 pinleri seçer. Farklı renkteki fotodiyotlar dizide iç içe dağıtıldığı için yüzeyin bir köşesine düşen ışık bütün renk gruplarını eşit etkiler.

Seçilen fotodiyot grubunun ürettiği küçük akım, yonganın içindeki akım-frekans dönüştürücüsüne gider. Bu devre, görev döngüsü %50 olan bir kare dalga üretir ve dalganın frekansı ışık şiddetiyle doğru orantılıdır. Yani ölçtüğün şey bir gerilim değil, saniyedeki darbe sayısıdır: tam karanlıkta birkaç hertz, beyaz bir yüzeye yakın tutulduğunda onlarca kilohertz görürsün. Frekans çıkışının güzel yanı, gürültüye dayanıklı olması ve Arduino'nun herhangi bir dijital pinine bağlanabilmesidir. Yalnızca ışığın ne kadar güçlü olduğunu ölçmek istiyorsan LDR ışık sensörü daha basit bir seçenektir; TCS3200 ise aynı işi üç renk için ayrı ayrı yapar.

ÖzellikDeğer
YongaTCS3200 (eski sürümü TCS230, pin uyumlu)
Fotodiyot dizisi8×8 = 64 adet: 16 kırmızı, 16 yeşil, 16 mavi, 16 filtresiz
Çıkış%50 görev döngülü kare dalga, frekans ışıkla doğru orantılı
Tam ölçek frekansı (tipik)600 kHz (%100), 120 kHz (%20), 12 kHz (%2)
Besleme gerilimi2,7–5,5 V
Yonganın akımıTipik 1,4 mA (modüldeki LED'lerin akımı buna eklenir)
Kontrol pinleriS0, S1 (frekans ölçeği), S2, S3 (renk filtresi), OE (çıkış etkin, aktif LOW)
Önerilen ölçüm mesafesiYaklaşık 1–3 cm, her ölçümde aynı
AydınlatmaModülde 4 beyaz LED

S0–S3 pinleri: frekans ölçeği ve renk filtresi seçimi

TCS3200'ün davranışını dört kontrol pini belirler. S0 ve S1 çıkış frekansını küçültür: %100 ölçekte darbeler birkaç mikrosaniyeye kadar kısalır ve Arduino Uno'nun ölçüm hassasiyetini zorlar; %2 ölçekte ise darbeler uzar ama aynı sürede daha az darbe gelir. S2 ve S3 ise hangi renk filtresinin okunacağını seçer. Bu pinleri Arduino'nun dijital çıkışlarına bağlar, her ölçümden önce koddan ayarlarsın.

S0S1Çıkış frekansı ölçeğiNe zaman kullanılır?
LOWLOWGüç kesik (power-down)Pilli projede sensörü uyutmak için
LOWHIGH%2 (tipik en fazla 12 kHz)Yavaş işlemciler, MicroPython ve kesmeyle sayım
HIGHLOW%20 (tipik en fazla 120 kHz)Arduino ve pulseIn için en uygun ayar
HIGHHIGH%100 (tipik en fazla 600 kHz)Donanım sayıcılı hızlı ölçümler
S2S3Okunan fotodiyot grubu
LOWLOWKırmızı filtreli
LOWHIGHMavi filtreli
HIGHLOWFiltresiz (clear, toplam ışık)
HIGHHIGHYeşil filtreli
Darbe süresiyle frekans arasındaki ilişki basittir: görev döngüsü %50 olduğu için LOW kısmın süresi periyodun yarısıdır. f = 1 / (2 × t) formülüyle pulseIn'in verdiği mikrosaniyeyi frekansa çevirebilirsin. Örneğin t = 25 µs ise f = 1 / (2 × 0,000025 s) = 20 kHz eder. %20 ölçekte, modülün LED'leri yanarken 10 ile 200 µs arasında değerler görmek olağandır.

TCS3200 bağlantısı: Arduino Uno, ESP32 ve Pico

Modül piniArduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT), pin 36
GNDGNDGNDGND
S0D4GPIO 32GP2
S1D5GPIO 33GP3
S2D6GPIO 25GP4
S3D7GPIO 26GP5
OUTD8GPIO 27GP6
OEGNDGNDGND
OE pinini boşta bırakma. Bu pin aktif LOW'dur; HIGH ya da boşta kalırsa çıkış yüksek empedansa geçer ve pulseIn sürekli 0 döndürür. Ayrıca ESP32 ve Pico'nun pinleri 3,3 V ile çalışır: modülü 5 V ile beslersen OUT pini 5 V'luk darbeler verir ve kartın girişini zorlar. Bu kartlarda modülü 3V3'ten besle ya da OUT hattına bir gerilim bölücü veya seviye dönüştürücü koy.

Modüldeki dört beyaz LED, yüzeyi her ölçümde aynı ışıkla aydınlatır; bu sayede oda ışığı değişse bile sonuçlar daha tutarlı olur. Bazı kartlarda LED'leri açıp kapatmaya yarayan ayrı bir LED pini vardır, bazılarında ise LED'ler besleme verildiği anda yanar; kendi kartının üzerindeki yazılara bak. En iyi sonucu almak için sensörün çevresini siyah bir boru ya da kartonla sar, ölçülecek nesneyi her seferinde aynı mesafeye getir ve parlak, yansıtıcı yüzeylerden kaçın. Kartının pin dizilimini Pinout aracında kontrol edebilirsin.

Adım adım: pulseIn ile R, G ve B okumak

  1. Modülü yukarıdaki tablodaki gibi bağla; OE'yi GND'ye, VCC'yi 5V'a bağla.
  2. S0'ı HIGH, S1'i LOW yaparak %20 frekans ölçeğini seç.
  3. Kırmızı için S2 ve S3'ü LOW yap ve çıkışın oturması için birkaç milisaniye bekle.
  4. pulseIn(OUT, LOW) ile darbenin LOW kısmının süresini mikrosaniye olarak ölç; gürültüyü azaltmak için 10 ölçümün ortalamasını al.
  5. Aynı işlemi yeşil (S2 HIGH, S3 HIGH) ve mavi (S2 LOW, S3 HIGH) için tekrarla.
  6. Sonuçları Seri Monitör'de 9600 baud ile izle ve sensörün önüne farklı renkte kağıtlar tut.
C++ (Arduino IDE)
1// TCS3200 ile ham R, G, B okuma / Raw R, G, B reading with the TCS3200
2const int S0 = 4;
3const int S1 = 5;
4const int S2 = 6;
5const int S3 = 7;
6const int OUT_PIN = 8;
7
8// Filtreyi seçer, 10 darbenin ortalama LOW süresini döndürür (µs) / Selects a filter, returns the average LOW time of 10 pulses (µs)
9unsigned long readPulse(bool s2, bool s3) {
10  digitalWrite(S2, s2 ? HIGH : LOW);
11  digitalWrite(S3, s3 ? HIGH : LOW);
12  delay(5);                                           // çıkışın oturmasını bekle / let the output settle
13  unsigned long total = 0;
14  int count = 0;
15  for (int i = 0; i < 10; i++) {
16    unsigned long t = pulseIn(OUT_PIN, LOW, 50000UL); // 50 ms zaman aşımı / 50 ms timeout
17    if (t > 0) {
18      total += t;
19      count++;
20    }
21  }
22  return count > 0 ? total / count : 50000UL;         // darbe yoksa çok karanlık / no pulse means very dark
23}
24
25void setup() {
26  pinMode(S0, OUTPUT);
27  pinMode(S1, OUTPUT);
28  pinMode(S2, OUTPUT);
29  pinMode(S3, OUTPUT);
30  pinMode(OUT_PIN, INPUT);
31  digitalWrite(S0, HIGH);                             // S0=HIGH, S1=LOW: %20 ölçek / 20% scaling
32  digitalWrite(S1, LOW);
33  Serial.begin(9600);
34}
35
36void loop() {
37  unsigned long r = readPulse(false, false);          // kırmızı filtre / red filter
38  unsigned long g = readPulse(true, true);            // yeşil filtre / green filter
39  unsigned long b = readPulse(false, true);           // mavi filtre / blue filter
40  Serial.print("R: ");
41  Serial.print(r);
42  Serial.print("  G: ");
43  Serial.print(g);
44  Serial.print("  B: ");
45  Serial.println(b);
46  delay(500);
47}

Bu kodda en önemli nokta, okunan sayının ışıkla ters orantılı olmasıdır: değer küçüldükçe o renkten gelen ışık artar. Kırmızı bir kağıt tuttuğunda örneğin "R: 24 G: 68 B: 52" gibi bir çıktı görürsün; en küçük sayı kırmızı kanaldadır. pulseIn'e verilen 50.000 µs'lik zaman aşımı, darbe gelmediğinde kodun varsayılan 1 saniye boyunca beklemesini önler; hiç darbe yakalanamazsa fonksiyon 50.000 döndürür ve bu "çok karanlık" anlamına gelir. Seri port çıktısını okumakta zorlanıyorsan Arduino Serial Monitor rehberine göz at.

Beyaz-siyah kalibrasyonu: ham değerleri 0–255'e çevirmek

Ham değerler tek başına yanıltıcıdır, çünkü üç fotodiyot grubunun hassasiyeti aynı değildir ve modüldeki beyaz LED'ler her rengi eşit miktarda yaymaz. Bu yüzden bembeyaz bir kağıt bile üç kanalda farklı sayılar verir. Kalibrasyon, bu farkları ortadan kaldırıp her kanalı 0 (siyah) ile 255 (beyaz) arasına yerleştirmektir; fotoğraf makinelerindeki beyaz dengesiyle aynı fikirdir. Kalibrasyonu sensörün gerçekten çalışacağı yerde, aynı ışık ve mesafede yapmalısın; masada yaptığın kalibrasyon kutunun içinde geçerli olmaz.

  1. Sensörü sabit bir tutucuya yerleştir ve ölçüm mesafesini (örneğin 1,5 cm) değişmeyecek şekilde ayarla.
  2. Önüne düz beyaz bir kağıt koy, yukarıdaki kodla R, G ve B değerlerini birkaç kez oku ve ortalamalarını beyaz referansı olarak not et; bunlar en küçük değerlerdir.
  3. Aynı yere mat siyah bir kağıt ya da keçe koy ve okunan değerleri siyah referansı olarak not et; bunlar en büyük değerlerdir.
  4. Bu altı sayıyı aşağıdaki kodun başındaki WHITE_ ve BLACK_ sabitlerine yaz ve kodu yükle.
  5. Beyaz kağıtta üç kanalın da 255'e, siyahta 0'a yakın çıktığını kontrol et; çıkmıyorsa ölçümü aynı ışık ve mesafede tekrarla.

Burada pek çok örnekte yapılan bir hataya dikkat: darbe süresini map() ile doğrudan 0–255'e çevirmek doğru sonuç vermez, çünkü ışık darbe süresiyle değil frekansla orantılıdır. Doğru yol, önce süreyi frekansa (1/t) çevirip sonra ölçeklemektir: seviye = (f − f_siyah) / (f_beyaz − f_siyah) × 255. Bir örnekle bakalım: beyazda 20 µs, siyahta 200 µs ölçtün ve nesne 40 µs verdi. map() bu değeri 226'ya çevirir; frekans yöntemi ise 113 bulur. Nesnenin frekansı beyazdakinin tam yarısıdır ve siyah seviyesi çıkarıldığında bu, ölçeğin yaklaşık %44'üne, yani 113'e karşılık gelir; map() ise renkleri olduklarından çok daha açık gösterir ve koyu tonları birbirinden ayırmayı zorlaştırır.

Renk ayırma algoritması: okunan değer hangi renk?

Kalibre edilmiş R, G, B değerleri hâlâ ışık miktarına bağlıdır: aynı kırmızı nesne sensöre biraz yaklaştığında üç değer birlikte artar. Bunu çözmek için her değeri toplama böleriz: r = R / (R + G + B), g ve b de aynı şekilde. Bu renk oranları, mesafe ve parlaklık biraz değişse bile hemen hemen sabit kalır. Ardından her renk için bir kez ölçüp kaydettiğin referans oranlarla karşılaştırır ve en yakın komşuyu seçersin. Karşılaştırma için oran farklarının karelerini toplamak yeterlidir; bu sayı ne kadar küçükse renkler o kadar benzerdir. En yakın referans bile belirli bir eşikten uzaksa sonuç "bilinmiyor" olur. Toplam ışık çok düşükse nesne siyah, üç kanal da çok yüksekse beyaz kabul edilir; bu iki durum oranlarla ayırt edilemediği için önce kontrol edilir.

C++ (Arduino IDE)
1// TCS3200 ile kalibrasyonlu renk tanıma / Calibrated color recognition with the TCS3200
2const int S0 = 4, S1 = 5, S2 = 6, S3 = 7, OUT_PIN = 8;
3
4// Kalibrasyonda ölçtüğün süreler (µs), kendi değerlerinle değiştir / Pulse widths from your calibration (µs), use your own
5const float WHITE_R = 16, WHITE_G = 20, WHITE_B = 18;     // beyaz kağıt / white paper
6const float BLACK_R = 140, BLACK_G = 170, BLACK_B = 150;  // siyah kağıt / black paper
7
8struct ColorRef {
9  const char *name;
10  float r, g, b;                                          // renk oranları, toplamı 1 / color ratios, sum is 1
11};
12
13// Örnek referanslar, kendi ölçümlerinle değiştir / Sample references, replace with your own measurements
14ColorRef refs[] = {
15  {"Kirmizi / Red",    0.58, 0.20, 0.22},
16  {"Turuncu / Orange", 0.55, 0.30, 0.15},
17  {"Sari / Yellow",    0.42, 0.40, 0.18},
18  {"Yesil / Green",    0.24, 0.46, 0.30},
19  {"Mavi / Blue",      0.18, 0.30, 0.52},
20  {"Mor / Purple",     0.40, 0.20, 0.40}
21};
22const int REF_COUNT = sizeof(refs) / sizeof(refs[0]);
23const float MAX_DIST = 0.02;                              // bundan uzaksa bilinmiyor / farther than this is unknown
24
25unsigned long readPulse(bool s2, bool s3) {
26  digitalWrite(S2, s2 ? HIGH : LOW);
27  digitalWrite(S3, s3 ? HIGH : LOW);
28  delay(5);
29  unsigned long total = 0;
30  int count = 0;
31  for (int i = 0; i < 10; i++) {
32    unsigned long t = pulseIn(OUT_PIN, LOW, 50000UL);
33    if (t > 0) {
34      total += t;
35      count++;
36    }
37  }
38  return count > 0 ? total / count : 50000UL;
39}
40
41// Süreyi frekansa çevirip 0-255 arasına ölçekler / Converts the pulse width to frequency and scales it to 0-255
42float toLevel(unsigned long t, float tWhite, float tBlack) {
43  float f = 1.0 / t;                                      // ışık frekansla orantılı / light is proportional to frequency
44  float fWhite = 1.0 / tWhite;
45  float fBlack = 1.0 / tBlack;
46  float level = (f - fBlack) / (fWhite - fBlack) * 255.0;
47  return constrain(level, 0.0, 255.0);
48}
49
50// En yakın referans rengi bulur / Finds the nearest reference color
51const char *classify(float R, float G, float B) {
52  float sum = R + G + B;
53  if (sum < 90) return "Siyah / Black";                  // çok az ışık / very little light
54  if (R > 200 && G > 200 && B > 200) return "Beyaz / White";
55  float r = R / sum, g = G / sum, b = B / sum;           // parlaklıktan bağımsız oranlar / brightness-independent ratios
56  int best = 0;
57  float bestDist = 1e9;
58  for (int i = 0; i < REF_COUNT; i++) {
59    float d = sq(r - refs[i].r) + sq(g - refs[i].g) + sq(b - refs[i].b);  // uzaklığın karesi / squared distance
60    if (d < bestDist) {
61      bestDist = d;
62      best = i;
63    }
64  }
65  if (bestDist > MAX_DIST) return "Bilinmiyor / Unknown";
66  return refs[best].name;
67}
68
69void setup() {
70  pinMode(S0, OUTPUT);
71  pinMode(S1, OUTPUT);
72  pinMode(S2, OUTPUT);
73  pinMode(S3, OUTPUT);
74  pinMode(OUT_PIN, INPUT);
75  digitalWrite(S0, HIGH);                                 // %20 ölçek / 20% scaling
76  digitalWrite(S1, LOW);
77  Serial.begin(9600);
78}
79
80void loop() {
81  float R = toLevel(readPulse(false, false), WHITE_R, BLACK_R);
82  float G = toLevel(readPulse(true, true), WHITE_G, BLACK_G);
83  float B = toLevel(readPulse(false, true), WHITE_B, BLACK_B);
84  float sum = R + G + B;
85  Serial.print("R=");
86  Serial.print(R, 0);
87  Serial.print(" G=");
88  Serial.print(G, 0);
89  Serial.print(" B=");
90  Serial.print(B, 0);
91  if (sum > 0) {                                          // referans için oranlar / ratios for your references
92    Serial.print("  r=");
93    Serial.print(R / sum, 2);
94    Serial.print(" g=");
95    Serial.print(G / sum, 2);
96    Serial.print(" b=");
97    Serial.print(B / sum, 2);
98  }
99  Serial.print("  -> ");
100  Serial.println(classify(R, G, B));
101  delay(500);
102}
Kod bölümüGörevi
WHITE_* ve BLACK_*Kalibrasyonda ölçtüğün beyaz ve siyah darbe süreleri (µs)
toLevel()Darbe süresini frekansa çevirip 0–255 arasına ölçekler
refs[]Her rengin referans r, g, b oranları; kendi ölçümlerinle değiştir
classify()Önce siyahı ve beyazı ayırır, sonra en yakın referansı bulur
MAX_DISTBu uzaklığı aşan ölçümler "Bilinmiyor" sayılır
Referans değerlerini tahmin etme, ölç: her renkten nesneyi sensörün önüne 5–10 kez koy, Seri Monitör'de yazan r, g, b oranlarının ortalamasını al ve refs[] dizisine yaz. Ölçümleri makinenin çalışacağı ışıkta ve mesafede yap. Okumalar titriyorsa birkaç ölçümün ortalamasını almak ya da medyan filtre uygulamak işe yarar; ayrıntılar için sensör verisi filtreleme yazısına bakabilirsin.

Renklerine göre nesne ayıran makine yapmak

TCS3200'ün en sevilen projesi; renkli şekerleri, boncukları ya da LEGO parçalarını renklerine göre ayıran makinedir. Mekanizma iki servodan oluşur. Üstteki besleme servosu, üzerinde tek bir nesnenin sığacağı delik bulunan bir diski döndürür: önce huni borusunun altından bir nesne alır, sonra onu sensörün önüne getirir ve ölçümden sonra alttaki kanala bırakır. Alttaki yönlendirme servosu ise eğik bir kanalı döndürerek nesneyi kendi rengine ait kutuya yollar. Servoları ilk kez kullanacaksan önce Servo Motor Nedir? yazısına göz at.

  1. Huniyi ve nesnelerden biraz geniş bir boruyu, nesneleri tek tek besleme diskine düşürecek şekilde yerleştir.
  2. Sensörü, diskin üzerindeki nesneyi 1–2 cm mesafeden görecek biçimde sabitle ve çevresini dış ışık girmeyecek şekilde kapat.
  3. Besleme servosu için üç açı belirle: yükleme, sensör ve bırakma. Açıları kendi mekanizmanda deneyerek bul; besleme servosunu D9'a, yönlendirme servosunu D10'a bağla.
  4. Yönlendirme servosu için her renk kutusuna bir açı ata (örneğin kırmızı 30°, yeşil 75°, mavi 120°, diğerleri 165°).
  5. Kalibrasyonu makinenin içinde, makinenin kendi ışığıyla yap ve her renkten birkaç nesneyle dene.
C++ (Arduino IDE)
1// TCS3200 ve iki servoyla renk ayırıcı / Color sorter with a TCS3200 and two servos
2#include <Servo.h>
3
4const int S0 = 4, S1 = 5, S2 = 6, S3 = 7, OUT_PIN = 8;
5const int FEEDER_PIN = 9;                 // besleme servosu / feeder servo
6const int CHUTE_PIN = 10;                 // yönlendirme servosu / chute servo
7
8const int LOAD_ANGLE = 160;               // huninin altı / under the hopper
9const int SENSOR_ANGLE = 95;              // sensörün önü / in front of the sensor
10const int DROP_ANGLE = 30;                // bırakma deliği / drop hole
11
12// Kalibrasyon süreleri (µs) / Calibration pulse widths (µs)
13const float WHITE_R = 16, WHITE_G = 20, WHITE_B = 18;
14const float BLACK_R = 140, BLACK_G = 170, BLACK_B = 150;
15
16Servo feeder;
17Servo chute;
18
19unsigned long readPulse(bool s2, bool s3) {
20  digitalWrite(S2, s2 ? HIGH : LOW);
21  digitalWrite(S3, s3 ? HIGH : LOW);
22  delay(5);
23  unsigned long total = 0;
24  int count = 0;
25  for (int i = 0; i < 10; i++) {
26    unsigned long t = pulseIn(OUT_PIN, LOW, 50000UL);
27    if (t > 0) {
28      total += t;
29      count++;
30    }
31  }
32  return count > 0 ? total / count : 50000UL;
33}
34
35float toLevel(unsigned long t, float tWhite, float tBlack) {
36  float f = 1.0 / t;
37  float level = (f - 1.0 / tBlack) / (1.0 / tWhite - 1.0 / tBlack) * 255.0;
38  return constrain(level, 0.0, 255.0);
39}
40
41// Baskın kanala göre kutu açısını seçer / Picks the bin angle from the dominant channel
42int binAngle(float R, float G, float B) {
43  if (R + G + B < 90) return 165;                     // çok koyu: diğer kutusu / too dark: "other" bin
44  if (R > G * 1.3 && R > B * 1.3) return 30;          // kırmızı kutusu / red bin
45  if (G > R * 1.3 && G > B * 1.3) return 75;          // yeşil kutusu / green bin
46  if (B > R * 1.3 && B > G * 1.3) return 120;         // mavi kutusu / blue bin
47  return 165;                                         // karar verilemedi / undecided
48}
49
50void setup() {
51  pinMode(S0, OUTPUT);
52  pinMode(S1, OUTPUT);
53  pinMode(S2, OUTPUT);
54  pinMode(S3, OUTPUT);
55  pinMode(OUT_PIN, INPUT);
56  digitalWrite(S0, HIGH);                             // %20 ölçek / 20% scaling
57  digitalWrite(S1, LOW);
58  feeder.attach(FEEDER_PIN);
59  chute.attach(CHUTE_PIN);
60  feeder.write(LOAD_ANGLE);
61  delay(500);
62}
63
64void loop() {
65  feeder.write(LOAD_ANGLE);                           // huniden bir nesne al / take one object from the hopper
66  delay(600);
67  feeder.write(SENSOR_ANGLE);                         // sensörün önüne getir / bring it to the sensor
68  delay(600);                                         // servo dursun, titreşim geçsin / let the servo settle
69  float R = toLevel(readPulse(false, false), WHITE_R, BLACK_R);
70  float G = toLevel(readPulse(true, true), WHITE_G, BLACK_G);
71  float B = toLevel(readPulse(false, true), WHITE_B, BLACK_B);
72  chute.write(binAngle(R, G, B));                     // kanalı doğru kutuya çevir / aim the chute at the right bin
73  delay(400);
74  feeder.write(DROP_ANGLE);                           // nesneyi kanala bırak / drop the object into the chute
75  delay(600);
76}
Servoları Arduino'nun 5V pininden beslemek, hareket anında gerilimin düşmesine ve kartın yeniden başlamasına yol açabilir; bu düşüş renk ölçümlerini de bozar. İki servoyu ayrı bir 5 V kaynaktan besle ve kaynağın GND'sini Arduino'nun GND'siyle birleştir. Servo hareket ederken ölçüm yapma; koddaki gibi servo yerine oturduktan sonra kısa bir bekleme ekle.

ESP32 ile TCS3200: kesmeyle frekans ölçmek

ESP32'de aynı pulseIn kodu çalışır, ama daha kararlı bir yöntem de var: darbe süresini tek tek ölçmek yerine belirli bir sürede kaç darbe geldiğini saymak. Bir kesme (interrupt) her yükselen kenarda sayacı bir artırır; 50 ms sonunda sayaçtaki değeri 20 ile çarpınca frekansı hertz olarak bulursun. Bu yöntem yüzlerce darbenin ortalamasını aldığı için tek bir bozuk darbeden etkilenmez. ESP32'nin 240 MHz'lik işlemcisi %20 ölçekte saniyede on binlerce kesmeyi rahatça karşılar; çok parlak ışıkta sayı aşırı büyürse ölçeği %2'ye düşürebilirsin. Aynı yöntemi Arduino Uno'da da OUT'u kesme destekleyen D2 pinine taşıyarak kullanabilirsin. ESP32'de modülü 3V3 pininden beslemeyi unutma.

C++ (Arduino IDE)
1// ESP32: kesmeyle TCS3200 frekans ölçümü / ESP32: TCS3200 frequency measurement with an interrupt
2const int S0 = 32, S1 = 33, S2 = 25, S3 = 26, OUT_PIN = 27;
3
4volatile uint32_t pulseCount = 0;
5
6void IRAM_ATTR onPulse() {
7  pulseCount++;                                       // her yükselen kenarda say / count every rising edge
8}
9
10// Seçilen filtrenin frekansını Hz olarak döndürür / Returns the frequency of the selected filter in Hz
11uint32_t readHz(bool s2, bool s3) {
12  digitalWrite(S2, s2 ? HIGH : LOW);
13  digitalWrite(S3, s3 ? HIGH : LOW);
14  delay(5);                                           // çıkış otursun / let the output settle
15  pulseCount = 0;
16  delay(50);                                          // 50 ms boyunca say / count for 50 ms
17  return pulseCount * 20;                             // 50 ms x 20 = 1 saniye / 1 second
18}
19
20void setup() {
21  Serial.begin(115200);
22  pinMode(S0, OUTPUT);
23  pinMode(S1, OUTPUT);
24  pinMode(S2, OUTPUT);
25  pinMode(S3, OUTPUT);
26  pinMode(OUT_PIN, INPUT);
27  digitalWrite(S0, HIGH);                             // %20 ölçek / 20% scaling
28  digitalWrite(S1, LOW);
29  attachInterrupt(digitalPinToInterrupt(OUT_PIN), onPulse, RISING);
30}
31
32void loop() {
33  uint32_t r = readHz(false, false);                  // kırmızı / red
34  uint32_t g = readHz(true, true);                    // yeşil / green
35  uint32_t b = readHz(false, true);                   // mavi / blue
36  Serial.print("R: ");
37  Serial.print(r);
38  Serial.print(" Hz  G: ");
39  Serial.print(g);
40  Serial.print(" Hz  B: ");
41  Serial.print(b);
42  Serial.println(" Hz");
43  delay(300);
44}

Raspberry Pi Pico ve MicroPython ile TCS3200

Pico'da Arduino'daki pulseIn'in karşılığı machine.time_pulse_us() fonksiyonudur: istenen seviyedeki darbenin süresini mikrosaniye olarak verir, zaman aşımında ise negatif bir sayı döndürür. Pin zaten istenen seviyedeyken çağrılırsa ölçüme hemen başlar ve yarım bir darbe ölçebilir; bu yüzden kod önce HIGH kısmın bitmesini bekler, sonra LOW süresini ölçer. MicroPython'da her fonksiyon çağrısı birkaç mikrosaniye sürdüğü için burada %2 ölçeği (S0=0, S1=1) seçtik: darbeler 10 kat uzar ve bu gecikmenin etkisi küçülür. Kalibrasyon değerleri Hz olarak yazılır; %2 ölçekte beyaz kağıtta birkaç kHz, siyahta birkaç yüz Hz görmek normaldir. Modülü Pico'nun 3V3(OUT) pininden besle; Pico'yu ilk kez kullanıyorsan Raspberry Pi Pico Nedir? yazısı MicroPython kurulumunu anlatıyor.

MicroPython
1# Pico + TCS3200: süreden frekansa ve 0-255 seviyesine / Pico + TCS3200: from pulse width to frequency and a 0-255 level
2from machine import Pin, time_pulse_us
3import time
4
5s0 = Pin(2, Pin.OUT)
6s1 = Pin(3, Pin.OUT)
7s2 = Pin(4, Pin.OUT)
8s3 = Pin(5, Pin.OUT)
9out = Pin(6, Pin.IN)
10
11s0.value(0)                                    # S0=0, S1=1: %2 ölçek / 2% scaling
12s1.value(1)
13
14FILTERS = {"R": (0, 0), "G": (1, 1), "B": (0, 1)}   # S2, S3 değerleri / S2, S3 values
15WHITE_HZ = {"R": 3125, "G": 2500, "B": 2778}        # beyaz kağıtta Hz / Hz on white paper
16BLACK_HZ = {"R": 357, "G": 294, "B": 333}           # siyah kağıtta Hz / Hz on black paper
17
18def read_hz(channel, samples=10):
19    s2.value(FILTERS[channel][0])
20    s3.value(FILTERS[channel][1])
21    time.sleep_ms(5)                           # çıkış otursun / let the output settle
22    total = 0
23    count = 0
24    for _ in range(samples):
25        time_pulse_us(out, 1, 50000)           # HIGH bitsin, LOW başında ol / wait for HIGH to end
26        t = time_pulse_us(out, 0, 50000)       # LOW süresi, µs / LOW time, µs
27        if t > 0:                              # negatif = zaman aşımı / negative = timeout
28            total += t
29            count += 1
30    if count == 0:
31        return 0
32    return 1000000 / (2 * total / count)       # f = 1 / (2t)
33
34def level(channel, hz):
35    v = (hz - BLACK_HZ[channel]) / (WHITE_HZ[channel] - BLACK_HZ[channel]) * 255
36    return max(0, min(255, int(v)))
37
38while True:
39    r = level("R", read_hz("R"))
40    g = level("G", read_hz("G"))
41    b = level("B", read_hz("B"))
42    print("R:", r, "G:", g, "B:", b)
43    time.sleep(0.5)

TCS3200 mü, TCS34725 mi?

TCS34725, aynı işi I2C üzerinden yapan daha yeni bir renk sensörüdür. Ölçümü yonganın içinde yapar ve sonuçları kanal başına 16 bitlik sayılar olarak verir; Arduino'nun darbe ölçmesi gerekmez. En önemli farkı, fotodiyotlarının üzerinde kızılötesi (IR) engelleyici filtre bulunmasıdır. TCS3200'de bu filtre yoktur; silikon fotodiyotlar kızılötesine de duyarlı olduğu için güneş ışığı ya da akkor ampul gibi IR'si bol ortamlarda ölçümler kayar. TCS34725'in kazancı (1x, 4x, 16x, 60x) ve entegrasyon süresi (2,4–614 ms) yazılımla ayarlanabildiği için çok loş ışıktan parlak ışığa kadar geniş bir aralıkta çalışır. I2C'nin nasıl çalıştığını merak ediyorsan I2C nedir? yazısına bakabilirsin.

TCS34725 I2C renk sensörü modülü
TCS34725 renk sensörü modülü: ortada IR filtreli renk sensörü yongası, yanında beyaz LED; LED, INT, SDA, SCL, 3V3, GND ve VIN pinleri.
ÖzellikTCS3200TCS34725
ÇıkışFrekans (kare dalga)I2C, adres 0x29
Sinyal kablolarıS0–S3, OUT ve OESDA ve SCL (isteğe bağlı INT ve LED)
ÇözünürlükÖlçüm yöntemine ve süresine bağlıKanal başına 16 bit
IR filtresiYokVar (yonganın üzerinde)
Ayarlar3 frekans ölçeği ve güç kesme4 kazanç, 2,4–614 ms entegrasyon süresi
Besleme2,7–5,5 VYonga 3,3 V; regülatörlü modüller 3–5 V
AydınlatmaGenellikle 4 beyaz LEDGenellikle 1 beyaz LED
İşlemci yüküDarbe ölçerken meşgulYonga ölçer, Arduino yalnızca okur
Kime uygun?Öğrenme, basit renk ayırıcılarHassas renk, renk sıcaklığı ve lüks ölçümü
C++ (Arduino IDE)
1// TCS34725 ile ham RGBC, renk sıcaklığı ve lüks / Raw RGBC, color temperature and lux with the TCS34725
2#include <Wire.h>
3#include <Adafruit_TCS34725.h>
4
5// 50 ms entegrasyon süresi, 4x kazanç / 50 ms integration time, 4x gain
6Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
7
8void setup() {
9  Serial.begin(9600);
10  if (!tcs.begin()) {                                 // 0x29 adresinde ara / look for it at 0x29
11    Serial.println("TCS34725 bulunamadi / not found");
12    while (true) {
13      delay(1000);
14    }
15  }
16}
17
18void loop() {
19  uint16_t r, g, b, c;
20  tcs.getRawData(&r, &g, &b, &c);                     // 16 bit ham değerler / 16-bit raw values
21  uint16_t kelvin = tcs.calculateColorTemperature_dn40(r, g, b, c);
22  uint16_t lux = tcs.calculateLux(r, g, b);
23  Serial.print("R: ");
24  Serial.print(r);
25  Serial.print("  G: ");
26  Serial.print(g);
27  Serial.print("  B: ");
28  Serial.print(b);
29  Serial.print("  C: ");
30  Serial.print(c);
31  Serial.print("  K: ");
32  Serial.print(kelvin);
33  Serial.print("  Lux: ");
34  Serial.println(lux);
35  delay(500);
36}

Kodu yüklemeden önce Kütüphane Yöneticisi'nden Adafruit TCS34725 kütüphanesini kur; bağımlılıkları sorduğunda hepsini kurmayı seç. Arduino Uno'da SDA'yı A4'e, SCL'yi A5'e, ESP32'de ise GPIO 21 ve 22'ye bağlarsın. getRawData() entegrasyon süresi kadar bekleyip ham kırmızı, yeşil, mavi ve filtresiz (C) değerlerini döndürür; calculateColorTemperature_dn40() renk sıcaklığını Kelvin olarak, calculateLux() ise yaklaşık aydınlık düzeyini verir. Kalibrasyon ve en yakın renk mantığı bu sensörde de aynen geçerlidir. Renkle birlikte el hareketlerini ve yakınlığı da algılayan bir sensör istiyorsan APDS-9960 iyi bir alternatiftir.

TCS3200 ile proje fikirleri

  • Renk ayıran makine: Şeker, boncuk ya da LEGO parçalarını renklerine göre ayrı kutulara ayır.
  • Renk kopyalayan lamba: Sensörün önüne tuttuğun nesnenin rengini bir RGB LED ya da WS2812B şerit ile yeniden oluştur.
  • Renk okuyan robot: Çizgi izleyen robotuna yerdeki kırmızı işarette durmayı, yeşilde yola devam etmeyi öğret.
  • Renk tanıyan robot kol: Bir robot kolla küpleri alıp her rengi kendi kutusuna bırak.
  • Rengi sesli söyleyen cihaz: Okunan rengi bir DFPlayer Mini ile önceden kaydedilmiş sesle söyle; görme engelliler için kullanışlı bir yardımcı olur.
  • Su rengi takibi: Saydam bir kaptaki suyun rengindeki değişimi zamanla izleyip akvaryum ya da sulama deposu için uyarı ver.

Sık yapılan hatalar ve çözümleri

BelirtiOlası nedenÇözüm
pulseIn hep 0 ya da zaman aşımı değeri döndürüyorOE boşta ya da HIGH, S0 ve S1 ikisi de LOW (güç kesik) ya da OUT yanlış pindeOE'yi GND'ye bağla, S0'ı HIGH, S1'i LOW yap, OUT pinini kodla karşılaştır
Değerler sürekli zıplıyorOda ışığı, titreyen lamba ya da değişen mesafeSensörü siyah boruyla kapat, mesafeyi sabitle, birkaç ölçümün ortalamasını al
Her nesne aynı renk çıkıyorKalibrasyon yapılmamış; kanalların hassasiyeti farklıBeyaz-siyah kalibrasyonu yap, referansları yeniden ölç
Gün ışığında renkler kayıyorTCS3200'de IR filtresi yokÖlçümü kapalı bir kutuda yap ya da TCS34725 kullan
Seviyeler hep 0 ya da 255'e yapışıyorNesne kalibrasyondakinden farklı mesafedeMesafeyi kalibrasyondakiyle aynı tut, gerekirse yeniden kalibre et
ESP32 ya da Pico garip davranıyorModül 5 V ile beslenmiş, OUT 5 V veriyorModülü 3V3'ten besle ya da seviye dönüştürücü kullan
Servo dönünce ölçümler bozuluyorServo akımı besleme gerilimini düşürüyorServolara ayrı 5 V kaynak kullan, GND'leri birleştir
Parlak ve yansıtıcı yüzeyler (metal, cilalı plastik, parlak kağıt) LED ışığını doğrudan sensöre geri yansıtır ve renkleri olduğundan soluk gösterir. Sensörü yüzeye tam dik değil, hafif açılı tutmak ya da mat nesnelerle çalışmak bu sorunu büyük ölçüde azaltır. Yalnızca siyah ve beyazı ayırman gerekiyorsa TCRT5000 daha basit ve hızlı bir seçimdir.

TCS3200; ışığın frekansa nasıl dönüştüğünü, kalibrasyonun neden gerekli olduğunu ve basit bir sınıflandırma algoritmasının nasıl kurulduğunu öğrenmek için harika bir sensördür. Daha hassas ölçüm gerektiğinde TCS34725'e geçmek de kolaydır, çünkü öğrendiğin kalibrasyon ve en yakın renk mantığı aynen geçerlidir. BlueGrays uygulamasında RGB LED ile renk karıştırma, ESP32 renk mikser lambası, LDR ile ışık ölçme ve servo motor projelerini devre şemaları ve adım adım kodlarıyla bulabilir, renk sensörünü bu projelerle birleştirerek kendi makineni kurabilirsin.

Sıkça sorulan sorular

TCS3200 renk sensörü kaç cm mesafeden okur?

En kararlı sonuçlar yaklaşık 1–3 cm mesafede alınır, çünkü modüldeki LED'lerin ışığı uzaklaştıkça hızla zayıflar. Mesafeden daha önemlisi, onu her ölçümde aynı tutmaktır; kalibrasyonu da aynı mesafede yapmalısın. Uzaktaki büyük yüzeylerin rengini okumak için bu sensör uygun değildir.

TCS230 ile TCS3200 arasındaki fark nedir?

TCS230, aynı üreticinin daha eski renk sensörüdür; TCS3200 onun geliştirilmiş sürümüdür. İkisi de 8×8 fotodiyot dizisi, frekans çıkışı ve aynı S0–S3 kontrol mantığını kullanır, bu yüzden bağlantı ve kodlar ortaktır. Bugün satılan modüllerin büyük çoğunluğunda TCS3200 bulunur.

TCS3200 ile pulseIn neden 0 döndürüyor?

pulseIn, verilen zaman aşımı içinde darbe göremezse 0 döndürür. En sık nedenler OE pininin GND'ye bağlanmamış olması, S0 ve S1'in ikisinin de LOW kalması (sensör güç kesme moduna geçer) ve OUT'un koddakinden farklı bir pine bağlanmasıdır. Sensörün önü tamamen karanlıksa frekans birkaç hertz'e düşer ve kısa bir zaman aşımında darbe yakalanamaz.

TCS3200 ESP32 ve Raspberry Pi Pico ile çalışır mı?

Evet. TCS3200 2,7–5,5 V arasında çalıştığı için modülü kartın 3V3 pininden besleyebilirsin; böylece OUT pini de 3,3 V seviyesinde darbe verir. Modülü 5 V ile beslersen OUT hattına gerilim bölücü ya da seviye dönüştürücü koyman gerekir. Pico'da MicroPython ile ölçüm yaparken %2 frekans ölçeği daha doğru sonuç verir.

TCS3200 mü TCS34725 mi daha iyi?

Hassas renk ölçümü için TCS34725 daha iyidir: IR engelleyici filtresi, kanal başına 16 bitlik çözünürlüğü ve ayarlanabilir kazancı vardır, üstelik yalnızca iki I2C kablosuyla bağlanır. TCS3200 ise frekans ölçümünü ve kalibrasyonu öğrenmek ve basit renk ayırıcılar yapmak için yeterli ve yaygın bir seçimdir.

TCS3200 kaç farklı rengi ayırt edebilir?

Kontrollü ışıkta ve sabit mesafede TCS3200; kırmızı, turuncu, sarı, yeşil, mavi, mor, siyah ve beyaz gibi birbirinden belirgin biçimde farklı 6–8 rengi güvenilir şekilde ayırır. Açık ve koyu yeşil gibi yakın tonları ayırmak da mümkündür, ama daha dikkatli kalibrasyon, her ton için çok sayıda referans ölçümü ve sıkı bir eşik gerektirir.

Tüm projeleri gör
Ldr İle Işık Şiddeti Okuma
#11Başlangıç

Ldr İle Işık Şiddeti Okuma

Odanın ne kadar aydınlık olduğunu sayıyla görmek ister misin? Işığa duyarlı küçük bir parça olan LDR ortam ışığını ölçer ve Arduino bu değeri yarım saniyede bir bilgisayar ekranına yazar. Elinle üstün

4.6(81)
139
ESP32 LDR Modülü ile Işık Şiddeti Okuma
#113Başlangıç

ESP32 LDR Modülü ile Işık Şiddeti Okuma

LDR modülünün ham ADC değerini ve karanlık/aydınlık referanslarına göre hesaplanan göreli ışık yüzdesini Serial Monitor'da gerçek zamanlı izleme. Bu yüzde lux ölçümü değildir. Modülün kalibrasyon mantığını öğretir. Proje 10'un öncesinde yapılması ideal; çünkü eşik değerini belirlemek için kullanılır.

4.6(36)
55
RGB Led Kullanımı
#39Başlangıç
Premium

RGB Led Kullanımı

Tek bir LED'in içinde üç renk saklı: RGB LED önce kırmızı, sonra yeşil, sonra mavi yanar; her renk yarım saniye yanıp yarım saniye söner ve sıra baştan başlar. Arduino'ya bir RGB LED ve üç direnç bağl

4.9(73)
98
RGB Led İle Yumuşak Renk Geçişi
#40Başlangıç
Premium

RGB Led İle Yumuşak Renk Geçişi

Tek bir RGB LED kırmızıdan yeşile, yeşilden maviye, maviden yeniden kırmızıya yavaşça geçer ve bu gökkuşağı döngüsü hiç durmaz. Her geçiş iki buçuk saniye kadar sürer; aradaki sarı, turkuaz ve mor ton

4.8(58)
76
ESP32 Renk Mikser Lambası (3 Pot + RGB LED + OLED)
#138İleri
Premium

ESP32 Renk Mikser Lambası (3 Pot + RGB LED + OLED)

ESP32 ile 3 potansiyometre çevirerek istediğin rengi karıştıran akıllı bir renk mikser lambası! Kırmızı, yeşil ve mavi potansiyometreleri çevirdikçe ortak katot RGB LED anlık olarak renk değiştirir. SSD1306 OLED ekranda her renk için 0-255 aralığında değer, görsel dolgu barları ve HEX web renk kodu (#FF8040 gibi) canlı olarak gösterilir. Mini bir profesyonel renk stüdyosu — RGB renk teorisi, ADC analog okuma, PWM ile parlaklık kontrolü ve I2C ekran tasarımını tek projede öğretir. Grafik tasarımc

4.7(6)
10
ESP32 RGB LED Kontrolü
#111Başlangıç

ESP32 RGB LED Kontrolü

3 ayrı LED yerine tek RGB LED ile sınırsız renk üretme. Arduino'daki gibi analogWrite() ile R/G/B değerlerini ayarlayarak gökkuşağı geçişi yaparız. Renk teorisi (red+green=yellow gibi) pratik olarak görülür.

4.6(29)
51
Servo Motor Kullanım
#35Başlangıç
Premium

Servo Motor Kullanım

Küçük bir servo motorun kolu sırayla üç konuma döner: en başa, tam ortaya ve en sona, her durakta iki saniye bekleyerek. Arduino motora hangi açıda durması gerektiğini söyler, motor da oraya gidip ora

4.7(48)
67
TCRT5000 Siyah Beyaz Zemin Tespiti
#78Orta
Premium

TCRT5000 Siyah Beyaz Zemin Tespiti

Çizgi izleyen robotların gözü olan küçük bir sensörle zeminin siyah mı beyaz mı olduğunu anlarsın. TCRT5000 sensörü zemine gözle görülmeyen bir ışık gönderip ne kadarının geri döndüğüne bakar; beyaz z

4.7(40)
49