Skip to Content

Capteur de gestes et de couleurs APDS-9960 avec Arduino

Capteur de gestes et de couleurs APDS-9960 avec Arduino

Dans ce tutoriel, vous allez apprendre à utiliser le capteur de gestes et de couleurs RGB APDS-9960 avec un Arduino ou d’autres microcontrôleurs courants comme l’ESP32 ou l’ESP8266.

L’APDS-9960 est un capteur très compact qui utilise la lumière infrarouge et des photodiodes pour reconnaître quatre gestes différents (de gauche à droite, de droite à gauche, de haut en bas, de bas en haut). Il possède également des détecteurs intégrés pour la lumière ambiante, la mesure des couleurs (rouge, vert, bleu) et la proximité.

Matériel nécessaire

Pour ce projet, il vous faut un capteur APDS-9960 et un microcontrôleur. J’ai utilisé un Arduino Uno mais n’importe quel autre Arduino ou un ESP32/ESP8266 fera l’affaire, tant qu’il fournit une sortie 3,3V. Un des exemples utilise aussi un servo, mais ce n’est pas indispensable pour ce projet.

Capteur APDS-9960

Arduino

Arduino Uno

USB Data Sync cable Arduino

Câble USB pour Arduino UNO

Dupont wire set

Jeu de fils Dupont

Half_breadboard56a

Breadboard

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Caractéristiques du capteur de gestes et de couleurs RGB APDS-9960

L’APDS-9960 est une puce minuscule (3,94×2,36×1,35 mm) qui offre une détection avancée des gestes, la détection de proximité, la mesure numérique de la lumière ambiante (ALS) et la détection des couleurs (RGBC). L’image ci-dessous montre la puce APDS-9960 :

APDS-9960 chip
Puce APDS-9960

La détection des gestes est réalisée grâce à quatre photodiodes directionnelles qui captent la lumière infrarouge réfléchie (émise par la LED intégrée), laquelle est ensuite convertie en informations numériques de mouvement (vitesse, direction et distance). Des gestes simples HAUT-BAS-DROITE-GAUCHE ou des gestes plus complexes peuvent être détectés.

La fonction de détection des couleurs et de la lumière ambiante (ALS) de l’APDS-9960 fournit des données d’intensité lumineuse pour le rouge, le vert, le bleu et le canal clair. Chacun des canaux R, G, B, C possède un filtre bloquant les UV et l’IR ainsi qu’un convertisseur de données dédié produisant des données 16 bits simultanément.

Schéma fonctionnel de l’APDS-9960

L’image ci-dessous montre le schéma fonctionnel de l’APDS-9960. Vous pouvez facilement identifier la LED émettrice IR, les quatre photodiodes pour la détection des couleurs (Clair, Rouge, Vert, Bleu), et les quatre photodiodes pour la détection des gestes (Haut, Bas, Gauche, Droite).

Schéma fonctionnel de l’APDS-9960 (source)

L’APDS-9960 communique via une interface I2C (SCL, SDA) et dispose d’une sortie d’interruption supplémentaire (INT) qui s’active lorsqu’un seuil programmable est dépassé (par exemple, la proximité).

La tension de fonctionnement de l’APDS-9960 est de 2,4V à 3,6V, la plage de mesure des gestes est de 10 à 20 cm et l’adresse I2C est 0x39. Pour plus de détails, consultez la fiche technique ci-dessous :

Breakout board pour APDS-9960

La puce APDS-9960 est trop petite pour être connectée directement à un Arduino. En général, vous aurez besoin d’une breakout board comme celle-ci :

Front and Back of breakout board for APDS-9960
Avant et arrière de la breakout board pour APDS-9960

La plupart des breakout boards pour l’APDS-9960 possèdent les six broches suivantes :

  • VCC : Alimentation (2,4 – 3,6V)
  • GND : Masse
  • VL : Alimentation LED IR
  • SDA : Signal de données I2C
  • SCL : Signal d’horloge I2C
  • INT : Broche d’interruption

