Composants · 15 min de lecture

Capteur de couleur TCS3200 Arduino : câblage et calibrage

Comment fonctionne le capteur de couleur TCS3200 : réglages S0–S3, lecture RVB avec pulseIn, calibrage blanc et noir, tri des couleurs, code ESP32 et Pico.

Le capteur de couleur TCS3200 est le module de détection de couleur le plus utilisé dans les projets Arduino : il mesure la couleur de la surface placée devant lui en la décomposant en rouge, vert et bleu. Il convertit la lumière captée par une matrice de photodiodes directement en fréquence : plus une surface renvoie de lumière rouge, plus la fréquence du canal rouge est élevée. Pas besoin de lecture analogique ni de protocole de communication particulier ; avec la fonction pulseIn() d'Arduino, tu lis les valeurs R, V et B en quelques lignes. Machines qui trient des bonbons colorés, robots qui reconnaissent les couleurs, véhicules qui tournent devant des repères colorés au sol, lampes qui copient la couleur de l'objet qu'on leur présente : tout cela se fait avec ce capteur.

Dans ce guide, tu verras pas à pas ce qu'il y a dans le capteur, à quoi servent les broches S0–S3, comment le câbler sur une Arduino Uno, un ESP32 et une Raspberry Pi Pico, comment faire des lectures brutes, comment réaliser le calibrage blanc et noir, ainsi qu'un algorithme qui détermine à quelle couleur correspond une mesure. Ensuite, nous construirons la logique d'une machine qui trie les objets par couleur et, pour finir, nous le comparerons au TCS34725, un capteur qui fonctionne en I2C.

Module capteur de couleur TCS3200
Module capteur de couleur TCS3200 : au centre la puce TCS3200 à 8 broches, aux quatre coins des LED blanches qui éclairent la surface ; d'un côté les broches S0, S1, OE, GND, de l'autre VCC, OUT, S2, S3.

Qu'est-ce que le capteur de couleur TCS3200 et comment fonctionne-t-il ?

