If you need to add swipe, hover, or directional gesture control to an embedded project, the APDS-9960 is the definitive default pick for 95% of makers. It outputs digital I2C data, handles ambient light rejection, and provides raw proximity counts alongside processed directional vectors. If your project strictly requires complex multi-axis gestures (like clockwise circles or double-waves) without writing custom FIFO-parsing code, buy the PAJ7620U2 instead. This guide cuts through the datasheet noise to give you the exact wiring, output math, and interference mitigation needed to get reliable gesture detection on the bench.

How IR Gesture Sensing Actually Works

Infrared (IR) gesture sensors rely on active optical reflectance. The sensor emits a specific wavelength of IR light (typically 940nm) via an onboard LED, and an array of segmented photodiodes measures the amplitude of the light bouncing off a target (your hand) back into the sensor. By comparing the relative signal strength across four spatially separated photodiodes (Up, Down, Left, Right), the sensor's internal logic detects the directional movement of the reflected light over time.

Unlike basic passive infrared (PIR) motion sensors that only detect gross thermal changes, these active IR sensors measure precise spatial deltas. The internal state machine samples the photodiode array at high frequency (often 10ms intervals), calculates the slope of the signal change across the axes, and pushes a directional vector into a hardware FIFO buffer when the slope crosses a configured threshold.

The Sensor Decision Matrix: Which Chip to Buy

Do not waste time trying to force a Time-of-Flight (ToF) sensor to do lateral swipes, or a basic proximity sensor to do circles. Use this decision path to select the exact part number for your BOM.

If your project requires... And your constraint is... Then select this Part Number
Basic 4-way swipes (Up/Down/Left/Right) + hover distance + RGB color sensing You want the industry standard with broad Arduino/ESP32 library support APDS-9960 (Default Pick)
9 complex gestures (circles, waves, forward/back) natively recognized You do not want to write custom state-machine code to parse raw FIFO data PAJ7620U2 (Pixart)
Exact Z-axis hover distance in millimeters (e.g., for a theremin or dial) You don't care about lateral X/Y swipes and need high precision VL53L1X (ToF, not a true gesture sensor)
Bench Verdict: For general UI navigation (swiping through menus, pausing media), stick to the APDS-9960. The PAJ7620U2 is excellent for niche kiosk interfaces but suffers from a smaller active sensing cone and higher quiescent current draw.

Wiring, Pinout, and Power Requirements

A common trap with cheap APDS-9960 breakout boards from overseas marketplaces is the missing or mislabeled voltage regulator. The bare APDS-9960 IC is strictly a 3.3V device. Feeding 5V directly into the VCC pin of a bare chip will instantly fry the I2C pull-ups and the IR LED driver.

APDS-9960 Breakout Wiring Reference
Breakout Pin IC Function ESP32 / Arduino Connection Notes & Pull-up Requirements
VIN / VCC Power Supply 3.3V (or 5V only if LDO is confirmed on board) Supply range: 2.4V to 3.8V at the IC level. Max 5V on regulated breakouts.
GND Ground GND Keep ground loops short; high IR LED current causes ground bounce.
SDA I2C Data GPIO 21 (ESP32) / A4 (Uno) Requires 4.7kΩ pull-up to logic VCC (3.3V).
SCL I2C Clock GPIO 22 (ESP32) / A5 (Uno) Requires 4.7kΩ pull-up to logic VCC (3.3V).
INT Interrupt Output Any GPIO capable of hardware interrupts Active LOW. Requires 10kΩ pull-up to 3.3V. Do not leave floating.

Output Signal Math: Raw Counts to Directional Vectors

It is critical to understand that the APDS-9960 does not output an analog voltage proportional to hand position. It is a purely digital I2C device. When you read the sensor, you are pulling digital bytes from internal registers. We must separate the proximity output from the gesture output.

1. Proximity Output (Raw to Distance)

The proximity engine outputs an 8-bit unsigned integer ($P_{raw}$) ranging from 0 to 255. This is an ADC count representing reflected IR amplitude. Because light follows an inverse-square law, the relationship between $P_{raw}$ and physical distance ($d$) is non-linear. The working approximation for a standard 18% gray card target is:

$$d \approx \frac{k}{\sqrt{P_{raw} - P_{offset}}}$$

Where $P_{offset}$ is the dark-current calibration value (typically 10-15 counts with no target), and $k$ is a scaling constant derived empirically (often around 45 for the default 100mA LED drive). If your raw reading is 100, and offset is 10, the distance is roughly $45 / \sqrt{90} \approx 4.7$ cm.