En général, seules les broches d’alimentation (VCC, GND), les broches pour la communication I2C (SCL, SDA) et la broche d’interruption (INT) sont nécessaires. VL permet d’alimenter la LED IR séparément, ce qui n’est généralement pas utile.

Notez que l’APDS-9960 fonctionne en 3,3V et que la plupart des breakout boards n’ont généralement pas de régulateur de tension.

Connexion de l’APDS-9960 à l’Arduino

Grâce à l’interface I2C de l’APDS-9960, la connexion à un Arduino est simple. Commencez par connecter la broche SCL de la breakout board APDS-9960 à A5 de l’Arduino. De même, connectez SDA à A4 de l’Arduino. Ensuite, reliez GND à GND et 3,3V à VCC de l’APDS-9960.

Connecting APDS-9960 to Arduino
Connexion de l’APDS-9960 à l’Arduino

Assurez-vous d’utiliser du 3,3V comme alimentation. Le capteur APDS-9960 n’est pas prévu pour du 5V et les breakout boards pour l’APDS-9960 n’ont généralement pas de régulateur de tension.

Installer la bibliothèque pour APDS-9960

Il existe deux principales bibliothèques Arduino pour l’APDS-9960. La Adafruit_APDS9960 bibliothèque et la SparkFun_APDS-9960_Sensor_Arduino_Library. J’utiliserai la bibliothèque Adafruit_APDS9960 dans ce projet.

Pour installer la bibliothèque Adafruit_APDS9960, ouvrez le LIBRARY MANAGER, cherchez « APDS9960 », trouvez la bibliothèque d’Adafruit et installez-la, comme montré ci-dessous :

Installing APDS9960 Library by Adafruit via Library Manager
Installation de la bibliothèque APDS9960 d’Adafruit via le Library Manager

L’installateur peut vous demander d’installer des dépendances. Pas de souci, cliquez simplement sur « INSTALL ALL »

Installing dependencies of  APDS9960 Library by Adafruit
Installation des dépendances de la bibliothèque APDS9960 d’Adafruit

Une fois la bibliothèque installée, écrivons un petit code de test pour essayer le capteur. Téléversez le code suivant et passez votre main devant le capteur à environ 5 cm.

#include "Adafruit_APDS9960.h"

Adafruit_APDS9960 sensor;

void setup() {
  Serial.begin(9600);
  if (!sensor.begin()) {
    Serial.println("failed to initialize device!");
  }
  sensor.enableProximity(true);
  sensor.enableGesture(true);
}


void loop() {
  if(sensor.readGesture()) {
    Serial.println("Movement detected");
  }  
}

Si vous voyez le message « Movement detected » affiché dans le Serial Monitor, tout fonctionne. Par contre, si vous voyez « failed to initialize device! », cela se complique un peu et il faut lire la section suivante. Si tout va bien, vous pouvez passer à la suite.

Adafruit_APDS9960: failed to initialize device!

Commencez par vérifier que le câblage est correct (SCL->A5, SDA->A4, VCC->3V3, GND->GND). Si le câblage est bon et que le capteur n’est pas défectueux, il y a principalement deux raisons pour lesquelles sensor.begin() peut échouer. Une adresse I2C différente ou un identifiant de puce différent. Vérifions d’abord l’adresse I2C.

Adresse I2C différente de l’APDS9960

L’adresse I2C habituelle de l’APDS9960 est 0x39 et la bibliothèque Adafruit_APDS9960 attend cette adresse I2C. Pour vérifier cela, installez et lancez le code I2C scanner suivant :

#include "I2CScanner.h"

I2CScanner scanner;

void setup() {
  Serial.begin(9600);
  scanner.Init();
}

void loop() {
  scanner.Scan();
  delay(5000);
}

Le scanner I2C devrait trouver un périphérique I2C à l’adresse 0x39 et l’afficher dans le Serial Monitor.

I2C device found at address 0x39  !
--- Scan finished ---

Si vous voyez une adresse I2C différente, il faut alors modifier le code dans la fonction setup comme suit et remplacer « addr » par l’adresse I2C que vous voyez.

void setup() {
  ...
  if (!sensor.begin(10, APDS9960_AGAIN_4X, addr, &Wire)) {
    Serial.println("failed to initialize device!");
  }
  ...
}