La puce TCS3200, cœur du module (sa version précédente s'appelle TCS230), porte sur sa surface 64 photodiodes disposées en grille 8×8. Seize d'entre elles sont sous un filtre rouge, 16 sous un filtre vert, 16 sous un filtre bleu, et les 16 dernières n'ont pas de filtre (clear) et voient la quantité totale de lumière. Les 16 photodiodes d'une même couleur sont branchées en parallèle, et les broches S2 et S3 choisissent le groupe mesuré. Comme les photodiodes des différentes couleurs sont entrelacées dans la matrice, la lumière qui tombe sur un coin de la surface agit de la même façon sur tous les groupes de couleur.

Le faible courant produit par le groupe de photodiodes choisi arrive à un convertisseur courant-fréquence intégré à la puce. Ce circuit génère un signal carré au rapport cyclique de 50 %, dont la fréquence est directement proportionnelle à l'intensité lumineuse. Ce que tu mesures n'est donc pas une tension mais un nombre d'impulsions par seconde : quelques hertz dans l'obscurité totale, plusieurs dizaines de kilohertz tout près d'une surface blanche. L'avantage d'une sortie en fréquence, c'est qu'elle résiste bien aux parasites et qu'elle se branche sur n'importe quelle broche numérique de l'Arduino. Si tu veux seulement mesurer la quantité de lumière, une photorésistance LDR est plus simple ; le TCS3200 fait le même travail séparément pour trois couleurs.

CaractéristiqueValeur
PuceTCS3200 (ancienne version TCS230, compatible broche à broche)
Matrice de photodiodes8×8 = 64 : 16 rouges, 16 vertes, 16 bleues, 16 sans filtre
SortieSignal carré au rapport cyclique de 50 %, fréquence proportionnelle à la lumière
Fréquence pleine échelle (typique)600 kHz (100 %), 120 kHz (20 %), 12 kHz (2 %)
Tension d'alimentation2,7–5,5 V
Consommation de la puce1,4 mA typique (le courant des LED du module s'y ajoute)
Broches de commandeS0, S1 (échelle de fréquence), S2, S3 (filtre de couleur), OE (validation de sortie, active à LOW)
Distance conseilléeEnviron 1–3 cm, identique à chaque mesure
Éclairage4 LED blanches sur le module

Broches S0–S3 : échelle de fréquence et choix du filtre de couleur

Quatre broches de commande déterminent le comportement du TCS3200. S0 et S1 divisent la fréquence de sortie : à 100 %, les impulsions descendent à quelques microsecondes et mettent à rude épreuve la précision de mesure de l'Arduino Uno, tandis qu'à 2 % elles s'allongent mais arrivent moins nombreuses dans le même temps. S2 et S3 choisissent le filtre de couleur lu. Tu relies ces broches à des sorties numériques de l'Arduino et tu les règles dans le code avant chaque mesure.

S0S1Échelle de la fréquence de sortieQuand l'utiliser ?
LOWLOWHors tension (power-down)Pour mettre le capteur en veille dans un projet sur batterie
LOWHIGH2 % (typiquement jusqu'à 12 kHz)Processeurs lents, MicroPython et comptage par interruption
HIGHLOW20 % (typiquement jusqu'à 120 kHz)Le meilleur réglage pour Arduino et pulseIn
HIGHHIGH100 % (typiquement jusqu'à 600 kHz)Mesures rapides avec un compteur matériel
S2S3Groupe de photodiodes lu
LOWLOWFiltre rouge
LOWHIGHFiltre bleu
HIGHLOWSans filtre (clear, lumière totale)
HIGHHIGHFiltre vert
Le lien entre durée d'impulsion et fréquence est simple : comme le rapport cyclique vaut 50 %, la partie LOW dure une demi-période. La formule f = 1 / (2 × t) convertit en fréquence les microsecondes renvoyées par pulseIn. Par exemple, si t = 25 µs, f = 1 / (2 × 0,000025 s) = 20 kHz. À l'échelle 20 %, LED du module allumées, des valeurs entre 10 et 200 µs sont normales.

Câblage du TCS3200 : Arduino Uno, ESP32 et Pico

Broche du moduleArduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT), broche 36
GNDGNDGNDGND
S0D4GPIO 32GP2
S1D5GPIO 33GP3
S2D6GPIO 25GP4
S3D7GPIO 26GP5
OUTD8GPIO 27GP6
OEGNDGNDGND
Ne laisse pas la broche OE en l'air. Elle est active à LOW ; si elle est à HIGH ou non connectée, la sortie passe en haute impédance et pulseIn renvoie 0 en permanence. Par ailleurs, les broches de l'ESP32 et de la Pico fonctionnent en 3,3 V : si tu alimentes le module en 5 V, la broche OUT envoie des impulsions de 5 V et malmène l'entrée de la carte. Sur ces cartes, alimente le module en 3V3 ou place un pont diviseur de tension ou un convertisseur de niveau logique sur la ligne OUT.

Les quatre LED blanches du module éclairent la surface de la même manière à chaque mesure, ce qui rend les résultats plus cohérents même si l'éclairage de la pièce change. Certaines cartes ont une broche LED séparée pour allumer et éteindre les LED, sur d'autres elles s'allument dès la mise sous tension ; regarde la sérigraphie de ta carte. Pour de meilleurs résultats, entoure le capteur d'un tube ou d'un carton noir, place l'objet toujours à la même distance et évite les surfaces brillantes et réfléchissantes. Tu peux vérifier le brochage de ta carte avec l'outil Pinout.

Pas à pas : lire R, V et B avec pulseIn

  1. Câble le module comme dans le tableau ci-dessus ; OE sur GND et VCC sur 5V.
  2. Choisis l'échelle de fréquence 20 % en mettant S0 à HIGH et S1 à LOW.
  3. Pour le rouge, mets S2 et S3 à LOW et attends quelques millisecondes que la sortie se stabilise.
  4. Mesure en microsecondes la durée de la partie LOW de l'impulsion avec pulseIn(OUT, LOW) ; fais la moyenne de 10 mesures pour réduire le bruit.
  5. Recommence pour le vert (S2 HIGH, S3 HIGH) et le bleu (S2 LOW, S3 HIGH).
  6. Suis les résultats dans le moniteur série à 9600 bauds et place des feuilles de différentes couleurs devant le capteur.
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}

Le point le plus important de ce code : le nombre lu est inversement proportionnel à la lumière. Plus la valeur est petite, plus cette couleur renvoie de lumière. Avec une feuille rouge devant le capteur, tu verras par exemple "R: 24 G: 68 B: 52" ; le plus petit nombre se trouve sur le canal rouge. Le délai maximal de 50 000 µs passé à pulseIn évite au code d'attendre la seconde complète prévue par défaut quand aucune impulsion n'arrive ; si aucune impulsion n'est captée, la fonction renvoie 50 000, ce qui signifie "très sombre". Si tu as du mal à lire la sortie série, jette un œil au guide du moniteur série Arduino.

Calibrage blanc et noir : convertir les valeurs brutes en 0–255

Les valeurs brutes seules sont trompeuses, car les trois groupes de photodiodes n'ont pas la même sensibilité et les LED blanches du module n'émettent pas toutes les couleurs de façon égale. C'est pourquoi même une feuille d'un blanc éclatant donne des nombres différents sur les trois canaux. Le calibrage gomme ces écarts et place chaque canal entre 0 (noir) et 255 (blanc) ; c'est la même idée que la balance des blancs d'un appareil photo. Calibre à l'endroit où le capteur travaillera vraiment, avec la même lumière et à la même distance ; un calibrage fait sur ton bureau ne vaut pas dans le boîtier de la machine.

  1. Fixe le capteur sur un support et règle la distance de mesure (par exemple 1,5 cm) pour qu'elle ne change pas.
  2. Place une feuille blanche unie devant, lis plusieurs fois les valeurs R, V et B avec le code ci-dessus et note leurs moyennes comme référence blanche ; ce sont les plus petites valeurs.
  3. Mets au même endroit une feuille noire mate ou de la feutrine et note les valeurs comme référence noire ; ce sont les plus grandes valeurs.
  4. Saisis ces six nombres dans les constantes WHITE_ et BLACK_ au début du code suivant, puis téléverse-le.
  5. Vérifie que les trois canaux sont proches de 255 sur la feuille blanche et de 0 sur la noire ; sinon, refais la mesure avec la même lumière et la même distance.

Attention à une erreur présente dans beaucoup d'exemples : convertir directement la durée d'impulsion en 0–255 avec map() ne donne pas le bon résultat, car la lumière est proportionnelle à la fréquence et non à la durée de l'impulsion. La bonne méthode consiste à convertir d'abord la durée en fréquence (1/t), puis à mettre à l'échelle : niveau = (f − f_noir) / (f_blanc − f_noir) × 255. Prenons un exemple : tu as mesuré 20 µs sur le blanc, 200 µs sur le noir, et l'objet donne 40 µs. map() le transforme en 226, alors que la méthode par la fréquence donne 113. La fréquence de l'objet vaut exactement la moitié de celle du blanc et, une fois le niveau du noir retranché, cela correspond à environ 44 % de l'échelle, soit 113 ; map(), lui, affiche les couleurs bien plus claires qu'elles ne le sont et complique la distinction des teintes sombres.

Algorithme de tri des couleurs : de quelle couleur s'agit-il ?

Les valeurs R, V, B calibrées dépendent encore de la quantité de lumière : si le même objet rouge se rapproche un peu du capteur, les trois valeurs augmentent ensemble. Pour corriger cela, on divise chaque valeur par la somme : r = R / (R + G + B), et de même pour g et b. Ces proportions de couleur restent presque constantes même si la distance et la luminosité varient un peu. Tu les compares ensuite à des proportions de référence mesurées et enregistrées une fois pour chaque couleur, et tu choisis le plus proche voisin. Pour comparer, il suffit d'additionner les carrés des écarts ; plus ce nombre est petit, plus les couleurs se ressemblent. Si même la référence la plus proche dépasse un certain seuil, le résultat est "inconnu". Si la lumière totale est très faible, l'objet est considéré comme noir, et si les trois canaux sont très élevés, comme blanc ; ces deux cas ne se distinguent pas par les proportions, ils sont donc testés en premier.

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}
Partie du codeRôle
WHITE_* et BLACK_*Les durées d'impulsion du blanc et du noir mesurées au calibrage (µs)
toLevel()Convertit la durée d'impulsion en fréquence et la ramène entre 0 et 255
refs[]Proportions r, g, b de référence de chaque couleur ; remplace-les par tes propres mesures
classify()Sépare d'abord le noir et le blanc, puis cherche la référence la plus proche
MAX_DISTLes mesures au-delà de cette distance sont classées "Inconnu"
Ne devine pas les valeurs de référence, mesure-les : place un objet de chaque couleur 5 à 10 fois devant le capteur, fais la moyenne des proportions r, g, b affichées dans le moniteur série et inscris-les dans le tableau refs[]. Mesure sous la lumière et à la distance où la machine fonctionnera. Si les valeurs fluctuent, faire la moyenne de plusieurs mesures ou appliquer un filtre médian aide beaucoup ; tous les détails dans l'article sur le filtrage des données de capteurs.

Construire une machine qui trie les objets par couleur

Le projet TCS3200 le plus apprécié est une machine qui trie des bonbons colorés, des perles ou des pièces LEGO par couleur. Le mécanisme compte deux servos. Le servo d'alimentation, en haut, fait tourner un disque percé d'un trou où tient un seul objet : il prend d'abord un objet sous le tube de la trémie, l'amène devant le capteur puis, après la mesure, le lâche dans la goulotte du dessous. Le servo de la goulotte, en bas, oriente une goulotte inclinée et envoie l'objet dans le bac de sa couleur. Si tu utilises des servos pour la première fois, lis d'abord Qu'est-ce qu'un servomoteur ?.

  1. Installe la trémie et un tube un peu plus large que les objets, pour qu'ils tombent un par un sur le disque d'alimentation.
  2. Fixe le capteur pour qu'il voie l'objet posé sur le disque à 1–2 cm, et ferme l'ensemble pour bloquer la lumière extérieure.
  3. Définis trois angles pour le servo d'alimentation : chargement, capteur et largage. Trouve-les par essais sur ton propre mécanisme ; branche le servo d'alimentation sur D9 et celui de la goulotte sur D10.
  4. Attribue un angle du servo de goulotte à chaque bac de couleur (par exemple rouge 30°, vert 75°, bleu 120°, tout le reste 165°).
  5. Calibre à l'intérieur de la machine, avec son propre éclairage, et teste avec plusieurs objets de chaque couleur.
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}
Alimenter les servos par la broche 5V de l'Arduino peut faire chuter la tension à chaque mouvement et redémarrer la carte ; cette chute fausse aussi les mesures de couleur. Alimente les deux servos avec une source 5 V séparée et relie sa masse (GND) à celle de l'Arduino. Ne mesure pas pendant qu'un servo bouge ; comme dans le code, ajoute une courte pause une fois le servo en position.

TCS3200 avec ESP32 : mesurer la fréquence par interruption

Le même code avec pulseIn fonctionne sur l'ESP32, mais il existe une méthode plus stable : au lieu de chronométrer les impulsions une par une, compter combien arrivent pendant une durée fixe. Une interruption incrémente un compteur à chaque front montant ; en multipliant par 20 le compte obtenu après 50 ms, tu obtiens la fréquence en hertz. Comme cette méthode fait la moyenne de centaines d'impulsions, une seule impulsion perturbée ne la dérange pas. Le processeur à 240 MHz de l'ESP32 encaisse sans peine des dizaines de milliers d'interruptions par seconde à l'échelle 20 % ; si le compte devient trop grand sous une lumière très forte, tu peux passer à 2 %. Tu peux aussi utiliser cette méthode sur l'Arduino Uno en déplaçant OUT sur la broche D2, qui gère les interruptions. Sur l'ESP32, n'oublie pas d'alimenter le module par la broche 3V3.

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}

