Explanation: A lamp designed to gently guide users through their evening routine using ambient light cues. A short tap on the touch sensor steps the light down to mark the completion of tasks like eating dinner or getting ready for bed, while a long press gradually fades the lamp to off, signaling the transition into rest. By breaking the evening into simple milestones, the lamp supports users who benefit from structured routines or subtle reminders without relying on alarms or screens.
Caption: The lamp glowing at full brightness with the lid on, fully illuminating the layered interior insert.
The lamp completely dark, representing how it appears when the user comes home or after they finish all their tasks.
The lamp glowing at full brightness with the lid on, fully illuminating the layered interior insert.
The lamp at medium light, with the layered insert partially illuminated to indicate the completion of one task.
The lamp with the lid removed, showing a finger pressing the capacitive touch sensor that controls the light levels.
Demonstration of the lamp’s interaction sequence: starting from fully off, the lid opens and two short taps step the brightness down to zero, while a long press smoothly fades the light all the way off.
I temporarily taped the capacitive touch sensor onto the circular extrusion of the 3D-printed lid to figure out its ideal alignment with the opening in the box. This step helped me physically map the sensor’s sensitivity area and understand how much tolerance I had with the lid’s thickness. The process photo shows the sensor wired across two mini breadboards and connected to an Arduino as I tested responsiveness and placement.
These are the first round of failed prints. The grey PLA prints stopped midway because the filament ran out, leaving incomplete geometry and revealing where the print paused. The clear resin print failed differently, the bottom layers didn’t fully cure before the upper layers formed, creating large internal gaps and distortions. Each failure helped pinpoint different issues in print settings, material behavior, and the structural demands of the insert.
After the print failures, I redesigned the CAD model to transition the insert to a layered, laser-cut approach. Using stacked acrylic gave me more predictable fabrication results and tighter tolerances. I cut the pieces from black-tinted acrylic, each shaped like a rounded triangle that gradually decreased in size toward the back. I then used superglue to assemble the stack, allowing me to precisely control depth and internal spacing.
I tested five LED light strips running from the capacitive touch sensor input. While they all powered on initially, I noticed that they slowly dimmed over time, likely because the power draw exceeded what my setup could consistently supply. After several trials, I decided to reduce the number of LED strips to maintain brightness and ensure stable performance.
I drilled a clean pass-through hole in the back of the box to route the sensor and LED wires to the breadboards and Arduino. I also drilled an opening at the bottom of the interior so the LED strips could feed through to the front, where I later glued them along the interior walls. This step allowed the electronics to remain hidden while keeping the internal lighting cleanly installed.
Throughout this process, I realized how much iterative making shaped the final outcome. Every failed print, wiring issue, and material change showed me something about the constraints of my design and the tools I was using. Switching from 3D printing to laser cutting helped me to clarify the structural logic of the insert and refine the geometry more intentionally. Troubleshooting the electronics taught me about power limitations and component placement. I also became more aware of how small tolerances can quickly accumulate into bigger functional problems. These challenges pushed me to slow down, test more frequently, and make more deliberate design choices instead of assuming the first version would work.
“Understanding the context and place will definitely help flesh out future functionality iterations.” It was helpful to hear that my context wasn’t fully communicated during the demonstration. This feedback made me realize that I need to more clearly define where and how my lamp would be used, since its functionality could shift depending on different users’ environments and routines. Another comment that stood out to me was, “Add a timer feature [that] gets triggered to start the timer at like 7pm to tell you to begin making dinner.” I appreciated this suggestion because it aligned with an idea I initially had to add a timer feature but didn’t have time to implement. It was reassuring to see that others saw potential for that kind of interaction, confirming that there’s room to expand the project’s functional complexity.
I’m happy with how the project turned out, especially considering the challenges I faced with 3D printing. The physical design was satisfying to complete, but I would like to keep refining it based on what I’ve learned. If I were to revisit the project, I’d better balance the physical build and electronic integration earlier in the process. I became too focused on the form and had to rush the circuitry at the end. I also wish I had explored ways to supply more power to illuminate additional LEDs. One major issue was the lid functionality. I experimented with both a tactile push button and a capacitive touch sensor, but neither worked as intended. I misunderstood how the touch sensor detected input, it relied on changes in capacitance, not direct contact. If I were to fix this, I’d solder copper tape to the sensor so it could better detect touch between the lid and the user’s finger.
I found CAD modeling to be one of the most enjoyable and useful parts of the process because it allowed me to refine my form precisely. However, 3D printing was tedious since each of my three parts failed multiple times, taking up a significant amount of time. In hindsight, I would have started by laser cutting the clear insert, which would have given me more time to focus on the electronics and iterate the lid design. I also got stuck early on trying to get the sensor to toggle the light and provide enough power to light all five LED strips. Despite these challenges, I learned to troubleshoot systematically and to anticipate how material and technical constraints affect design execution.
I plan to create another iteration of this lamp. I would print the body in black and redesign the clear insert at a steeper, more intentional angle. I’d also prototype the lid earlier, first testing with soldered copper tape, and if that fails, modeling a mechanism to integrate a button more effectively. Additionally, I’d increase the number of LED strips and introduce a nightlight mode controlled by two buttons for adjustable brightness. These improvements would make the lamp both more functional and refined in its interaction design.
/*
Project Title: Task Lamp
Description:
This Arduino program controls a two-strip LED lamp using a
capacitive touch sensor. A short tap cycles through dimming
sequences by toggling each strip on or off one at a time.
A long press (2 seconds or more) triggers a full sequential
fade-out of both LED strips, turning the lamp off completely.
The behavior enables users to track tasks through ambient
lighting feedback—each tap representing task completion.
Pin Mapping:
- Touch Sensor Input: Pin 10
- LED Strip 1 (Lower Layer): Pin 3
- LED Strip 2 (Upper Layer): Pin 4
- Power: Both LED strips share 5V and GND with the Arduino.
LED Overview:
- Strip 1: 15 LEDs (warm white)
- Strip 2: 20 LEDs (warm white)
- Both use PololuLedStrip library for fast RGB updates.
Credits: Much of this code structure, debugging help, and logic flow
was developed with assistance from ChatGPT (OpenAI), including
guidance on long-press detection, fade sequencing, and LED
state management.
*/
#include <PololuLedStrip.h>
// Pin definitions
const int touchPin = 10; // Capacitive touch sensor
const int ledStripPin1 = 3; // First LED strip DI
const int ledStripPin2 = 4; // Second LED strip DI
// Number of LEDs
const int NUMLEDS1 = 15;
const int NUMLEDS2 = 20;
// LED strip objects
PololuLedStrip<ledStripPin1> ledStrip1;
PololuLedStrip<ledStripPin2> ledStrip2;
// LED arrays
rgb_color strip1[NUMLEDS1];
rgb_color strip2[NUMLEDS2];
// Colors
rgb_color warmWhite = rgb_color(255, 100, 50);
rgb_color black = rgb_color(0, 0, 0);
// State tracking
bool strip1On = true;
bool strip2On = true;
bool lastTouchState = false;
unsigned long touchStartTime = 0;
bool longPressTriggered = false;
bool fingerPressed = false;
int nextToggleStrip = 1;
void setup() {
pinMode(touchPin, INPUT);
updateLEDs();
Serial.begin(9600);
}
void loop() {
bool touchState = digitalRead(touchPin);
// Touch started
if (touchState && !lastTouchState) {
touchStartTime = millis();
longPressTriggered = false;
fingerPressed = true;
}
// Long press (≥2 sec): sequential fade
if (touchState && fingerPressed && !longPressTriggered) {
if (millis() - touchStartTime >= 2000) {
fadeOutStrip1();
fadeOutStrip2();
strip1On = strip2On = false;
nextToggleStrip = 1;
updateLEDs();
longPressTriggered = true;
}
}
// Touch released
if (!touchState && lastTouchState) {
fingerPressed = false;
unsigned long pressDuration = millis() - touchStartTime;
// Short tap (<2 sec)
if (pressDuration < 2000 && !longPressTriggered) {
// If both strips are off, turn both on
if (!strip1On && !strip2On) {
strip1On = strip2On = true;
nextToggleStrip = 1; // reset sequence
} else {
// Otherwise, toggle next strip in sequence
switch (nextToggleStrip) {
case 1: strip1On = !strip1On; break;
case 2: strip2On = !strip2On; break;
}
// Move to next strip for next short press
nextToggleStrip++;
if (nextToggleStrip > 2) nextToggleStrip = 1;
}
updateLEDs();
}
}
lastTouchState = touchState;
delay(20);
}
// Update both LED strips according to on/off state
void updateLEDs() {
for (int i = 0; i < NUMLEDS1; i++)
strip1[i] = strip1On ? warmWhite : black;
ledStrip1.write(strip1, NUMLEDS1);
for (int i = 0; i < NUMLEDS2; i++)
strip2[i] = strip2On ? warmWhite : black;
ledStrip2.write(strip2, NUMLEDS2);
}
// Fade out strip 1 gradually
void fadeOutStrip1() {
int steps = 30;
int delayMs = 50;
rgb_color startColor = strip1[0];
for (int step = steps; step >= 0; step--) {
rgb_color color = rgb_color(
(startColor.red * step) / steps,
(startColor.green * step) / steps,
(startColor.blue * step) / steps
);
for (int i = 0; i < NUMLEDS1; i++)
strip1[i] = color;
ledStrip1.write(strip1, NUMLEDS1);
delay(delayMs);
}
for (int i = 0; i < NUMLEDS1; i++)
strip1[i] = black;
ledStrip1.write(strip1, NUMLEDS1);
}
// Fade out strip 2 gradually (after strip1)
void fadeOutStrip2() {
int steps = 30;
int delayMs = 50;
rgb_color startColor = strip2[0];
for (int step = steps; step >= 0; step--) {
rgb_color color = rgb_color(
(startColor.red * step) / steps,
(startColor.green * step) / steps,
(startColor.blue * step) / steps
);
for (int i = 0; i < NUMLEDS2; i++)
strip2[i] = color;
ledStrip2.write(strip2, NUMLEDS2);
delay(delayMs);
}
for (int i = 0; i < NUMLEDS2; i++)
strip2[i] = black;
ledStrip2.write(strip2, NUMLEDS2);
}