Si votre adresse I2C est 0x39 ou si vous avez changé l’adresse I2C comme décrit ci-dessus mais que sensor.begin() échoue toujours, alors le prochain suspect est un identifiant de puce différent. Si le scanner I2C ne trouve aucun périphérique, il est probable que votre capteur soit défectueux (ou que le câblage soit encore incorrect).

Identifiant de puce différent pour l’APDS9960

Si vous regardez dans le code de la fonction begin() dans la bibliothèque Adafruit_APDS9960, vous verrez que le code utilise d’abord l’adresse I2C addr. Il vérifie ensuite l’identifiant de la puce et s’attend à ce qu’il soit 0xAB.

boolean Adafruit_APDS9960::begin(uint16_t iTimeMS, apds9960AGain_t aGain,
                                 uint8_t addr, TwoWire *theWire) {

  if (i2c_dev)
    delete i2c_dev;
  i2c_dev = new Adafruit_I2CDevice(addr, theWire);
  if (!i2c_dev->begin()) {
    return false;
  }

  /* Make sure we're actually connected */
  uint8_t x = read8(APDS9960_ID);
  if (x != 0xAB) {
    return false;
  }

Cependant, j’ai un APDS9960 avec l’identifiant de puce 0xA8 (et non 0xAB) et la SparkFun_APDS-9960_Sensor_Arduino_Library indique un autre identifiant de puce, qui est 0x9C.

Comme l’identifiant de la puce est codé en dur, il faut modifier le code. Le plus simple est de télécharger deux fichiers Adafruit_APDS9960.h et Adafruit_APDS9960.cpp dans votre dossier de projet, à côté de votre sketch, par exemple MySketch.ino :


Adafruit library files copied into sketch folder
Fichiers de la bibliothèque Adafruit copiés dans le dossier du sketch

Vous verrez alors ces deux nouveaux fichiers apparaître comme des onglets dans l’IDE Arduino :

Fichiers de la bibliothèque Adafruit dans l’IDE Arduino

Ouvrez maintenant l’onglet avec le fichier Adafruit_APDS9960.cpp, trouvez la fonction begin et supprimez ou commentez simplement le bloc annoté avec /* Make sure we're actually connected * / comme montré ci-dessous :

boolean Adafruit_APDS9960::begin(uint16_t iTimeMS, apds9960AGain_t aGain,
                                 uint8_t addr, TwoWire *theWire) {

  if (i2c_dev)
    delete i2c_dev;
  i2c_dev = new Adafruit_I2CDevice(addr, theWire);
  if (!i2c_dev->begin()) {
    return false;
  }

  /* Make sure we're actually connected */
  // uint8_t x = read8(APDS9960_ID);
  // if (x != 0xAB) {
  //  return false;
  // }

Sinon, vous pouvez aussi afficher « x » pour connaître l’ID de votre puce et adapter le test if (x != 0xAB) en conséquence.

Si vous ne souhaitez pas modifier le code vous-même, j’ai créé une version modifiée des deux fichiers, que vous pouvez télécharger ici (link). Il faudra quand même décompresser les fichiers et les copier dans votre projet. Avec cette correction, le code de test ci-dessus devrait maintenant fonctionner.

Reconnaître les gestes avec l’APDS-9960

Le code suivant est une légère extension du code de test précédent. Comme avant, dans la fonction setup, on initialise le capteur avec sensor.begin() puis on active la détection de proximité et de gestes :

#include "Adafruit_APDS9960.h"

Adafruit_APDS9960 sensor;

void setup() {
  Serial.begin(9600);
  if (!sensor.begin()) {
    Serial.println("failed to initialize device!");
  }
  sensor.enableProximity(true);
  sensor.enableGesture(true);
}


void loop() {
  uint8_t gesture = sensor.readGesture();
  if (gesture == APDS9960_DOWN) Serial.println("DOWN");
  if (gesture == APDS9960_UP) Serial.println("UP");
  if (gesture == APDS9960_LEFT) Serial.println("LEFT");
  if (gesture == APDS9960_RIGHT) Serial.println("RIGHT");
}

Dans la fonction loop, on appelle sensor.readGesture() et selon la valeur retournée, on affiche le geste détecté dans le Serial Monitor.

Maintenant, passez votre main devant le capteur à une distance d’environ 5 à 10 cm et selon la direction, vous devriez voir le geste détecté affiché dans le Serial Monitor comme ci-dessous :

Detected Gestures on Serial Monitor
Gestes détectés sur le Serial Monitor

Au lieu d’afficher dans le Serial Monitor, vous pouvez maintenant modifier le code pour allumer des LEDs, contrôler des servos ou déclencher toute autre action selon le geste. Les sections suivantes montrent un exemple simple pour contrôler un servo avec des gestes.

Contrôler un servo avec le capteur de gestes APDS-9960

D’abord, il faut connecter le servo à l’Arduino. Si vous avez un de ces petits Micro Servos SG90, vous pouvez les brancher directement à un Arduino (pas besoin d’alimentation séparée). Connectez simplement le fil rouge (broche du milieu) du servo au 5V, le fil marron à la masse (GND) et le fil orange/jaune à la broche 13, comme ci-dessous.

Connecting Servo to Arduino
Connexion du servo à l’Arduino

Si vous avez besoin de plus d’infos sur la connexion et l’utilisation de ces servos, consultez le tutoriel How to control servo motors with Arduino.

Le code pour contrôler le servo avec un geste est une simple variante du code précédent pour la détection des gestes.

#include "Adafruit_APDS9960.h"
#include "Servo.h"

Adafruit_APDS9960 sensor;
Servo servo;

const int servoPin = 13;

void setup() {
  if (!sensor.begin()) {
    Serial.println("failed to initialize device!");
  }
  sensor.enableProximity(true);
  sensor.enableGesture(true);
  servo.attach(servoPin);
  servo.write(90);
}

void loop() {
  uint8_t gesture = sensor.readGesture();
  if (gesture == APDS9960_DOWN) servo.write(90);
  if (gesture == APDS9960_UP) servo.write(90);
  if (gesture == APDS9960_LEFT) servo.write(10);
  if (gesture == APDS9960_RIGHT) servo.write(170);
}

D’abord, on inclut la bibliothèque standard Servo (pas besoin d’installation). Ensuite, on crée l’objet servo et on définit la broche à laquelle le servo est connecté (servoPin).

Dans la fonction setup, on attache le servo à la broche et on l’oriente initialement à 90°. Dans la fonction loop, on remplace les appels à la fonction print par des commandes write pour le servo. Un geste haut ou bas place le servo à 90°, un geste gauche à 10° et un geste droite à 170°. Le court extrait vidéo ci-dessous montre le code en action :

Controlling Servo with Gestures and APDS-9960
Contrôle d’un servo avec gestes et APDS-9960

Voilà, vous avez maintenant un contrôle gestuel simple pour un petit servo, que vous pouvez utiliser, par exemple, pour ouvrir ou fermer une boîte sans contact. Dans l’exemple suivant, nous allons tester le capteur de couleur intégré à l’APDS-9960.

Mesurer les couleurs avec l’APDS-9960

Le code ci-dessous utilise le capteur de couleur de l’APDS-9960 pour mesurer les valeurs de couleur rouge, vert, bleu et clair, et les affiche dans le Serial Monitor.

On commence par inclure la bibliothèque Adafruit et créer l’objet capteur. Dans la fonction setup, on initialise le capteur comme d’habitude avec sensor.begin(), puis on appelle sensor.enableColor(true) pour activer le capteur de couleur.

#include "Adafruit_APDS9960.h"

Adafruit_APDS9960 sensor;

void setup() {
  Serial.begin(9600);
  if (!sensor.begin()) {
    Serial.println("failed to initialize device!.");
  }
  sensor.enableColor(true);
}

void loop() {
  uint16_t r, g, b, c, tmp, lux;

  while (!sensor.colorDataReady()) {
    delay(5);
  }

  sensor.getColorData(&r, &g, &b, &c);
  Serial.print("red:");
  Serial.println(r);

  Serial.print("green:");
  Serial.println(g);

  Serial.print("blue:");
  Serial.println(b);

  Serial.print("clear:");
  Serial.println(c);

  tmp = sensor.calculateColorTemperature(r, g, b);
  Serial.print("tmp:");
  Serial.println(tmp);

  lux = sensor.calculateLux(r, g, b);
  Serial.print("lux:");
  Serial.println(lux);

  Serial.println();

  delay(1000);
}

Dans la fonction loop, on appelle sensor.colorDataReady() pour récupérer les valeurs de couleur rouge (r), vert (g), bleu (b) et clair (c), puis on les affiche dans le Serial Monitor.

La bibliothèque Adafruit_APDS9960 propose deux fonctions supplémentaires qui permettent de calculer la température de couleur et la luminosité en lux à partir des valeurs mesurées. On affiche aussi ces valeurs dans le Serial Monitor.

Si vous changez la luminosité de la lumière ambiante ou placez des LEDs de différentes couleurs devant le capteur, vous verrez que les valeurs de couleur changent.

Test de la détection des couleurs de l’APDS-9960

Pour tester la détection des couleurs de l’APDS-9960, j’ai utilisé des LEDs rouges, vertes et bleues. Voici les valeurs mesurées lorsque j’ai placé une LED rouge près du capteur :

red:329
green:26
blue:47
clear:342
tmp:24902
lux:65436

Comme prévu, la valeur rouge est bien plus élevée que les valeurs verte et bleue. Notez aussi que les valeurs de température de couleur et de luminosité (lux) sont très élevées. Il semble que la lumière de la LED rouge perturbe ces mesures.

Ensuite, j’ai utilisé une LED verte. Elle était relativement faible et la valeur verte n’a augmenté que légèrement. La valeur rouge a aussi augmenté. On voit à la valeur lux que la luminosité de ma LED verte était faible.

red:15
green:16
blue:6
clear:42
tmp:3045
lux:15

Enfin, j’ai essayé une LED bleue et obtenu les valeurs ci-dessous. La valeur bleue était très élevée mais il y a aussi eu une augmentation du composant vert.

red:40
green:561
blue:2507
clear:2751
tmp:1754
lux:64574

La réponse du capteur de couleur dépend évidemment de la luminosité et de la longueur d’onde de la lumière colorée. Mes LEDs n’étaient pas forcément dans la plage la plus sensible, ce qui peut expliquer la faible réaction à la LED bleue. Mais on voit aussi sur le graphique de réponse spectrale ci-dessous que l’APDS-9960 a généralement une sensibilité bien plus faible pour la lumière bleue (B).

Spectral Response of APDS-9960 Color Sensor
Réponse spectrale du capteur de couleur APDS-9960 (source)

Réagir aux interruptions avec l’APDS-9960

Pour finir, je vais vous montrer comment utiliser la broche d’interruption de l’APDS-9960. Pour cela, il faut connecter la sortie INT de l’APDS-9960 à une broche d’interruption de l’Arduino. Sur un Arduino Uno, seules les broches 2 et 3 sont prévues pour les interruptions. Pour les broches d’interruption des autres cartes microcontrôleurs, voir ici (link).

Sur le schéma de câblage ci-dessous, je connecte la sortie INT de l’APDS-9960 à la broche 3 de l’Arduino.

Connecting Interrupt Pin of APDS-9960 with Arduino
Connexion de la broche d’interruption de l’APDS-9960 à l’Arduino

Le code suivant déclenche un signal d’interruption si un objet s’approche du capteur, puis affiche la valeur de proximité.

#include "Adafruit_APDS9960.h"

Adafruit_APDS9960 sensor;
const int intPin = 3;

void setup() {
  Serial.begin(9600);
  if (!sensor.begin()) {
    Serial.println("failed to initialize device!");
  }
  sensor.enableProximity(true);
  sensor.setProximityInterruptThreshold(0, 100);
  sensor.enableProximityInterrupt();
  pinMode(intPin, INPUT_PULLUP);
}

void loop() {
  if (!digitalRead(intPin)) {
    Serial.println(sensor.readProximity());
    sensor.clearInterrupt();
  }
}

On commence le code en incluant la bibliothèque, en créant l’objet capteur et en définissant la broche d’interruption. Dans la fonction setup, on active la détection de proximité, on règle les seuils de proximité et on active l’interruption de proximité. Il faut aussi passer la broche d’interruption intPin en mode INPUT.

Dans la fonction loop, on interroge l’état de la broche intPin. Si son état passe à LOW, cela signifie qu’une interruption a été déclenchée, on lit alors la valeur de proximité et on l’affiche.

Les valeurs de proximité vont de 255 (plus proche) à 0 (plus éloigné). Comme on a fixé un seuil de proximité à 100, le code commence à afficher les valeurs de proximité si un objet s’approche à moins de 100, ce qui correspond à une distance d’environ 10 mm.

Faire varier l’intensité d’une LED en fonction de la proximité

Vous pouvez utiliser ce code pour contrôler la luminosité d’une LED selon la proximité d’un objet. Pour cela, ajoutez une LED à votre montage. Connectez la cathode (patte courte) de la LED au GND et l’anode (patte longue) via une résistance de 220Ω à la broche 11. Toute autre broche PWM fonctionnera aussi.

Connecting an LED with Arduino
Connexion d’une LED à l’Arduino

Ensuite, on étend un peu le code. On définit la ledPin et on la passe en mode OUTPUT dans la fonction setup. Dans la fonction loop, on lit la valeur de proximité prox, et comme c’est une valeur entre 0 et 255, on peut l’utiliser directement pour contrôler la luminosité de la LED en appelant analogWrite(ledPin, prox):

#include "Adafruit_APDS9960.h"

Adafruit_APDS9960 sensor;
const int intPin = 3;
const int ledPin = 11;

void setup() {
  Serial.begin(9600);
  if (!sensor.begin()) {
    Serial.println("failed to initialize device!");
  }
  sensor.enableProximity(true);
  sensor.setProximityInterruptThreshold(0, 0);
  sensor.enableProximityInterrupt();
  pinMode(intPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (!digitalRead(intPin)) {
    uint8_t prox = sensor.readProximity();
    analogWrite(ledPin, prox);
    sensor.clearInterrupt();
  } 
}

Le court extrait vidéo ci-dessous montre comment la luminosité de la LED varie selon la distance de la main par rapport au capteur :

Variation de la luminosité d’une LED avec l’APDS-9960 selon la proximité

Et voilà pour aujourd’hui ! J’espère que vous vous êtes amusé avec le capteur APDS-9960.

Conclusions

Dans ce tutoriel, vous avez appris à utiliser le capteur de gestes et de couleurs APDS-9960 avec un Arduino pour détecter des gestes et mesurer des valeurs de couleur et de luminosité.

Comparé au capteur de proximité APDS-9930, l’APDS-9960 peut détecter quatre gestes intégrés (haut, bas, gauche, droite) et possède un capteur de couleur RGB, alors que l’APDS-9930 n’a qu’un capteur de proximité et de lumière ambiante. Les deux capteurs sont spécialement conçus pour les applications mobiles (téléphones, tablettes) pour activer des fonctions (comme allumer haut-parleurs, micros, écrans) et contrôler la luminosité de l’écran.

Si vous avez besoin de plus de gestes, regardez du côté du PAJ7620U2, qui peut détecter jusqu’à 13 gestes, et son petit frère, le PAJ7620, peut en détecter 9.

La portée du capteur de proximité dans l’APDS-9930 et l’APDS-9960 est volontairement très limitée. Si vous voulez mesurer précisément des distances plus longues, par exemple pour la robotique, il vaut mieux utiliser des capteurs de distance infrarouge comme le GP2Y0A710K0F qui utilisent la triangulation pour déterminer la distance à un objet. Ou des capteurs de distance laser Time-of-Flight (ToF) comme le TOF10120 ou la bibliothèque VL53L1X.

Si vous avez des questions, n’hésitez pas à les poser dans les commentaires.

Bon bricolage ; )