TCS3200 avec la Raspberry Pi Pico et MicroPython

Sur la Pico, l'équivalent du pulseIn d'Arduino est la fonction machine.time_pulse_us() : elle renvoie en microsecondes la durée d'une impulsion au niveau demandé, et un nombre négatif en cas de délai dépassé. Si on l'appelle alors que la broche est déjà à ce niveau, elle commence à mesurer immédiatement et peut ne mesurer qu'une demi-impulsion ; c'est pourquoi le code attend d'abord la fin de la partie HIGH, puis mesure la durée LOW. Comme chaque appel de fonction en MicroPython prend quelques microsecondes, nous avons choisi ici l'échelle 2 % (S0=0, S1=1) : les impulsions sont 10 fois plus longues et l'effet de ce retard diminue. Les valeurs de calibrage s'écrivent en Hz ; à l'échelle 2 %, il est normal de voir quelques kHz sur une feuille blanche et quelques centaines de Hz sur une noire. Alimente le module par la broche 3V3(OUT) de la Pico ; si tu découvres la Pico, Qu'est-ce que la Raspberry Pi Pico ? explique comment installer MicroPython.

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 ou TCS34725 ?

Le TCS34725 est un capteur de couleur plus récent qui fait le même travail en I2C. Il effectue la mesure dans la puce elle-même et fournit les résultats sous forme de nombres de 16 bits par canal ; l'Arduino n'a aucune impulsion à mesurer. Sa différence la plus importante est le filtre bloquant l'infrarouge (IR) placé sur ses photodiodes. Le TCS3200 n'en a pas ; comme les photodiodes en silicium sont aussi sensibles à l'infrarouge, les mesures dérivent sous une lumière riche en IR comme le soleil ou les ampoules à incandescence. Comme le gain (1x, 4x, 16x, 60x) et le temps d'intégration (2,4–614 ms) du TCS34725 se règlent par logiciel, il fonctionne sur une large plage, de la lumière très faible à la lumière vive. Si tu veux savoir comment fonctionne l'I2C, consulte l'article Qu'est-ce que l'I2C ?.

