What I wanted to learn, and why it interested me: I want to learn about how to solder an LED strip, and build a live-varying LED display depending on a sensor value.
Final outcome: The Arduino reads a pulse sensor to detect heartbeats and calculates the beats per minute (BPM). It outputs a flowing pulse effect on an LED strip, with the color of the LEDs changing based on the current BPM. Blue indicates a slow heart rate, green a normal rate, and red a fast heart rate.
Images of final creative/exploratory output
The final setup consists of an Arduino connected to a pulse sensor and a soldered LED strip.
The final video demoing the flowing lights according to my pulse rate (pulse sensor is taped under my finger). I placed a frosted acrylic on top of the light strip for diffusion.
Process images from development towards creative/exploratory output
Wiring the pulse sensor and the LED strip to the arduino using a breadboard.
I experimented with gradients proportional to pulse rate, however I was not able to get it to be very responsive and smooth.
Original demo with raw LED strip. I found that the camera is not able to capture the LEDs very well, so I decided to add a piece of frosted acrylic sheet on top to smooth out the light for better visuals.
Process and reflection:
The process of learning about the basics of how to manipulate and wire an LED strip is very entertaining, especially because I can see instant, colorful feedback from the lights. Once I understood the fundamentals, I chose a sensor that seemed the most interesting to me, a pulse sensor, and used that as an input to control the LED display. I experimented with multiple ways of translating the pulse rate to LEDs: flashing to each heartbeat, creating wave/ ripple effects with each beat, creating gradients, and mapping the pulse rate to color and speed of the individual LEDs on the strip. It was interesting to play with different libraries to control the LED strip!
In terms of hardware, both the LED and the pulse sensor were easy and straightforward to wire. The most challenging part was soldering wires onto the LED strip. It was difficult to hold both the wire and the strip in place while soldering on a small area. Because I was also inexperienced in soldering, the wires came apart multiple times, and I spent a tedious amount of time getting them to stay in place.
Technical details
Electrical Schematic
Block Diagram
/*
60-223 Intro to Physical Computing, fall 2025
Domain-specific Skill Building exercise: [Heartbeat Responsive Flowing Lights]
[This sketch reads a pulse sensor and smooths the analog signal to reduce noise. It detects each heartbeat, calculates the correact BPM, prints both the smoothed sensor value and BPM to the Serial Monito,and sends a flowing pulse of LEDs down a trip, with the LED color changing according to the current BPM (blue for slow heart rate, green for normal, and red for a fast hear rate.]
Pin mapping:
Arduino pin | role | details
------------------------------
A0 input pulse sensor
6 output external LED Strip
Code implementation assisted by ChatGPT, 9/26/2025
*/
#include <Adafruit_NeoPixel.h>
#define LED_PIN 6
#define NUM_LEDS 18
#define PULSE_PIN A0
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
// Pulse detection
int threshold = 550;
int pulseState = LOW;
int pulseIndex = -1;
int fadeAmount = 10;
// BPM calculation
unsigned long lastBeatTime = 0;
float bpm = 0;
// Smoothing
const int smoothSize = 5;
int values[smoothSize] = {0};
int index = 0;
// Simple moving average smoothing
int smooth(int reading) {
values[index] = reading;
index = (index + 1) % smoothSize;
long sum = 0;
for (int i = 0; i < smoothSize; i++) sum += values[i];
return sum / smoothSize;
}
void setup() {
strip.begin();
strip.show();
Serial.begin(9600);
}
void loop() {
int rawValue = analogRead(PULSE_PIN);
int sensorValue = smooth(rawValue); // Smoothed reading
// Print smoothed sensor value
Serial.print("Smoothed: ");
Serial.print(sensorValue);
// Detect heartbeat
if (sensorValue > threshold && pulseState == LOW) {
pulseState = HIGH;
pulseIndex = 0; // Start new pulse
unsigned long currentTime = millis();
if (lastBeatTime > 0) {
unsigned long interval = currentTime - lastBeatTime; // ms between beats
bpm = 60000.0 / interval; // Correct BPM calculation
Serial.print(" BPM: ");
Serial.print(bpm);
}
lastBeatTime = currentTime;
}
if (sensorValue < threshold && pulseState == HIGH) {
pulseState = LOW;
}
Serial.println();
// Update LED strip
updatePulse();
fadeStrip();
}
// Move pulse down the strip
void updatePulse() {
if (pulseIndex >= 0 && pulseIndex < NUM_LEDS) {
strip.setPixelColor(pulseIndex, bpmColor(bpm));
pulseIndex++;
}
}
// Fade LEDs gradually
void fadeStrip() {
for (int i = 0; i < NUM_LEDS; i++) {
uint32_t color = strip.getPixelColor(i);
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = color & 0xFF;
r = max(0, r - fadeAmount);
g = max(0, g - fadeAmount);
b = max(0, b - fadeAmount);
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
// Map BPM to color
uint32_t bpmColor(float bpm) {
if (bpm < 70) return strip.Color(0, 0, 255); // Blue
if (bpm < 100) return strip.Color(0, 255, 0); // Green
return strip.Color(255, 0, 0); // Red
}