FlickMote: Gestensteuerung per Ultraschall & IR für Smart Home (Arduino 101)
Komponenten
| Bauteil | Anzahl |
|---|---|
| Arduino 101 (oder UNO) | 1 |
| HC-SR04 Ultraschall-Entfernungsmesser | 1 |
| IR-Sende-LED (940 nm) | 1 |
| Widerstand 220 Ω (für IR-LED) | 1 |
| RGB-LED (Common Cathode) | 1 |
| Steckbrett & Kabel | 1 Set |
Software
- Arduino IDE
- Bibliothek:
IRremote(von shirriff / z3t0)
Funktionsprinzip
Der HC-SR04 misst die Distanz zur Hand. Aus Distanzänderungen (Swipes, Halten) werden Gesten erkannt und entsprechende IR-Codes (Sony-TV-Protokoll) gesendet. Eine RGB-LED gibt visuelles Feedback.
Gesten-Mapping
| Geste | Distanz | Aktion | IR-Code (Sony, 12 Bit) |
|---|---|---|---|
| Hand abdecken (< 3 cm / ~1,2″) | < 3 Zoll | Power Toggle (Ein/Aus) | 0xA90 |
| Swipe niedrig (3–10 Zoll / ~7–25 cm) | 3–10 Zoll | Channel Down | 0x890 |
| Swipe hoch (10–20 Zoll / ~25–50 cm) | 10–20 Zoll | Channel Up | 0x090 |
| Halten niedrig (3–10 Zoll) | 3–10 Zoll | Volume Down (wiederholend) | 0xC90 |
| Halten hoch (10–20 Zoll) | 10–20 Zoll | Volume Up (wiederholend) | 0x490 |
Power-Bestätigung: Erstes Abdecken → LED blinkt lila (Bestätigung). Zweites Abdecken innerhalb 5 s → IR-Code wird gesendet. Verhindert versehentliches Ausschalten.
Verdrahtung
- IR-LED Anode → Pin 3 (PWM, fest in IRremote lib) über 220 Ω → Kathode → GND.
- HC-SR04: VCC → 5 V, GND → GND, Trig → Pin 8, Echo → Pin 7.
- RGB-LED: Common Cathode → GND, R → Pin 11, G → Pin 10, B → Pin 9 (PWM-Pins).
Arduino-Code (Vollständig)
#include <IRremote.h>
#define CONTROL_CH 1
#define CONTROL_VOL 2
#define CONTROL_POW 3
#define CONTROL_UP 1
#define CONTROL_DOWN -1
#define DIST_MAX 20
#define DIST_DOWN 10
#define DIST_POW 3
const int irPin = 3; // fixed in library
const int pingPin = 8;
const int echoPin = 7;
const int led = 13;
const int ledR = 11, ledG = 10, ledB = 9;
unsigned long timer = 0;
IRsend irsend;
bool powerConfirmed = false;
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(ledR, OUTPUT);
pinMode(ledG, OUTPUT);
pinMode(ledB, OUTPUT);
pinMode(pingPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
long duration = doPing();
long inches = microsecondsToInches(duration);
// Timer-Reset nach 5 s
if (timer && millis() - timer > 5000) {
timer = 0;
Serial.println("timer reset");
}
digitalWrite(led, LOW);
setColor(0, 0, 0);
if (inches < DIST_MAX) {
Serial.print(inches); Serial.println("in");
if (inches < DIST_POW) { // Power-Geste
if (timer) {
doIR(CONTROL_POW, 0);
timer = 0;
delay(2000);
} else {
Serial.println("power flag set");
timer = millis();
setColor(255, 50, 50); // Lila
delay(500);
}
} else { // Channel oder Volume
int value = handleDist(inches);
delay(300);
long inches2 = microsecondsToInches(doPing());
if (inches2 > DIST_MAX) { // Swipe (kurz)
doIR(CONTROL_CH, value);
} else { // Hold → Volume
int d = 500;
while (inches2 < DIST_MAX) {
value = handleDist(inches2);
doIR(CONTROL_VOL, value);
delay(d);
inches2 = microsecondsToInches(doPing());
d = 100;
}
delay(500); // Verhindert Channel-Wechsel nach Volume
}
}
}
delay(50);
}
int handleDist(int inches) {
if (inches > DIST_DOWN) {
digitalWrite(led, HIGH);
return CONTROL_UP;
} else {
digitalWrite(led, LOW);
return CONTROL_DOWN;
}
}
void doIR(int control, int val) {
switch (control) {
case CONTROL_POW:
Serial.println("power on/off 0xA90");
for (int i = 0; i < 3; i++) {
setColor(255, 0, 0);
irsend.sendSony(0xA90, 12);
delay(40);
}
break;
case CONTROL_CH:
setColor(0, 255, 0);
if (val == CONTROL_UP) {
digitalWrite(led, HIGH);
for (int i = 0; i < 3; i++) { irsend.sendSony(0x090, 12); delay(40); }
Serial.println("channel up 0x090");
} else {
for (int i = 0; i < 3; i++) { irsend.sendSony(0x890, 12); delay(40); }
Serial.println("channel down 0x890");
}
break;
case CONTROL_VOL:
setColor(0, 0, 255);
if (val == CONTROL_UP) {
digitalWrite(led, HIGH);
for (int i = 0; i < 3; i++) { irsend.sendSony(0x490, 12); delay(40); }
Serial.println("volume up 0x490");
} else {
for (int i = 0; i < 3; i++) { irsend.sendSony(0xC90, 12); delay(40); }
Serial.println("volume down 0xC90");
}
break;
}
}
void setColor(int r, int g, int b) {
analogWrite(ledR, r);
analogWrite(ledG, g);
analogWrite(ledB, b);
}
long doPing() {
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
return pulseIn(echoPin, HIGH);
}
long microsecondsToInches(long us) { return us / 74 / 2; }
long microsecondsToCentimeters(long us) { return us / 29 / 2; }
Vorteile & Ausblick
- Kein Suchen nach Tasten – intuitive Gestensteuerung.
- Barrierefrei: Bedienung für Sehbehinderte & motorisch eingeschränkte Personen.
- Erweiterbar: Weitere Geräte (Klima, Licht, Medien) per zusätzlichen IR-Codes.
- Verbesserung: Machine Learning für komplexere Gesten, batteriebetriebener Wearable-Formfaktor.
Schaltplan & Fritzing
Breadboard-Schaltbild & Fritzing-Datei (flickmote_9Gx3XNFHEp.fzz) im Projekt enthalten.
Herstellungsprozess
- Ultraschall-Schwebegerät mit Arduino bauen – Akustische Levitation Schritt für Schritt
- Bluetooth-gesteuerter Arduino-Spybot bauen – Überwachungsroboter mit IP-Kamera
- DIY Arduino TV-B-Gone: Universelle TV-Aus-Fernbedienung
- Einen eigenen LED-Master-Clock mit Alarm bauen – aus 12 Metern Entfernung ablesbar
- Find Me: Smarter Gegenstands-Finder mit Arduino und Bluetooth
- Optimierte Stromversorgungslösungen für Arduino-Projekte
- Arduino Tic Tac Toe mit MAX7219 LED-Matrix und Karton-Gehäuse
- Intelligenten Arduino-Vierbeiner-Roboter bauen: Schritt-für-Schritt-Anleitung
- DIY Arduino Lenkrad / Joystick für Rennspiele – USB-HID-Umbau
- Kompaktes Arduino-Radar mit HC-SR04 Ultraschallsensor & 1,8″ Display