Module capteur de couleur I2C TCS34725
Module capteur de couleur TCS34725 : au centre la puce du capteur de couleur avec filtre IR, à côté une LED blanche ; broches LED, INT, SDA, SCL, 3V3, GND et VIN.
CaractéristiqueTCS3200TCS34725
SortieFréquence (signal carré)I2C, adresse 0x29
Fils de signalS0–S3, OUT et OESDA et SCL (INT et LED en option)
RésolutionDépend de la méthode et de la durée de mesure16 bits par canal
Filtre IRNonOui (sur la puce)
Réglages3 échelles de fréquence et mise hors tension4 gains, temps d'intégration de 2,4 à 614 ms
Alimentation2,7–5,5 VPuce en 3,3 V ; modules avec régulateur en 3–5 V
ÉclairageGénéralement 4 LED blanchesGénéralement 1 LED blanche
Charge du processeurOccupé pendant la mesure des impulsionsLa puce mesure, l'Arduino se contente de lire
Idéal pourApprendre, trieurs de couleurs simplesCouleur précise, température de couleur et mesure en lux
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}

Avant de téléverser le code, installe la bibliothèque Adafruit TCS34725 depuis le gestionnaire de bibliothèques ; quand il te propose les dépendances, choisis de toutes les installer. Sur l'Arduino Uno, relie SDA à A4 et SCL à A5 ; sur l'ESP32, aux GPIO 21 et 22. getRawData() attend la fin du temps d'intégration et renvoie les valeurs brutes rouge, verte, bleue et sans filtre (C) ; calculateColorTemperature_dn40() donne la température de couleur en kelvins et calculateLux() le niveau d'éclairement approximatif. Le calibrage et la logique de la couleur la plus proche s'appliquent de la même façon à ce capteur. Si tu cherches un capteur qui détecte aussi les gestes de la main et la proximité en plus de la couleur, l'APDS-9960 est une bonne alternative.

