Atom Yang
Published © GPL3+

Wave Your Hand to Light Up Your World! A XIAO Gesture Light

Control LED modes with a wave! A compact, fun, hands-free lighting setup for desks, TVs, or shelves, blending function and style!

BeginnerFull instructions provided1 hour48

Things used in this project

Hardware components

LED Driver Board for Seeed Studio XIAO
LED Driver Board for Seeed Studio XIAO
×1
Grove Smart IR Gesture Sensor
Seeed Studio Grove Smart IR Gesture Sensor
×1
XIAO ESP32C3
Seeed Studio XIAO ESP32C3
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Seeed Studio Grove - Universal 4 Pin Buckled 5cm Cable (5 PCs Pack)

Story

Read more

Schematics

Overall Connection Diagram

Schematics

Code

Ges_LED

C/C++
// Gesture -> LED example for XIAO ESP32-C3 + Grove PAJ7660 + LED Driver Board
// Dependencies: Adafruit_NeoPixel, Grove_Gesture (Seeed)
// If you want to use FastLED instead, please replace the relevant functions yourself.

#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include "Gesture.h"    // Seeed Grove Gesture library


#define LED_PIN    A0     // Pin expected by the XIAO D5 / LED Driver board (as in the driver board example)
#define NUMPIXELS  300    // Adjust according to your LED strip

Adafruit_NeoPixel strip(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

// Gesture object (library type)
pag7660 Gesture;

unsigned long lastGestureTime = 0;
const unsigned long gestureDebounce = 300; // ms for debouncing
bool ledsOn = true;
uint8_t brightnessVal = 80; // 0-255
uint16_t currentHue = 0;    // Used for rotation/rainbow effects

// Simple color helper
uint32_t wheel(byte h) {
  // h: 0-255 -> RGB wheel
  if (h < 85) return strip.Color(h * 3, 255 - h * 3, 0);
  if (h < 170) { h -= 85; return strip.Color(255 - h * 3, 0, h * 3); }
  h -= 170; return strip.Color(0, h * 3, 255 - h * 3);
}

void colorWipe(uint32_t c, uint8_t wait) {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
  }
  strip.show();
  if (wait) delay(wait);
}

void rainbowCycle(uint8_t wait) {
  for (int j = 0; j < 256; j++) {
    for (int i = 0; i < strip.numPixels(); i++) {
      uint32_t c = wheel(((i * 256 / strip.numPixels()) + j) & 255);
      strip.setPixelColor(i, c);
    }
    strip.show();
    delay(wait);
  }
}

void theaterChase(uint32_t c, uint8_t wait) {
  for (int a = 0; a < 10; a++) {
    for (int b = 0; b < 3; b++) {
      for (int i = 0; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i + b, c);
      }
      strip.show();
      delay(wait);
      for (int i = 0; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i + b, 0);
      }
    }
  }
}

void setColorByIndex(int n) {
  // 1-> red, 2->green, 3->blue, 4->purple, 5->yellow
  uint32_t colors[] = {0, strip.Color(255,0,0), strip.Color(0,255,0), strip.Color(0,0,255), strip.Color(150,0,150), strip.Color(255,200,0)};
  if (n >= 1 && n <=5) {
    colorWipe(colors[n], 20);
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);
  Serial.println("\nGesture -> LED Demo");

  // LED init
  strip.begin();
  strip.setBrightness(brightnessVal);
  strip.show(); // Turn off LEDs

  // Gesture init (I2C mode  make sure the DIP switch is set)
  if (Gesture.init()) {
    Serial.println("Gesture init OK");
  } else {
    Serial.println("Gesture init FAILED");
  }
}

void loop() {
  pag7660_gesture_t result;
  if (Gesture.getResult(result)) {
    unsigned long now = millis();
    if (now - lastGestureTime < gestureDebounce) {
      // Debounce
      return;
    }
    lastGestureTime = now;

    // Thumb detection (may be available in thumb mode or composite mode)
    if (result.thumb.up) {
      Serial.println("Thumb Up -> Increase brightness");
      brightnessVal = min(255, brightnessVal + 20);
      strip.setBrightness(brightnessVal);
      strip.show();
      return;
    } else if (result.thumb.down) {
      Serial.println("Thumb Down -> Decrease brightness");
      brightnessVal = max(0, (int)brightnessVal - 20);
      strip.setBrightness(brightnessVal);
      strip.show();
      return;
    }

    // cursor / tap / pinch / grab
    if (result.type == 0) {
      // cursor subtype
      if (result.cursor.type == 1 && result.cursor.select) { // Tap
        Serial.println("Tap -> Blink white");
        for (int i=0;i<3;i++) {
          colorWipe(strip.Color(255,255,255), 100);
          colorWipe(0, 100);
        }
        return;
      } else if (result.cursor.type == 2 && result.cursor.select) { // Grab
        Serial.println("Grab -> Theater chase");
        theaterChase(strip.Color(0,0,255), 50);
        return;
      } else if (result.cursor.type == 3 && result.cursor.select) { // Pinch
        Serial.println("Pinch -> Toggle On/Off");
        ledsOn = !ledsOn;
        if (!ledsOn) colorWipe(0,0);
        else colorWipe(wheel(currentHue & 255), 0);
        return;
      }
    }

    // Rotate
    if (result.type == 6) { // Rotate Right
      Serial.print("Rotate Right: ");
      Serial.println(result.rotate);
      currentHue += 16;
      colorWipe(wheel(currentHue & 255), 0);
      return;
    } else if (result.type == 7) { // Rotate Left
      Serial.print("Rotate Left: ");
      Serial.println(result.rotate);
      currentHue -= 16;
      colorWipe(wheel(currentHue & 255), 0);
      return;
    }

    // Swipe
    if (result.type == 8) { // Swipe Left
      Serial.println("Swipe Left -> RainbowCycle");
      rainbowCycle(5);
      return;
    } else if (result.type == 9) { // Swipe Right
      Serial.println("Swipe Right -> Theater chase green");
      theaterChase(strip.Color(0,255,0), 60);
      return;
    }

    // N-finger push types (19-23 -> 1~5 finger push)
    if (result.type >= 19 && result.type <= 23) {
      int n = result.type - 19 + 1;
      Serial.print("N-finger push: ");
      Serial.println(n);
      setColorByIndex(n);
      return;
    }

    // Static N-finger detection (1..5)
    if (result.type >= 1 && result.type <= 5) {
      Serial.print("Static finger count: ");
      Serial.println(result.type);
      // Map to a single color
      setColorByIndex(result.type);
      return;
    }

    // Other fallbacks
    Serial.print("Unknown gesture type: ");
    Serial.println(result.type);
  }

  // Main loop idle, or for a slight animation (if needed)
  delay(50);
}

Credits

Atom Yang
3 projects • 2 followers
A Product Manager.

Comments