#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <MPU6050.h>
// OLED Display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// MPU6050
MPU6050 mpu;
// Pin definitions - CORRECTED for your Wokwi circuit
// Physical layout: [LDR5] [LDR2] [LDR1] [LDR3] [LDR4]
const int LDR_PINS[5] = {D0, D1, D2, D3, D10}; // LDR5, LDR2, LDR1, LDR3, LDR4
const int BUTTON_1 = D8; // Green button
const int BUTTON_2 = D9; // Red button
// Sensor data
int ldrValues[5];
int16_t ax, ay, az;
int16_t gx, gy, gz;
// Gesture recognition
#define MAX_GESTURES 10
struct GesturePattern {
String word;
int ldrThresholds[5][2]; // min, max for each LDR
int motionThresholds[3][2]; // min, max for ax, ay, az
bool useMotion;
};
// Dictionary of gestures - CUSTOMIZED FOR YOUR LAYOUT
GesturePattern dictionary[MAX_GESTURES] = {
// HELLO: All medium light + device tilted UP (screen facing sky)
{
"HELLO",
{{800, 3000}, {800, 3000}, {800, 3000}, {800, 3000}, {800, 3000}},
{{-4000, 4000}, {-4000, 4000}, {12000, 20000}}, // Tilted up
true
},
// YES: Center dark (cover middle LDRs) + tilted down
{
"YES",
{{1000, 4095}, // LDR5: bright
{0, 800}, // LDR2: dark
{0, 800}, // LDR1: dark
{0, 800}, // LDR3: dark
{1000, 4095}}, // LDR4: bright
{{-3000, 3000}, {-3000, 3000}, {-20000, -10000}}, // Tilted down
true
},
// NO: Edges dark + tilted left/right
{
"NO",
{{0, 800}, // LDR5: dark
{1000, 4095}, // LDR2: bright
{1000, 4095}, // LDR1: bright
{1000, 4095}, // LDR3: bright
{0, 800}}, // LDR4: dark
{{-20000, 20000}, {-3000, 3000}, {-3000, 3000}}, // Rotated
true
},
// LIGHT: All sensors detect bright light
{
"LIGHT",
{{2800, 4095}, {2800, 4095}, {2800, 4095}, {2800, 4095}, {2800, 4095}},
{{-5000, 5000}, {-5000, 5000}, {-5000, 5000}},
false // No motion needed
},
// DARK: All sensors covered/dark
{
"DARK",
{{0, 600}, {0, 600}, {0, 600}, {0, 600}, {0, 600}},
{{-5000, 5000}, {-5000, 5000}, {-5000, 5000}},
false
},
// WAVE: Progressive light pattern (left to right)
{
"WAVE",
{{0, 800}, // LDR5: darkest
{800, 1600}, // LDR2
{1600, 2400}, // LDR1: center
{2400, 3200}, // LDR3
{3200, 4095}}, // LDR4: brightest
{{-5000, 5000}, {-5000, 5000}, {-5000, 5000}},
false
},
// UP: Device tilted strongly upward
{
"UP",
{{0, 4095}, {0, 4095}, {0, 4095}, {0, 4095}, {0, 4095}}, // Any light
{{-4000, 4000}, {-4000, 4000}, {14000, 20000}}, // Strong tilt up
true
},
// DOWN: Device tilted strongly downward
{
"DOWN",
{{0, 4095}, {0, 4095}, {0, 4095}, {0, 4095}, {0, 4095}},
{{-4000, 4000}, {-4000, 4000}, {-20000, -14000}}, // Strong tilt down
true
}
};
int activeDictionarySize = 8; // Number of active gestures
// Timing for gesture display
unsigned long lastMatchTime = 0;
String lastMatchedWord = "";
void setup() {
Serial.begin(115200);
delay(1000);
// Initialize I2C
Wire.begin(D4, D5); // SDA, SCL
// Initialize OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("Gesture System"));
display.println(F("Initializing..."));
display.display();
delay(2000);
// Initialize MPU6050
mpu.initialize();
if (!mpu.testConnection()) {
Serial.println(F("MPU6050 connection failed"));
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("MPU6050 ERROR!"));
display.display();
for(;;);
}
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
// Initialize LDR pins
for (int i = 0; i < 5; i++) {
pinMode(LDR_PINS[i], INPUT);
}
// Initialize buttons - ACTIVE HIGH with internal pull-down
pinMode(BUTTON_1, INPUT_PULLDOWN);
pinMode(BUTTON_2, INPUT_PULLDOWN);
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("Ready!"));
display.println(F(""));
display.println(F("Green: Info"));
display.println(F("Red: Reset"));
display.println(F(""));
display.print(F("Gestures: "));
display.println(activeDictionarySize);
display.display();
delay(2000);
Serial.println("\n=================================");
Serial.println("GESTURE RECOGNITION SYSTEM READY");
Serial.println("=================================");
Serial.println("Physical LDR Layout:");
Serial.println("[LDR5] [LDR2] [LDR1] [LDR3] [LDR4]");
Serial.println(" D0 D1 D2 D3 D10");
Serial.println("\nAvailable Gestures:");
for (int i = 0; i < activeDictionarySize; i++) {
Serial.print("- ");
Serial.println(dictionary[i].word);
}
Serial.println("=================================\n");
}
void loop() {
// Check buttons
if (digitalRead(BUTTON_1) == HIGH) {
showInfo();
delay(300); // Debounce
}
if (digitalRead(BUTTON_2) == HIGH) {
resetDisplay();
delay(300); // Debounce
}
// Read sensors
readSensors();
// Check for gesture match
String matchedWord = matchGesture();
// Display result
if (matchedWord != "") {
displayWord(matchedWord);
lastMatchTime = millis();
lastMatchedWord = matchedWord;
delay(1500); // Show word for 1.5 seconds
} else {
// Show sensor data if no recent match
if (millis() - lastMatchTime > 3000) {
displaySensorData();
}
}
delay(150); // Update rate
}
void readSensors() {
// Read LDR values
for (int i = 0; i < 5; i++) {
ldrValues[i] = analogRead(LDR_PINS[i]);
}
// Read MPU6050
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
// Debug output
Serial.print("LDR: ");
for (int i = 0; i < 5; i++) {
Serial.print(ldrValues[i]);
Serial.print(" ");
}
Serial.print(" | Motion: AX=");
Serial.print(ax);
Serial.print(" AY=");
Serial.print(ay);
Serial.print(" AZ=");
Serial.println(az);
}
String matchGesture() {
for (int i = 0; i < activeDictionarySize; i++) {
bool ldrMatch = true;
bool motionMatch = true;
// Check LDR thresholds
for (int j = 0; j < 5; j++) {
if (ldrValues[j] < dictionary[i].ldrThresholds[j][0] ||
ldrValues[j] > dictionary[i].ldrThresholds[j][1]) {
ldrMatch = false;
break;
}
}
// Check motion thresholds if required
if (dictionary[i].useMotion) {
if (ax < dictionary[i].motionThresholds[0][0] || ax > dictionary[i].motionThresholds[0][1] ||
ay < dictionary[i].motionThresholds[1][0] || ay > dictionary[i].motionThresholds[1][1] ||
az < dictionary[i].motionThresholds[2][0] || az > dictionary[i].motionThresholds[2][1]) {
motionMatch = false;
}
}
// If both match, return the word
if (ldrMatch && motionMatch) {
Serial.print(">>> MATCH: ");
Serial.println(dictionary[i].word);
return dictionary[i].word;
}
}
return ""; // No match
}
void displayWord(String word) {
display.clearDisplay();
display.setTextSize(3);
display.setTextColor(SSD1306_WHITE);
// Center the word
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(word, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w) / 2, (SCREEN_HEIGHT - h) / 2);
display.println(word);
// Add small indicator
display.setTextSize(1);
display.setCursor(0, SCREEN_HEIGHT - 10);
display.print(F("Detected!"));
display.display();
}
void displaySensorData() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
// Header
display.println(F("Sensor Monitor"));
display.println(F("-------------"));
// LDR values - show physical layout
display.println(F("LDR (D0-D1-D2-D3-D10):"));
for (int i = 0; i < 5; i++) {
display.print(ldrValues[i] / 10); // Scale for display
if (i < 4) display.print("-");
}
display.println();
// Motion data
display.print(F("Motion: "));
display.print(ax / 1000);
display.print(F(","));
display.print(ay / 1000);
display.print(F(","));
display.println(az / 1000);
display.println();
display.println(F("Perform gesture..."));
display.display();
}
void showInfo() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("Gesture System"));
display.println(F("-------------"));
display.print(F("Gestures: "));
display.println(activeDictionarySize);
display.println();
// Show first 5 gestures
for (int i = 0; i < min(5, activeDictionarySize); i++) {
display.print(F("- "));
display.println(dictionary[i].word);
}
if (activeDictionarySize > 5) {
display.print(F("+ "));
display.print(activeDictionarySize - 5);
display.println(F(" more..."));
}
display.display();
delay(3000);
}
void resetDisplay() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(20, 20);
display.println(F("RESET"));
display.display();
lastMatchTime = 0;
lastMatchedWord = "";
delay(1000);
}