Community project
Aleteo de Mariposa Interactiva
The Interactive Butterfly Flutter is a motion-activated decorative accessory that flaps its wings in response to hand gestures and sound. Built around an ESP32 microcontroller, it combines a servo-driven wing mechanism with distance sensing and audio detection to create an engaging, responsive butterfly that reacts to its environment.
This guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions for building the butterfly from lightweight materials. The included firmware handles servo control, distance sensor input from the VL53L0X, and clap detection via the MAX9814 microphone amplifier, allowing the wings to flutter when someone approaches or claps nearby.
Wiring diagram

Gather all the parts
Assemble it in 6 steps
1. Haz el cuerpo ligero de la mariposa
Corta dos alas de espuma EVA fina, tela rígida o cartulina laminada y forma una bisagra flexible en su borde interior con cinta textil. Pega el microservo servo_1 sobre una base muy ligera encima de la pinza hair_clip_1, con su eje apuntando hacia las alas. No pegues todavía las alas al pelo: primero prueba el movimiento fuera de la cabeza.
- Mantén las alas y la base tan ligeras como puedas: un servo pequeño puede moverlas mejor y la pinza no se caerá.
- Deja libre el conector USB-C de la IdeaBoard.
- No uses la mariposa mientras el mecanismo está sin carcasa o con alambres expuestos: una pieza móvil puede enganchar pelo o pellizcar piel.
2. Une las alas al brazo del servo
Coloca el brazo plástico incluido con servo_1 en el eje del servo cuando esté en reposo. Dobla linkage_1 como una varilla corta y engancha un extremo en un agujero del brazo y el otro en el punto común de las dos bisagras de wing_1. Mueve el brazo a mano muy despacio para comprobar que las alas pueden abrirse y cerrarse sin forzarlas.
- Si las alas golpean el cuerpo, acorta el brazo del servo o mueve el gancho a un agujero más cercano al eje.
- La posición cerrada del programa es aproximadamente 58 grados; vuelve a montar el brazo un diente si las alas quedan demasiado abiertas al descansar.
- No fuerces el servo con la mano ni dejes que las alas lleguen a un tope duro: eso puede dañar sus pequeños engranajes.
3. Conecta el servo al conector de la IdeaBoard
Con el USB desconectado, enchufa servo_1 en uno de los conectores de tres pines para servo de la IdeaBoard correspondiente a GPIO4: VCC rojo → 5V (power), GND marrón o negro → GND (ground), y SIGNAL naranja o amarillo → GPIO4 (signal). Coloca servo_cap_1 junto al conector: pata larga marcada + → 5V (power) y pata corta junto a la franja − → GND (ground).
- La IdeaBoard tiene alimentación preparada para microservos; usa el conector marcado con GPIO4 para no tener que llevar tres cables separados.
- La franja del condensador identifica el lado negativo.
- No inviertas el condensador: conectarlo al revés puede calentarlo, dañarlo o hacerlo reventar.
- No alimentes el servo desde 3V3; necesita los 5 V del USB para moverse con fuerza.
4. Conecta el sensor de mano al puerto pequeño
Conecta distance_1 al conector STEMMA QT/Qwiic de la IdeaBoard, usando un adaptador o cuatro cables: VIN → 3V3 (power), GND → GND (ground), SDA → GPIO21 (data) y SCL → GPIO22 (clock). Orienta la ventanita negra del sensor hacia delante, donde pueda ver una mano que se acerque.
- El puerto pequeño ya entrega 3,3 V y comparte los dos cables de datos correctos para este sensor.
- El programa activa el aleteo cuando detecta algo a menos de unos 25 cm.
- No conectes VIN del VL53L0X a 5 V en esta IdeaBoard: el sensor y sus cables de datos trabajan a 3,3 V.
5. Conecta el micrófono para el aplauso
Conecta VDD de microphone_1 → 3V3 (power), GND → GND (ground) y OUT → GPIO34 (sound signal). Deja el pequeño micrófono mirando hacia fuera y lejos del servo para que el zumbido del motor no parezca un aplauso.
- Si el módulo tiene un agujerito con tornillo de ganancia, empieza cerca de la posición media.
- Sujeta los cables para que no se muevan ni rocen el brazo de las alas.
- No conectes OUT del micrófono a 5 V ni alimentes el micrófono desde 5 V: su señal podría superar el máximo seguro de 3,3 V del ESP32.
6. Aísla y termina el accesorio
Revisa que todos los GND están unidos, cubre las uniones con tubo termorretráctil o cinta aislante y fija la IdeaBoard, los sensores y los cables a una base plana y ligera. Conecta la IdeaBoard al USB-C de una fuente USB de al menos 1 A; una batería USB pequeña puede ir en un bolsillo o en la ropa, no en la pinza.
- Antes de llevarla puesta, prueba el aleteo varias veces sobre una mesa y ajusta la varilla si roza.
- El programa mueve las alas durante cuatro segundos por cada mano cercana o aplauso.
- No lleves una batería USB, la IdeaBoard ni una placa sin aislar directamente contra la piel o el cuero cabelludo; pueden engancharse, resultar pesados o causar un cortocircuito.
Review all connections
1. Connections between "servo_1" and "ESP32"
2. Connections between "distance_1" and "ESP32"
3. Connections between "microphone_1" and "ESP32"
4. Connections between "servo_cap_1" and "ESP32"
Deploy the firmware
#include <Arduino.h>
#include <Wire.h>
#include <ESP32Servo.h>
#include <Adafruit_VL53L0X.h>
constexpr int SERVO_PIN = 4;
constexpr int MIC_PIN = 34;
constexpr int I2C_SDA_PIN = 21;
constexpr int I2C_SCL_PIN = 22;
constexpr int WINGS_CLOSED = 58;
constexpr int WINGS_OPEN = 118;
constexpr uint16_t NEAR_DISTANCE_MM = 250;
constexpr uint32_t SENSOR_INTERVAL_MS = 100;
constexpr uint32_t FLAP_DURATION_MS = 4000;
constexpr uint32_t SERVO_INTERVAL_MS = 15;
constexpr int CLAP_THRESHOLD = 260;
constexpr uint32_t CLAP_LOCKOUT_MS = 350;
Servo wingServo;
Adafruit_VL53L0X lox;
bool distanceSensorReady = false;
int servoAngle = WINGS_CLOSED;
int flapDirection = 1;
uint32_t flapUntil = 0;
uint32_t lastServoUpdate = 0;
uint32_t lastSensorRead = 0;
uint32_t lastClap = 0;
void wakeButterfly() {
flapUntil = millis() + FLAP_DURATION_MS;
}
bool heardClap() {
long total = 0;
int samples[64];
for (int i = 0; i < 64; ++i) {
samples[i] = analogRead(MIC_PIN);
total += samples[i];
delayMicroseconds(120);
}
const int average = total / 64;
int peakDeviation = 0;
for (int i = 0; i < 64; ++i) {
peakDeviation = max(peakDeviation, abs(samples[i] - average));
}
return peakDeviation > CLAP_THRESHOLD;
}
void updateServo() {
const uint32_t now = millis();
if (now - lastServoUpdate < SERVO_INTERVAL_MS) return;
lastServoUpdate = now;
if (static_cast<int32_t>(flapUntil - now) > 0) {
servoAngle += flapDirection * 2;
if (servoAngle >= WINGS_OPEN) {
servoAngle = WINGS_OPEN;
flapDirection = -1;
} else if (servoAngle <= WINGS_CLOSED) {
servoAngle = WINGS_CLOSED;
flapDirection = 1;
}
} else {
if (servoAngle > WINGS_CLOSED) servoAngle--;
if (servoAngle < WINGS_CLOSED) servoAngle++;
}
wingServo.write(servoAngle);
}
void checkDistance() {
if (!distanceSensorReady) return;
VL53L0X_RangingMeasurementData_t measure;
lox.rangingTest(&measure, false);
if (measure.RangeStatus != 4 && measure.RangeMilliMeter > 0 &&
measure.RangeMilliMeter < NEAR_DISTANCE_MM) {
wakeButterfly();
}
}
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetPinAttenuation(MIC_PIN, ADC_11db);
wingServo.setPeriodHertz(50);
wingServo.attach(SERVO_PIN, 500, 2400);
wingServo.write(WINGS_CLOSED);
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
distanceSensorReady = lox.begin();
if (!distanceSensorReady) Serial.println("VL53L0X not found; clap control remains active.");
}
void loop() {
const uint32_t now = millis();
if (now - lastSensorRead >= SENSOR_INTERVAL_MS) {
lastSensorRead = now;
checkDistance();
}
if (now - lastClap >= CLAP_LOCKOUT_MS && heardClap()) {
lastClap = now;
wakeButterfly();
}
updateServo();
}Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.




