Back to Tutorial

ESP32 with APDS-9960 Gesture Sensor


The APDS-9960 is an advanced, compact sensor from Broadcom (formerly Avago Technologies) that offers multiple sensing capabilities in one chip. It is widely used in gesture recognition, proximity sensing, ambient light detection, and color sensing, making it highly useful for smart devices and human-machine interfaces (HMIs).


🔍 Key Features of APDS-9960

FeatureDescription
Gesture DetectionRecognizes hand gestures (up, down, left, right, near, far).
Proximity SensingDetects how close an object is to the sensor (up to ~10 cm).
Ambient Light SensingMeasures surrounding light intensity (lux value).
Color SensingDetects Red, Green, Blue, and Clear light levels.
Digital I²C InterfaceCommunicates via I²C protocol, making it easy to interface with microcontrollers.
Compact SizeTiny module suitable for portable and embedded applications.

📦 Built-in Components

  • IR LED (Infrared emitter)
  • Photodiodes for R, G, B, Clear
  • Gesture engine
  • ALS (Ambient Light Sensor)
  • Proximity sensor

📐 Technical Specifications

ParameterValue
Voltage Range2.4V – 3.6V
I²C Address0x39 (7-bit)
Gesture Detection Range~10 to 20 cm
Proximity Detection Range~1 to 10 cm
Ambient Light Range0 – 10,000 lux
Operating Temperature-40°C to +85°C

🔌 Pin Configuration

PinDescription
VIN3.3V power supply
GNDGround
SCLI²C clock (connect to SCL of MCU)
SDAI²C data (connect to SDA of MCU)
INTInterrupt output (optional)

🤖 Applications

  • Gesture-based control (swipe to change songs, etc.)
  • Smartphones (auto-brightness, face detection)
  • Laptops/tablets (gesture navigation)
  • Smart appliances (touchless control)
  • Interactive displays and kiosks

🧠 How Gesture Sensing Works

  1. The IR LED emits light.
  2. Four directional photodiodes (up, down, left, right) measure reflected IR light from a moving hand.
  3. The internal gesture engine compares the light intensity across these directions to detect:
    • UP / DOWN
    • LEFT / RIGHT
    • NEAR / FAR
    • 📋 Tips for Better Performance
      • Use dark background behind the sensor to reduce IR reflection.
      • Ensure adequate lighting (not direct sunlight).
      • Place sensor in open space, not recessed.
      • Gesture speed should be moderate (not too fast or slow).
      📦 Available Libraries
      • SparkFun APDS-9960 Library (recommended)
      • Adafruit_APDS9960
      • PlatformIO and Arduino IDE compatible

               HOW TO OPERATE

/***************************************************************************

  This is a library for the APDS9960 digital proximity, ambient light, RGB, and gesture sensor

  This sketch puts the sensor in gesture mode and decodes gestures.

  To use this, first put your hand close to the sensor to enable gesture mode.

  Then move your hand about 6″ from the sensor in the up -> down, down -> up,

  left -> right, or right -> left direction.

  Designed specifically to work with the Adafruit APDS9960 breakout

  —-> http://www.adafruit.com/products/3595

  These sensors use I2C to communicate. The device’s I2C address is 0x39

  Adafruit invests time and resources providing this open source code,

  please support Adafruit andopen-source hardware by purchasing products

  from Adafruit!

  Written by Dean Miller for Adafruit Industries.

  BSD license, all text above must be included in any redistribution

 ***************************************************************************/

#include "Adafruit_APDS9960.h"
Adafruit_APDS9960 apds;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(115200);
 
  if(!apds.begin()){
    Serial.println("failed to initialize device! Please check your wiring.");
  }
  else Serial.println("Device initialized!");

  //gesture mode will be entered once proximity mode senses something close
  apds.enableProximity(true);
  apds.enableGesture(true);
}

// the loop function runs over and over again forever
void loop() {
  //read a gesture from the device
    uint8_t gesture = apds.readGesture();
    if(gesture == APDS9960_DOWN) Serial.println("v");
    if(gesture == APDS9960_UP) Serial.println("^");
    if(gesture == APDS9960_LEFT) Serial.println("<");
    if(gesture == APDS9960_RIGHT) Serial.println(">");
}
                   HOW TO OPERATE WITH SSD1306(OLED DISPLAY)

// UP → Green

// DOWN → Red

// RIGHT → Blue

// LEFT → Yellow

