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
| Feature | Description |
|---|---|
| Gesture Detection | Recognizes hand gestures (up, down, left, right, near, far). |
| Proximity Sensing | Detects how close an object is to the sensor (up to ~10 cm). |
| Ambient Light Sensing | Measures surrounding light intensity (lux value). |
| Color Sensing | Detects Red, Green, Blue, and Clear light levels. |
| Digital I²C Interface | Communicates via I²C protocol, making it easy to interface with microcontrollers. |
| Compact Size | Tiny 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
| Parameter | Value |
|---|---|
| Voltage Range | 2.4V – 3.6V |
| I²C Address | 0x39 (7-bit) |
| Gesture Detection Range | ~10 to 20 cm |
| Proximity Detection Range | ~1 to 10 cm |
| Ambient Light Range | 0 – 10,000 lux |
| Operating Temperature | -40°C to +85°C |
🔌 Pin Configuration
| Pin | Description |
|---|---|
| VIN | 3.3V power supply |
| GND | Ground |
| SCL | I²C clock (connect to SCL of MCU) |
| SDA | I²C data (connect to SDA of MCU) |
| INT | Interrupt 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
- The IR LED emits light.
- Four directional photodiodes (up, down, left, right) measure reflected IR light from a moving hand.
- 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).
- 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
}

Leave a Reply
You must be logged in to post a comment.