Idées de projets avec le TCS3200

  • Machine de tri par couleur : Trie des bonbons, des perles ou des pièces LEGO dans des bacs séparés selon leur couleur.
  • Lampe caméléon : Reproduis la couleur de l'objet placé devant le capteur avec une LED RVB ou un ruban WS2812B.
  • Robot qui lit les couleurs : Apprends à ton robot suiveur de ligne à s'arrêter sur un repère rouge au sol et à repartir sur un vert.
  • Bras robotique qui reconnaît les couleurs : Utilise un bras robotique pour saisir des cubes et déposer chaque couleur dans son propre bac.
  • Détecteur de couleur parlant : Annonce la couleur détectée avec un message préenregistré sur un DFPlayer Mini ; une aide pratique pour les personnes malvoyantes.
  • Suivi de la couleur de l'eau : Observe dans le temps les changements de couleur de l'eau d'un récipient transparent et déclenche une alerte pour un aquarium ou une cuve d'arrosage.

Erreurs fréquentes et solutions

SymptômeCause probableSolution
pulseIn renvoie toujours 0 ou la valeur de délaiOE en l'air ou à HIGH, S0 et S1 tous deux à LOW (hors tension) ou OUT sur la mauvaise brocheRelie OE à GND, mets S0 à HIGH et S1 à LOW, compare la broche OUT avec le code
Les valeurs sautent sans arrêtLumière ambiante, lampe qui scintille ou distance qui varieProtège le capteur avec un tube noir, fixe la distance, fais la moyenne de plusieurs mesures
Tous les objets sortent de la même couleurPas de calibrage ; les canaux n'ont pas la même sensibilitéFais le calibrage blanc et noir, mesure à nouveau les références
Les couleurs dérivent à la lumière du jourLe TCS3200 n'a pas de filtre IRMesure dans une boîte fermée ou utilise un TCS34725
Les niveaux restent bloqués à 0 ou 255L'objet n'est pas à la même distance qu'au calibrageGarde la même distance qu'au calibrage, recalibre si besoin
L'ESP32 ou la Pico se comporte bizarrementModule alimenté en 5 V, OUT sort du 5 VAlimente le module en 3V3 ou utilise un convertisseur de niveau
Les mesures se faussent quand le servo tourneLe courant du servo fait chuter la tension d'alimentationSource 5 V séparée pour les servos, masses reliées
Les surfaces brillantes et réfléchissantes (métal, plastique verni, papier glacé) renvoient la lumière des LED directement dans le capteur et font paraître les couleurs plus pâles qu'elles ne le sont. Incliner légèrement le capteur au lieu de le placer bien perpendiculaire, ou travailler avec des objets mats, réduit fortement le problème. Si tu dois seulement distinguer le noir du blanc, le TCRT5000 est un choix plus simple et plus rapide.

