Cerradura por Gestos Sin Contacto: Acceso Seguro con APDS-9960 y Arduino
Componentes y materiales
| Sensor SparkFun APDS-9960 (gestos, proximidad, RGB) | 1 |
| Arduino UNO | 1 |
| LED RGB difuso (cátodo común) | 1 |
| Pantalla LCD 16x2 (blanco sobre azul, Adafruit) | 1 |
| Resistencia 4,75 kΩ | 2 |
| Cables jumper | 1 set |
| Resistencia 1 kΩ | 1 |
Software
- Arduino IDE
- Librería
SparkFun_APDS9960(instalar desde Gestor de librerías) - Librería
Wire(incluida) - Librería
LiquidCrystal(incluida) - Librería
Servo(incluida)
Sobre el proyecto
Nota: El APDS-9960 no funciona con Arduino Nano ni Mega 2560 (según pruebas del autor).
Base para una cerradura controlada por gestos. Usa un sensor APDS-9960 para detectar movimientos (arriba, abajo, izquierda, derecha) y compara con una contraseña gestual predefinida. Si coincide, acciona un servomotor que abre el cerrojo. Incluye LCD para retroalimentación visual y LEDs RGB para estado.
Montaje
Conexiones clave
- APDS-9960 solo admite 3,3 V. En Arduino UNO (5 V) se requiere adaptación de nivel I2C:
- SDA (pin A4) y SCL (pin A5) → cada uno a una resistencia 4,7 kΩ → 3,3 V (pull-up).
- VCC → 3,3 V del Arduino; GND → GND.
- INT → pin 2 (interrupción).
- LCD: pines 12, 11, 6, 5, 4, 3 (RS, E, D4-D7). Contraste: potenciómetro 10k o resistencia 1k a GND.
- LED RGB: Rojo → A1, Verde → A2 (PWM), común a GND con resistencias 220 Ω.
- Servo: pin 9 (señal), VCC/GND a 5 V/GND.
- Alimentación: batería 9 V con conector jack DC.
Caja
Caja de cartón con orificios para componentes. Opcional: soldar en placa perforada para mayor robustez.
Código principal
#include <Wire.h>
#include <SparkFun_APDS9960.h>
#include <LiquidCrystal.h>
#include <Servo.h>
#define PINSIZE 6
#define SERVOPIN 9
#define APDS9960_INT 2
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
Servo servo;
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint8_t proximity_data = 0;
int red_led = A1, green_led = A2;
int pageNum = 0;
String secret[PINSIZE] = {"UP","DOWN","UP","UP","RIGHT","LEFT"}; // Contraseña (mayúsculas)
String currentGesture = "";
int numRight = 0;
volatile int isr_flag = 0;
void setup() {
pinMode(APDS9960_INT, INPUT);
lcd.begin(16, 2);
servo.attach(SERVOPIN); servo.write(0); servo.detach();
Serial.begin(9600);
Serial.print("Password length: "); Serial.println(PINSIZE);
attachInterrupt(0, interruptRoutine, FALLING);
if (apds.init()) Serial.println("APDS-9960 init OK");
else Serial.println("APDS-9960 init FAIL");
if (!apds.setProximityGain(PGAIN_1X)) Serial.println("PGAIN fail");
if (apds.enableProximitySensor(false)) Serial.println("Proximity ON");
else Serial.println("Proximity FAIL");
if (apds.enableGestureSensor(true)) Serial.println("Gesture ON");
else Serial.println("Gesture FAIL");
}
void loop() {
// Página 0: espera proximidad (~3 pulgadas)
if (pageNum == 0) {
if (apds.readProximity(proximity_data)) {
if (proximity_data >= 40) { pageNum = 1; delay(2000); }
}
}
switch (pageNum) {
case 0:
LCDClear(); lcd.print("Locked- get"); lcd.setCursor(0,1); lcd.print("3 inches away."); blinkRed(); break;
case 1: // Introducir código
numRight = 0;
lcd.print("Enter code...");
for (int x = 0; x < PINSIZE; x++) {
while (!apds.isGestureAvailable()) {}
if (isr_flag == 1) {
detachInterrupt(0);
handleGesture();
isr_flag = 0;
attachInterrupt(0, interruptRoutine, FALLING);
if (currentGesture != "NONE") {
if (currentGesture == secret[x]) {
LCDClear(); lcd.print("Next"); numRight++;
analogWrite(green_led, 255); delay(1000); allOff();
} else {
LCDClear(); lcd.print("Wrong, return to"); lcd.setCursor(0,1); lcd.print("main page.");
analogWrite(red_led, 255); delay(1000); allOff();
pageNum = 0; break;
}
if (numRight == PINSIZE) { pageNum = 2; break; }
} else { LCDClear(); lcd.print("Not recognized:"); lcd.setCursor(0,1); lcd.print("Try again."); x--; }
}
}
break;
case 2: // Acceso concedido
LCDClear(); lcd.print("Enter now."); pageNum = 0;
servo.attach(SERVOPIN); servo.write(90); enter(); delay(1000); servo.write(0);
break;
}
}
void interruptRoutine() { isr_flag = 1; }
void handleGesture() {
if (apds.isGestureAvailable()) {
switch (apds.readGesture()) {
case DIR_UP: currentGesture = "UP"; break;
case DIR_DOWN: currentGesture = "DOWN"; break;
case DIR_LEFT: currentGesture = "LEFT"; break;
case DIR_RIGHT: currentGesture = "RIGHT"; break;
case DIR_NEAR: currentGesture = "NEAR"; break;
case DIR_FAR: currentGesture = "FAR"; break;
default: currentGesture = "NONE";
}
Serial.println(currentGesture);
LCDClear(); lcd.print(currentGesture);
}
}
void allOff() { analogWrite(red_led, 0); analogWrite(green_led, 0); }
void blinkRed() { analogWrite(red_led, 255); delay(250); allOff(); delay(250); }
void LCDClear() { lcd.clear(); lcd.setCursor(0, 0); }
void enter() {
for (int x = 0; x < 30; x++) { analogWrite(green_led, 255); delay(100); allOff(); delay(100); }
for (int x = 9; x > 0; x--) {
LCDClear(); lcd.print("Closing in: "); lcd.setCursor(0,1); lcd.print(x); lcd.print(" seconds..."); delay(1000);
}
LCDClear(); lcd.print("Closing");
}
Esquemático
Ver diagrama en sección "Schematics" del proyecto original (conexiones I2C con pull-ups 4,7k a 3,3V, LCD, servo, LEDs).
Personalización
- Cambia
secret[]para tu contraseña gestual (máx. 6 gestos: UP, DOWN, LEFT, RIGHT). - Ajusta
PINSIZEsegún longitud. - Sustituye el servo por cualquier mecanismo de cierre (cerrojo electromagnético, pestillo, etc.).
Proceso de manufactura
- La evolución y fabricación de cerraduras modernas de cilindro de pines
- Cerradura de combinación: Diseño, fabricación y evolución histórica
- Alerta de Sed Inteligente para Plantas: Sensor DIY para Riego Óptimo
- Reloj de Palabras en Italiano con Arduino Nano, NeoPixel, LCD y RTC
- Ahorra Pines en Arduino: Conecta Teclado 4x3 con Solo 3 Conexiones Analógicas
- Medidor kWh Sigfox Fiable con Arduino MKR Fox 1200
- Monitor de temperatura con Bluetooth usando Arduino Nano
- Kit Compañero Arduino Nano: Componentes y Herramientas Esenciales para Electrónica DIY
- Kit Adaptador USB MIDI para Arduino Micro / Leonardo: Lista Completa de Componentes
- Circuito de entrada analógica aislada para Arduino
- Test de Precisión de Tiempo de Reacción con Arduino UNO