jeudi 2 janvier 2014

Arduino et perception des couleurs: construction d'une sonde RGB

Saviez-vous qu'il est facile et peu coûteux de fabriquer une sonde qui permettra à votre Arduino de connaître la couleur d'un objet?  Par exemple, grâce à cette sonde, votre robot pourrait reconnaître la pièce de la maison dans laquelle il se trouve en se basant sur la couleur des murs et du plancher. Vous pouvez aussi vous en servir dans cette impressionnante machine à trier les bonbons­.


Matériel:

Pour la fabrication de cette sonde, je me suis beaucoup inspiré de ce projet publié par Fjordcarver sur Instructables, par contre j'ai ajouté deux boutons poussoir qui déclenchent la calibration du capteur et la lecture de la couleur (dans le projet de Fjordcarver, la calibration se faisait au démarrage, et la lecture de la couleur se faisait ensuite sans arrêt).  Tout le matériel est facile à trouver:  une LED RGB à cathode commune (qu'on peut très bien remplacer par trois LEDs distinctes:  une rouge, une verte et une bleue), une photorésistance, une résistance de 220 Ω pour protéger la LED, une autre résistance pour mettre en série avec le photorésistance (j'ai utilisé 10 kΩ), deux boutons poussoir,  et bien sûr l'Arduino de votre choix (j'ai utilisé un Uno).  


Principe de fonctionnement:

Pour mesurer la couleur d'un objet, nous allons utiliser le système "RGB" qui consiste à assigner un nombre entre 0 et 255 pour chacune de ses trois composantes, soit le rouge (R), le vert (G) et le bleu (B).  Pour ce faire, nous allons éclairer l'objet avec une source de lumière rouge et mesurer au moyen de la photorésistance la quantité de lumière réfléchie par l'objet, puis répéter la mesure avec la lumière verte et la lumière bleue.

Un objet rouge réfléchira fortement la couleur émise par la LED rouge, mais beaucoup plus faiblement la lumière émise par la LED verte et la LED bleue.  Un objet blanc réfléchira fortement chacune des 3 couleurs, etc.

Puisque la couleur est mesurée par réflexion, ce dispositif ne permet pas de déterminer la couleur émise par une source de lumière (par exemple une LED colorée).

Le montage électrique:

Le montage est tellement simple que Fritzing fera parfaitement l'affaire pour l'illustrer:



La LED RGB est branchée aux entrées 2 (rouge), 3 (vert) et 4 (bleu) de l'Arduino.  La cathode commune à toutes les couleurs est branchée à une résistance protectrice de 220 Ω, qui est elle-même reliée à la masse (GND).  Une broche de la photorésistance est reliée à la masse (GND), et son autre broche est reliée à la fois à l'entrée A0 de l'Arduino, ainsi qu'à une résistance fixe (j'ai utilisé 10 kΩ). L'autre broche de la résistance fixe est reliée à + 5 V.

Deux boutons poussoirs sont reliés directement à la masse (GND); j'utilise les résistances pull-up interne de l'Arduino, donc pas besoin de résistance externe pour accompagner ces boutons.  L'autre borne du bouton de lecture des couleurs est branchée à l'entrée 5 de l'Arduino, alors que le bouton de calibration est relié à l'entrée 6.

Assurez-vous que la photoésistance est placée à proximité de la LED.  Mais attention:  vous voulez que la photorésistance capte la lumière réfléchie par l'objet et non la lumière provenant directement de la LED: pensez à insérer un carton noir ou autre obstacle opaque entre la LED et la photorésistance:




Pour mes tests sur breadboard, tout mon circuit était enfermé dans un récipient en carton noir afin d'éviter que la lumière ambiante n'affecte mes résultats (l'objet coloré était placé au dessus de ce récipient):



Après que les tests sur breadboard se soient révélé concluants, j'ai ensuite construit une sonde plus permanente en soudant les composants à l'extrémité d'un câble à six conducteurs (long de quelques dizaines de centimètres) ayant jadis servi à brancher un quelconque périphérique d'ordinateur:



...et en les enfermant dans un récipient opaque (un récipeint de Kinder Surprise dont l'intérieur est peint en noir; le diamètre est inutilement grand, mais c'est ce que j'avais de mieux sous la main):






Le sketch:

Le sketch est relativement simple:  chaque fois que vous appuyez sur le bouton poussoir de lecture, les trois couleurs de la LED RGB s'allument l'une après l'autre. Pour chaque couleur de la LED, on mesure la réflexion captée par la photorésistance (en faisant la moyenne sur plusieurs mesure pour une meilleure fiabilité).

Dans le système RGB, le noir est représenté par R = 0, G = 0 et B = 0 alors que le blanc est représenté par R = 255, G = 255 et B = 255.  Le sketch comporte donc une routine de calibration qui mesure la réflexion d'un objet blanc et d'un objet noir.  Ces données sont ensuite utilisées pour assigner une valeur entre 0 et 255 pour chaque couleur mesurée.

/**************Capteur de couleurs *************************
*
* Ce sketch pour Arduino contrôle un capteur de couleurs
* constitué d'une LED RGB et d'une photorésistance. Le code RGB et
* le nom de la couleur sont affichés sur le moniteur série.
* Branchements: RGB rouge: sortie 2
* RGB vert: sortie 3
* RGB bleu: sortie 4
* (résistance de 220 ohms entre la LED et GND)
* Photorésisteur en série avec une résistance de 10K
* Singnal du photorésisteur acheminé à l'entrée A0
* Basé sur un sketch de fjordcarver:
* http://www.instructables.com/id/Using-an-RGB-LED-to-Detect-Colours/
* Adapté par Yves Pelletier:
* http://electroniqueamateur.blogspot.com/2014/01/arduino-et-perception-des-couleurs.html
*
***********************************************************/
int ledPin[] = {
2,3,4}; // Numéro des pins de la LED (rouge 2, vert 3 et bleu 4)
int readButtonPin = 5; // Numéro de pin du bouton de lecture de couleur
int calibrateButtonPin = 6; //Numéro de pin du bouton de calibration
int colourArray[] = {
0,0,0}; // code RGB de la couleur mesurée
int whiteArray[] = {
0,0,0}; // résultats mesurés pour le blanc lors de la calibration
int blackArray[] = {
0,0,0}; // résultats mesurés pour le noir lors de la calibration
int ConvertedArray[] = {
0,0,0}; // coulourArray pondéré pour que le total soit 100
//moyenne sur plusieurs lectures
int avgRead;
void setup(){
//on règle les pins de la LED en sortie
pinMode(ledPin[0],OUTPUT);
pinMode(ledPin[1],OUTPUT);
pinMode(ledPin[2],OUTPUT);
//Pour les boutons
pinMode(readButtonPin, INPUT);
digitalWrite(readButtonPin, HIGH); // on active la résistance pullup interne
pinMode(calibrateButtonPin, INPUT);
digitalWrite(calibrateButtonPin, HIGH); // on active la résistance pullup interne
//initialisation du moniteur série
Serial.begin(9600);
Serial.println("Avant de prendre une mesure, veuillez calibrer l'appareil.");
}
void loop(){
if (!digitalRead(readButtonPin)){
checkColour();
}
if (!digitalRead(calibrateButtonPin)){
calibration();
}
}
void calibration(){
//acquisition du blanc
// message à l'utilisateur par le moniteur Série
Serial.print("Debut de la calibration: Mettre du blanc SVP...3...");
delay(1000);
Serial.print("2...");
delay(1000);
Serial.print("1...");
delay(1000);
Serial.println("0!");
// on allume chaque couleur une à la fois
for(int i = 0;i<=2;i++){
digitalWrite(ledPin[i],HIGH);
delay(100);
whiteArray[i] = getReading(5); // une moyenne est prise sur le nombre de lectures indiqué entre parenthèses.
digitalWrite(ledPin[i],LOW);
delay(100);
}
// message à l'utilisateur par le moniteur Série
Serial.print("Suite de la calibration: Mettre du noir SVP...3...");
delay(1000);
Serial.print("2...");
delay(1000);
Serial.print("1...");
delay(1000);
Serial.println("0!");
//on mesure encore les 3 couleurs de LED, mais cette fois pour une cible noire
for(int i = 0;i<=2;i++){
digitalWrite(ledPin[i],HIGH);
delay(100);
blackArray[i] = getReading(10);
digitalWrite(ledPin[i],LOW);
delay(100);
}
// résultats de la calibration affichés au moniteur série
// (utile seulement pour déboguer).
Serial.println("Calibration terminee. Resultats: ");
Serial.print ("Blancs: R: ");
Serial.print (whiteArray[0]);
Serial.print (" G: ");
Serial.print (whiteArray[1]);
Serial.print (" B: ");
Serial.println (whiteArray[2]);
Serial.print ("Noirs: R: ");
Serial.print (blackArray[0]);
Serial.print (" G: ");
Serial.print (blackArray[1]);
Serial.print (" B: ");
Serial.println (blackArray[2]);
Serial.println("Vous pouvez maintenant prendre des mesures.");
}
void checkColour(){
for(int i = 0;i<=2;i++){
digitalWrite(ledPin[i],HIGH); //on allume la LED de couleur appropriée
delay(100); //on laisse à la photorésistance le temps de réagir
colourArray[i] = getReading(10); //on lit la photorésistance (moyenne sur plusieurs lectures)
float greyDiff = whiteArray[i] - blackArray[i]; // différence entre blanc et noir
colourArray[i] = (colourArray[i] - blackArray[i])/(greyDiff)*255; // conversion pour donner une valeur entre 0 et 255
if (colourArray[i] < 0){ // pas de valeur négative SVP
colourArray[i] = 0;
}
digitalWrite(ledPin[i],LOW); // on éteint la LED
delay(100);
}
// on écrit le code RGB au moniteur série
Serial.print("R = ");
Serial.print(int(colourArray[0]));
Serial.print(" G = ");
Serial.print(int(colourArray[1]));
Serial.print(" B = ");
Serial.println(int(colourArray[2]));
// de quelle couleur s'agit-il?
// pour la suite, pondérons les valeurs pour que le total des 3 donne 100
short total = colourArray[0] + colourArray[1] + colourArray[2];
ConvertedArray[0] = colourArray[0]*100/total;
ConvertedArray[1] = colourArray[1]*100/total;
ConvertedArray[2] = colourArray[2]*100/total;
// on écrit le code RGB pondérés au moniteur série
Serial.print("Valeurs ponderees: R = ");
Serial.print(int(ConvertedArray[0]));
Serial.print(" G = ");
Serial.print(int(ConvertedArray[1]));
Serial.print(" B = ");
Serial.println(int(ConvertedArray[2]));
identificationCouleur();
}
// on essaie de nommer la couleur à partir du code RGB
void identificationCouleur(void){
// si les 3 valeurs sont trés élevées, c'est du blanc
if (colourArray[0] > 240 && colourArray[1] > 240 && colourArray[2] > 240) {
Serial.println("Cet objet est blanc.");
}
// si les 3 valeurs sont très basses, c'est du noir
else if (colourArray[0] < 30 && colourArray[1] < 30 && colourArray[2] < 30) {
Serial.println("Cet objet est noir.");
}
// si les 3 valeurs sont équivalentes, c'est du gris
else if (ConvertedArray[0] > 28 && ConvertedArray[0] < 38 && ConvertedArray[1] > 28 && ConvertedArray[1] < 38 && ConvertedArray[2] > 28 && ConvertedArray[2] < 38) {
Serial.println("Cet objet est gris.");
}
//plutôt rouge
else if (ConvertedArray[0] > 55) {
if (ConvertedArray[1] > 20) {
Serial.println("Cet objet est orange.");
}
else {
Serial.println("Cet objet est rouge.");
}
}
// plutôt vert
else if (ConvertedArray[1] > 55) {
Serial.println("Cet objet est vert.");
}
// plutôt bleu
else if (ConvertedArray[2] > 55) {
Serial.println("Cet objet est bleu.");
}
else if (ConvertedArray[0] + ConvertedArray[1] > 80) {
Serial.println("Cet objet est jaune.");
}
else if (ConvertedArray[0] + ConvertedArray[2] > 80) {
Serial.println("Cet objet est violet.");
}
else if (ConvertedArray[1] + ConvertedArray[2] > 80) {
Serial.println("Cet objet est turquoise.");
}
else{
Serial.println("Couleur non reconnue.");
}
}
// lecture de la valeur de la photorésistance
// (on mesure plusieurs fois consécutives, et on retourne la moyenne)
int getReading(int times){
int reading;
int tally=0;
for(int i = 0;i < times;i++){
reading = analogRead(0);
tally = reading + tally;
delay(10);
}
return (tally)/times; // moyenne des mesures
}

Utilisation de la sonde

Après avoir téléversé le sketch dans votre Arduino, vous affichez à l'écran le moniteur série, car c'est de cette façon que l'Arduino vous communiquera les résultats de ses mesures.

Commencez par calibrer votre capteur en appuyant sur le bouton de calibration (celui qui est relié à l'entrée 6 de l'Arduino).  L'Arduino vous demandera d'abord d'appuyer votre sonde sur un objet blanc (une feuille de papier, par exemple), puis ensuite sur un objet noir (mat, de préférence).

Ensuite, appuyez la sonde sur un objet coloré, puis appuyez sur le bouton de lecture (celui qui est branché à l'entrée 5 de l'Arduino).  Le code RGB correspondant à la couleur de l'objet s'affichera sur le moniteur série. L'Arduino tentera également de nommer la couleur (cette partie est à améliorer:  ça marche la plupart du temps, mais pas toujours).

À lire également:

3 commentaires:

  1. Bonjour,

    Tout d'abord merci pour vos montages extrêmement intéressant !
    Je viens de me lancer dans le monde "Arduino" et je découvre (difficilement) plein de choses :)

    Mon travail étant l'image (je suis retoucheur photo) , je suis très intéressé par votre montage de perception des couleurs.
    J'ai reçu mon matériel, et j'ai pris dans la foulée un écran LCD.
    Je souhaiterai afficher les informations du moniteur sur mon petit LCD.

    Pourriez vous m'éclairer sur ce point ?


    Merci encore pour votre partage !
    A vite,

    Tony.

    RépondreSupprimer
  2. Bonjour,

    très bien fait votre système de perception de couleurs
    je l'ai testé. j'aimerai y apporter en complément une recherche de valeurs approchées dans un tableau de codes
    RVB pour identifier une couleur pourriez-vous m'aider

    RépondreSupprimer
  3. Bonjour j'ai essayé ce programme et ce circuit mais lors de la calibration, les valeurs affiché atteignent 1023 alors que les valeurs sont censé être comprises entre 0 et 255. J'ai tout essayé (revérifier les branchements et les composants) mais je ne parviens pas à savoir quel est le problème. Pouvez vous m'aider s'il vous plaît?

    RépondreSupprimer