Le TCS3200 est un excellent capteur pour comprendre comment la lumière devient une fréquence, pourquoi le calibrage est indispensable et comment bâtir un algorithme de classification simple. Passer au TCS34725 quand tu as besoin de plus de précision est facile, car le calibrage et la logique de la couleur la plus proche que tu as appris restent valables tels quels. Dans l'application BlueGrays, tu trouveras des projets de mélange de couleurs avec une LED RVB, une lampe mélangeuse de couleurs à ESP32, la mesure de lumière avec une LDR et des projets à servomoteur, avec schémas de câblage et code pas à pas ; combine-les avec le capteur de couleur pour construire ta propre machine.

Questions fréquentes

À quelle distance le capteur TCS3200 détecte-t-il les couleurs ?

Les résultats les plus stables s'obtiennent vers 1–3 cm, car la lumière des LED du module faiblit vite avec la distance. Plus que la distance elle-même, l'essentiel est de la garder identique à chaque mesure ; fais aussi le calibrage à cette distance. Ce capteur ne convient pas pour lire la couleur de grandes surfaces éloignées.

Quelle est la différence entre le TCS230 et le TCS3200 ?

Le TCS230 est l'ancien capteur de couleur du même fabricant, et le TCS3200 sa version améliorée. Tous deux utilisent une matrice de photodiodes 8×8, une sortie en fréquence et la même logique de commande S0–S3 ; le câblage et le code sont donc identiques. La plupart des modules vendus aujourd'hui sont équipés d'un TCS3200.

Pourquoi pulseIn renvoie 0 avec le TCS3200 ?

pulseIn renvoie 0 lorsqu'il ne voit aucune impulsion dans le délai indiqué. Les causes les plus courantes sont une broche OE non reliée à GND, S0 et S1 tous deux à LOW (le capteur passe alors hors tension) et une sortie OUT branchée sur une autre broche que celle du code. Si tout est noir devant le capteur, la fréquence tombe à quelques hertz et aucune impulsion n'est captée avec un délai court.

Le TCS3200 fonctionne-t-il avec l'ESP32 et la Raspberry Pi Pico ?

Oui. Comme le TCS3200 fonctionne entre 2,7 et 5,5 V, tu peux alimenter le module par la broche 3V3 de la carte ; la broche OUT délivre alors aussi des impulsions de 3,3 V. Si tu l'alimentes en 5 V, il te faut un pont diviseur ou un convertisseur de niveau sur la ligne OUT. Pour mesurer en MicroPython sur la Pico, l'échelle de fréquence 2 % donne des résultats plus précis.

Lequel choisir : TCS3200 ou TCS34725 ?

