A galvanic-skin-response (GSR) biofeedback device built on a Raspberry Pi Pico. It sonifies the wearer's arousal level: as you relax, skin resistance rises and the buzzer's pitch falls and pulse slows. The goal of the exercise is to make the sound low and slow.
A Seeed Grove GSR module measures skin conductance from two finger electrodes. The firmware:
- Oversamples and smooths (EMA) the GSR signal.
- Auto-calibrates to the wearer with a slowly-moving min/max window, so the full pitch range always maps onto your own dynamic range.
- Drives a buzzer via hardware PWM (
mbed::PwmOut) — PWM period sets pitch, duty cycle sets volume. - Emits a soft, pulsing beep whose pitch and tempo both track arousal: calm = low and slow, tense = high and fast.
- Mutes when the electrodes aren't worn (reading sits near the open-circuit level; a trim-pot-tunable ceiling detects contact).
- Optionally reads battery charge from a Waveshare Pico-UPS (INA219 over I²C) and chirps a distinctive low-battery alert.
| Signal | Pico pin |
|---|---|
| Grove GSR signal | GP26 / ADC0 |
| Buzzer + | GP15 |
| Buzzer − | GND |
| Contact-threshold trim pot — wiper | GP27 / ADC1 (pin 32) |
| Contact-threshold trim pot — ends | 3V3(OUT) and GND |
| Waveshare UPS gauge (INA219) | I²C on GP6 (SDA) / GP7 (SCL) |
Modules' VCC → 3V3(OUT), GND → GND.
See docs/WIRING.md for a full wiring diagram, colour key,
and connection table.
Trim pot: 10 kΩ linear, wiper to GP27, outer legs to 3V3(OUT) and GND (optional 100 nF wiper-to-GND). Sets the contact-detection ceiling live.
Power (untethered): a single 3.7 V LiPo via a Waveshare Pico-UPS, which feeds VSYS (never 3V3) and charges over the Pico's USB. The UPS's INA219 gauge enables the low-battery alert.
PlatformIO project targeting the Pico with the Arduino (mbed) core:
pio run # build
pio run -t upload # hold BOOTSEL while plugging in, then uploadOpen the serial monitor at 115200 baud to watch the live signal
(raw, ceil, Hz, gap, arsl, batt).
All key parameters are constants at the top of src/main.cpp:
| Constant | Effect |
|---|---|
FREQ_LOW / FREQ_HIGH |
Pitch span (relaxed → aroused) |
PERIOD_CALM / PERIOD_TENSE |
Beep gap (relaxed → aroused) |
VOLUME |
Buzzer loudness (PWM duty, 0.0–0.5) |
INVERT_RESPONSE |
Flip pitch direction if your module reads inverted |
CEIL_MIN / CEIL_MAX |
Range of the live contact-threshold pot |
LOW_BATT_PCT / ALERT_FREQ |
Low-battery alert threshold and chirp pitch |
The UPS I²C pins (UPS_SDA/UPS_SCL) and address (INA219_ADDR) default to
Waveshare's values — verify against your module's wiki if the gauge doesn't
respond.
Released under the MIT License.
