THE TECHNIQUE¶
Breath-Based Interaction Concept¶
The wearer carries a thin nasal tube similar to those used in medical oxygen systems. When the wearer exhales, the airflow is directed through this tube onto a sound sensor / microphone inside the wearable. The resulting sound becomes the activation signal for the system: - Exhalation present → motor rotates & LEDs pulse - Breathing stops / silence → motor & LEDs stop The motor drives the Sargassum modules, causing the entire structure to gently move in response to the wearer’s breath. Through this motion, the wearable & the body begin to share a synchronized rhythm. What emerges is the sensation of a collective inhaling & exhaling — a quiet state of alignment in which human & artificial organism appear to breathe together, in harmony.
Hardware Assumptions¶
- Seeed XIAO RP2040 operates at 3.3V logic level.
- NeoPixels are powered with 5V & accept 3.3V data.
- TB6612FNG motor driver logic (VCC) is powered by 3.3V.
- TB6612FNG motor supply (VM) is powered by an external 5–9V source.
- DC motor voltage rating matches the VM supply.
- Sound Sensor V1.4 provides a digital trigger signal (SIG) when sound is detected.
- All grounds are shared between XIAO, motor driver, NeoPixels, sound sensor, & power supply.
- Power source can deliver enough current for motor & LEDs.
System Components & Functions¶
| Order | Category | Component | Description | Function in System |
|---|---|---|---|---|
| 1 | Microcontroller | Seeed XIAO RP2040 | 3.3V compact microcontroller | Central control unit managing sound input, LED animation, and motor control |
| 2 | Programming | Custom Arduino Code | Non-blocking structured firmware | Coordinates sound trigger, motor ramp behavior, and LED pulsing logic |
| 3 | Input | Sound Sensor V1.4 (SIG) | Microphone with comparator output | Detects breath / speech and activates system while sound is present |
| 4 | Motor Control | TB6612FNG Motor Driver | Dual H-bridge driver | Controls motor direction and speed via PWM signal |
| 5 | Actuation | DC Motor | Small rotational motor | Generates mechanical rotation for movement system |
| 6 | Light Output | 10× NeoPixel LEDs | Individually addressable RGB LEDs | Produce soft, pulsating, breathing-like illumination |
| 7 | Power – Logic | XIAO 3.3V Output | On-board voltage regulator | Supplies logic voltage to motor driver and sound sensor |
| 8 | Power – Motor | External Battery / Step-down | 5–9V motor supply | Provides motor operating voltage via TB6612 VM |
| 9 | Motion Transmission | Gear Set (various sizes) | Laser-cut acrylic gears | Converts motor rotation into differentiated motion speeds |
| 10 | Motion Interface | Rounded Wire Loops | Bent metal transfer elements | Transfers mechanical movement from gears outward |
| 11 | Wiring | Jumper Wires / Soldered Connections | Electrical connections | Connects all electronic components into unified system |
THE CODE¶
#include <Adafruit_NeoPixel.h>
// =====================
// NEOPIXELS
// =====================
#define LED_PIN D0
#define LED_COUNT 10
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// =====================
// MOTOR (your wiring)
// =====================
#define STBY D6
#define PWMA D4
#define AIN1 D7
#define AIN2 D8
// =====================
// SOUND SENSOR V1.4 (SIG)
// =====================
#define SOUND_SIG D2 // SIG -> D2
// If your sensor outputs LOW when sound is detected, set this to LOW.
#define SOUND_ACTIVE_STATE HIGH
// =====================
// SYSTEM STATE
// =====================
bool systemOn = false;
// =====================
// MOTOR RAMP
// =====================
uint8_t motorTargetPWM = 0;
uint8_t motorCurrentPWM = 0;
const uint8_t motorRampStep = 3;
const unsigned long motorRampInterval = 10;
unsigned long lastMotorRampMs = 0;
// =====================
// LED PALETTE
// =====================
uint32_t colorsA[5];
uint32_t colorsB[5];
unsigned long cycleTime[5] = {
3000, // Pixel 1
3500, // Pixel 2
4000, // Pixel 3
4500, // Pixel 4
5000 // Pixel 5
};
void setup() {
// Motor
pinMode(STBY, OUTPUT);
pinMode(PWMA, OUTPUT);
pinMode(AIN1, OUTPUT);
pinMode(AIN2, OUTPUT);
digitalWrite(STBY, HIGH);
analogWrite(PWMA, 0);
// Sound sensor signal
pinMode(SOUND_SIG, INPUT); // if it floats, change to INPUT_PULLDOWN (see note below)
// LEDs
strip.begin();
strip.setBrightness(40);
strip.show();
// Color pairs (your palette)
colorsA[0] = strip.Color(245,240,220); // cream
colorsB[0] = strip.Color(180,195,210); // dove blue
colorsA[1] = strip.Color(210,190,180); // beige
colorsB[1] = strip.Color(200,170,175); // rose
colorsA[2] = strip.Color(200,170,175); // rose
colorsB[2] = strip.Color(90,95,105); // anthracite
colorsA[3] = strip.Color(90,95,105); // anthracite
colorsB[3] = strip.Color(245,240,220); // cream
colorsA[4] = strip.Color(245,240,220); // cream
colorsB[4] = strip.Color(180,195,210); // dove blue
}
// Sound present -> ON, silence -> OFF
void handleSoundTrigger() {
int sig = digitalRead(SOUND_SIG);
systemOn = (sig == SOUND_ACTIVE_STATE);
}
void handleMotor() {
motorTargetPWM = systemOn ? 25 : 0;
unsigned long now = millis();
if (now - lastMotorRampMs < motorRampInterval) return;
lastMotorRampMs = now;
if (motorCurrentPWM < motorTargetPWM) motorCurrentPWM += motorRampStep;
if (motorCurrentPWM > motorTargetPWM) motorCurrentPWM -= motorRampStep;
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, LOW);
analogWrite(PWMA, motorCurrentPWM);
}
void handleLEDs() {
if (!systemOn) {
strip.clear();
strip.show();
return;
}
unsigned long now = millis();
for (int i = 0; i < 5; i++) {
float phase = (float)(now % cycleTime[i]) / (float)cycleTime[i];
float t = (sin(phase * TWO_PI - HALF_PI) + 1.0f) * 0.5f;
uint32_t c1 = colorsA[i];
uint32_t c2 = colorsB[i];
uint8_t r = (uint8_t)(((c1 >> 16) & 255) + ((((c2 >> 16) & 255) - ((c1 >> 16) & 255)) * t));
uint8_t g = (uint8_t)(((c1 >> 8) & 255) + ((((c2 >> 8) & 255) - ((c1 >> 8) & 255)) * t));
uint8_t b = (uint8_t)(( c1 & 255) + ((( c2 & 255) - ( c1 & 255)) * t));
strip.setPixelColor(i, r, g, b); // 1–5
strip.setPixelColor(i+5, r, g, b); // 6–10 mirror
}
strip.show();
}
void loop() {
handleSoundTrigger();
handleMotor();
handleLEDs();
}
. . . . . . .
©️ Copyright 2024 laura Muth
- All project & material experiment images are my own & were photographed by me.
- Other images are credited to the respective artists below.