#include <Adafruit_GFX.h>              // Core graphics library for OLED
#include <Adafruit_SSD1306.h>          // OLED display library
#include <Wire.h>                      // I2C communication
#include "Adafruit_APDS9960.h"         // Gesture sensor library
#include <Adafruit_NeoPixel.h>         // NeoPixel (RGB LED strip) library

// Define NeoPixel settings
#define PIN_NEO_PIXEL 15               // GPIO pin connected to NeoPixel
#define NUM_PIXELS 10                  // Number of NeoPixels

// Define OLED screen settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1                 // Reset pin not used with this OLED

// Create objects for OLED, gesture sensor, and NeoPixel
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_APDS9960 apds;
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);               // Initialize serial monitor for debugging
  NeoPixel.begin();                   // Initialize NeoPixel strip

  // Initialize the APDS9960 gesture sensor
  if (!apds.begin()) {
    Serial.println("Failed to initialize device! Please check your wiring.");
  } else {
    Serial.println("Device initialized!");
  }

  apds.enableProximity(true);         // Enable proximity detection
  apds.enableGesture(true);           // Enable gesture detection

  // Initialize the OLED display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // I2C address is usually 0x3C
  display.clearDisplay();             // Clear display buffer
  display.display();                  // Push the cleared screen to the display
  delay(1000);                        // Wait 1 second for display to stabilize
}

void loop() {
  // Read any gesture detected
  uint8_t gesture = apds.readGesture();

  // Handle UP gesture
  if (gesture == APDS9960_UP) {
    Serial.println("^");             // Print gesture to serial monitor
    display.clearDisplay();          // Clear previous content on OLED
    drawUpArrow();                   // Draw UP arrow on OLED
    display.display();               // Display the arrow

    // Light NeoPixels green one by one
    for (int pixel = 0; pixel < NUM_PIXELS; pixel++) {          
      NeoPixel.setPixelColor(pixel, NeoPixel.Color(0, 255, 0)); // Green
      NeoPixel.show();
      delay(500);                    // Delay between lighting each LED
    }

    // Clear all LEDs after animation
    NeoPixel.clear();
    NeoPixel.show();
  }

  // Handle DOWN gesture
  if (gesture == APDS9960_DOWN) {
    Serial.println("v");
    display.clearDisplay();
    drawDownArrow();
    display.display();

    // Light NeoPixels red one by one
    for (int pixel = 0; pixel < NUM_PIXELS; pixel++) {
      NeoPixel.setPixelColor(pixel, NeoPixel.Color(255, 0, 0)); // Red
      NeoPixel.show();
      delay(500);
    }

    NeoPixel.clear();
    NeoPixel.show();
  }

  // Handle RIGHT gesture
  if (gesture == APDS9960_RIGHT) {
    Serial.println(">");
    display.clearDisplay();
    drawRightArrow();
    display.display();

    // Light NeoPixels blue one by one
    for (int pixel = 0; pixel < NUM_PIXELS; pixel++) {
      NeoPixel.setPixelColor(pixel, NeoPixel.Color(0, 0, 255)); // Blue
      NeoPixel.show();
      delay(500);
    }

    NeoPixel.clear();
    NeoPixel.show();
  }

  // Handle LEFT gesture
  if (gesture == APDS9960_LEFT) {
    Serial.println("<");
    display.clearDisplay();
    drawLeftArrow();
    display.display();

    // Light NeoPixels yellow one by one (red + green)
    for (int pixel = 0; pixel < NUM_PIXELS; pixel++) {
      NeoPixel.setPixelColor(pixel, NeoPixel.Color(255, 255, 0)); // Yellow
      NeoPixel.show();
      delay(500);
    }

    NeoPixel.clear();
    NeoPixel.show();
  }
}

// Function to draw an UP arrow on OLED
void drawUpArrow() {
  display.fillTriangle(64, 10, 44, 40, 84, 40, SSD1306_WHITE); // Triangle pointing up
}

// Function to draw a DOWN arrow on OLED
void drawDownArrow() {
  display.fillTriangle(64, 54, 44, 24, 84, 24, SSD1306_WHITE); // Triangle pointing down
}

// Function to draw a RIGHT arrow on OLED
void drawRightArrow() {
  display.fillTriangle(100, 32, 70, 12, 70, 52, SSD1306_WHITE); // Triangle pointing right
}

// Function to draw a LEFT arrow on OLED
void drawLeftArrow() {
  display.fillTriangle(28, 32, 58, 12, 58, 52, SSD1306_WHITE); // Triangle pointing left
}
iotwebplanet.com - 1

Share this post

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to Tutorial