2. Gesture Output (FIFO to Directional Vector)

When the gesture engine is enabled, it stops outputting simple proximity bytes and instead fills a 32-byte FIFO buffer with 4-byte packets (Up, Down, Left, Right counts). The physical unit here is a directional state enum, not a distance. The internal state machine calculates the delta over time ($\Delta P / \Delta t$). If the Up-diode slope exceeds the Down-diode slope by the configured threshold, the chip pushes a DIR_UP (0x01) byte to the GESTURE_FIFO register. You are reading a processed vector, not a raw spatial coordinate.

Calibration, Scaling, and Interference Rejection

Out-of-the-box, gesture sensors are notoriously twitchy. You must calibrate three parameters and mitigate two major interference sources to achieve reliable operation.

The Calibration Trinity

  1. Gesture Gain (GGAIN): Controls the sensitivity of the photodiode array. Default is often 4x. If your sensor triggers from 15cm away but misses close swipes, drop the gain to 1x to prevent ADC saturation.
  2. LED Drive Strength (LDRIVE): Dictates the current to the IR LED (ranging from 100mA down to 12.5mA). High drive gives a wider sensing cone but causes internal optical crosstalk if the plastic housing is poorly molded. Drop to 50mA for near-field (2-5cm) swipes.
  3. Gesture Wait Time (GWTIME): The idle time between FIFO samples. Lowering this from the default 20ms to 10ms increases the sampling rate, allowing the chip to track faster hand movements without aliasing.

Common Interference Sources

Sunlight Saturation: Direct sunlight contains massive amounts of 940nm IR radiation. While the APDS-9960 features an optical bandpass filter and ambient light rejection (ALS) algorithm, pointing the sensor toward a sunlit window will saturate the photodiodes, pegging the raw counts at 255 and blinding the gesture engine. Fix: Add a physical 3D-printed hood or light pipe to restrict the field of view.

60Hz/50Hz Mains Flicker: Incandescent and some poorly driven LED room lights flicker at twice the mains frequency (120Hz/100Hz). If your gesture wait time aligns with this flicker, you will see periodic noise in the FIFO data. Fix: Ensure your integration time is a multiple of the mains period (e.g., 8.3ms for 60Hz regions).

Pro-Tip for ESP32 Builders: Never poll the gesture FIFO over I2C in your main loop(). Polling at 100Hz will consume enough I2C bus time to starve your WiFi stack, causing MQTT disconnects or web server timeouts. Always wire the INT pin and use a hardware interrupt to read the FIFO only when a gesture is actually detected.

Step-by-Step: Getting Reliable Swipes on the ESP32

Follow this sequence to interface the APDS-9960 with an ESP32 DevKit v1, ensuring you bypass the common library pitfalls.

  1. Verify I2C Pull-ups: Use your multimeter in continuity mode. Check the resistance between SDA and 3.3V, and SCL and 3.3V. You should read ~4.7kΩ. If you read infinite resistance, your breakout board lacks pull-ups, and you must solder 4.7kΩ resistors to the I2C lines.
  2. Scan the Bus: Upload a basic I2C scanner sketch. The APDS-9960 hardcodes to address 0x39. If it doesn't appear, check your wiring and ensure you aren't using a 5V logic ESP32 variant without a level shifter.
  3. Install the Correct Library: Use the SparkFun APDS9960 RGB and Gesture Sensor library via the Arduino Library Manager. Avoid generic forks; the SparkFun version correctly handles the FIFO buffer clearing.
  4. Configure Interrupts: In your setup function, configure the INT pin.
    pinMode(INT_PIN, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(INT_PIN), isr, FALLING);
  5. Tune the Gain for your Environment: Call apds.setGestureGain(1) (1x gain) if you are mounting the sensor behind a dark acrylic bezel, or apds.setGestureGain(2) (2x gain) for open-air mounting at a distance of 5-10cm.
  6. Read and Clear the FIFO: In your interrupt service routine (ISR), simply set a volatile boolean flag gesture_detected = true;. In your main loop, check this flag, call apds.readGesture() to pull the directional enum from the FIFO, and immediately process it. The library automatically clears the FIFO upon reading, resetting the INT pin.

By treating the sensor as a digital state-machine rather than an analog proximity probe, and by respecting the I2C bus limitations of the ESP32, you will achieve robust, lag-free gesture control suitable for production-grade DIY interfaces.

Sources consulted for I2C timing and register maps: SparkFun APDS-9960 Hookup Guide, Adafruit APDS9960 Breakout Documentation, and the Seeed Studio Grove Gesture (PAJ7620U2) Wiki.