Pour une mesure de couleur précise, le TCS34725 est meilleur : il possède un filtre anti-IR, une résolution de 16 bits par canal et un gain réglable, et se branche avec seulement deux fils I2C. Le TCS3200 reste un choix courant et tout à fait suffisant pour apprendre la mesure de fréquence et le calibrage, et pour construire des trieurs de couleurs simples.

Combien de couleurs le TCS3200 peut-il distinguer ?

Sous un éclairage maîtrisé et à distance fixe, le TCS3200 sépare de façon fiable 6 à 8 couleurs nettement différentes, comme le rouge, l'orange, le jaune, le vert, le bleu, le violet, le noir et le blanc. Distinguer des teintes proches, comme le vert clair et le vert foncé, est possible aussi, mais demande un calibrage plus soigné, de nombreuses mesures de référence par teinte et un seuil serré.

Voir tous les projets
Mesurer l'intensité lumineuse avec une LDR
#11Débutant

Mesurer l'intensité lumineuse avec une LDR

Envie de voir en chiffres à quel point ta chambre est lumineuse ? Le LDR, une petite pièce sensible à la lumière, mesure la lumière ambiante, et l'Arduino écrit la valeur sur l'écran de ton ordinateur

4.6(81)
139
Mesure de l'intensité lumineuse avec le module LDR ESP32
#113Débutant

Mesure de l'intensité lumineuse avec le module LDR ESP32

Suivi en temps réel sur le moniteur série de la valeur brute de l'ADC du module LDR et du pourcentage relatif de luminosité calculé à partir de références dans l'obscurité et à la lumière. Ce pourcentage n'est pas une mesure en lux. Permet de comprendre le principe de calibrage du module. Il est préférable de réaliser cet exercice avant le projet 10, car il sert à déterminer la valeur seuil.

4.6(36)
55
Utilisation d'une LED RVB
#39Débutant
Premium

Utilisation d'une LED RVB

Trois couleurs se cachent dans une seule LED : la LED RGB s'allume en rouge, puis en vert, puis en bleu, chaque couleur allumée une demi-seconde puis éteinte une demi-seconde, avant que tout recommenc

4.9(73)
98
Transition douce des couleurs avec une LED RVB
#40Débutant
Premium

Transition douce des couleurs avec une LED RVB

Une seule LED RGB glisse doucement du rouge au vert, du vert au bleu, puis revient au rouge, dans une boucle arc-en-ciel qui ne s'arrête jamais. Chaque transition dure environ deux secondes et demie,

4.8(58)
76
Lampe à mélangeur de couleurs ESP32 (3 potentiomètres + LED RVB + écran OLED)
#138Avancé
Premium

Lampe à mélangeur de couleurs ESP32 (3 potentiomètres + LED RVB + écran OLED)

Une lampe mélangeuse de couleurs intelligente qui vous permet de créer la couleur de votre choix en tournant 3 potentiomètres grâce à l'ESP32 ! À mesure que vous tournez les potentiomètres rouge, vert et bleu, la LED RVB à cathode commune change de couleur en temps réel. L'écran OLED SSD1306 affiche en temps réel la valeur de chaque couleur sur une plage de 0 à 255, des barres de remplissage visuelles et le code couleur HEX (#FF8040, par exemple). Un mini-studio de couleur professionnel — il per

4.7(6)
10
Contrôle d'une LED RVB avec ESP32
#111Débutant

Contrôle d'une LED RVB avec ESP32

Génération illimitée de couleurs avec une seule LED RVB au lieu de 3 LED séparées. Comme dans Arduino, nous réalisons une transition arc-en-ciel en réglant les valeurs R/G/B avec analogWrite(). La théorie des couleurs (telle que rouge+vert=jaune) est mise en pratique.

4.6(29)
51
Utilisation du servomoteur
#35Débutant
Premium

Utilisation du servomoteur

Le bras d'un petit servomoteur tourne tour à tour vers trois positions : tout au début, pile au milieu et tout au bout, en attendant deux secondes à chaque arrêt. L'Arduino indique au moteur l'angle à

4.7(48)
67
TCRT5000 Détection de surface noire et blanche
#78Intermédiaire
Premium

TCRT5000 Détection de surface noire et blanche

Avec le petit capteur qui sert d'œil aux robots suiveurs de ligne, tu sais si le sol est noir ou blanc. Le TCRT5000 envoie une lumière invisible vers le sol et regarde combien revient ; sur du blanc l

4.7(40)
49