Ferns: Lunch Break Reminder
Final Documentation
Final Documentation
In this project, the Ferns (Caden, Estee, and Summer) created an assistive device to make Ted’s work easier. Ted is a storeroom clerk at Carnegie Mellon’s Facilities Management Services, and we had a conversation with him about the most tedious and challenging parts of his job (documentation link). As a result, we worked with Ted to make an operable lunch break reminder that covers the storeroom doorbell so Ted can eat in peace.
In order to give Ted a peaceful lunch break, our device is a sign that covers the storeroom doorbell so that delivery drivers & other FMS workers won’t have access to the bell. When the sign is in use (11:30am - 12pm), a countdown of 30 minutes starts, informing visitors when to come back. We believe this is the most effective way to stop any disturbances.
The sign base is laser cut with white acrylic, with red acrylic letter inlay. For the operable mechanism, we used a large servo motor with an attachment that pushes the sign up via a hinge. In order to keep the sign as light as possible, all the electronics are placed in a box beside it. Three buttons at the top enable Ted to manually adjust the time if necessary (i.e. for daylight savings), but the device is equipped with an RTC module so that it automatically opens & closes during Ted’s lunch break every day.
In addition to this, we also created a separate sign for the exterior doorbell, which we were not able to build a device for. Because the FMS storeroom hours kept changing, the original sign was quite worn (refer to documentation link for context). This was an extra 'gift' for Ted!
Final product: a sign attached to the doorbell via a hinge component. When in use, the 30-minute countdown starts, informing visitors when to return. Buttons on the side box enable manual time adjustment for daylight savings.
Top view of device, flipped down
Electronics box with buttons to set time. Servo motor attachment on the side
Device flipped up, when not 11:30am-12pm
Extra exterior sign
Device in use:
When it is 11:30, the sign flips down to cover the doorbell. A countdown starts. Once his break is over at 12:30, the sign flips up again.
This prototype was designed to help answer the design question can we design something that informs visitor about Ted’s lunch break and what time they need to come back?
We build a doorbell cover that will cover the doorbell during lunch time (11:30AM-12PM). The rest of time the cover will be opened. The doorbell follows real time and have buttons to update the time in case day light savings happens.
Prototyping the box & bringing the sign & electronics together
Back of the sign. Figuring out how to flip the sign up/down
During lunch time the doorbell cover will close:
Outside of lunch time the doorbell cover will be opened:
First prototype of the doorbell cover. The client was concerned that the sign is too small so we decided to make it bigger.
Laser cut a sign for the outside doorbell. We cut out the time part so that they can write the time on their own.
Wiring all the electronic components together
Assembling a doorbell attachment with hinge to put the sign on
Mounting the servo motor attachment
Testing if adding a foam block to the servo attachment would help it flip the sign properly (it didn't)
Part 1: Prototyping
During the initial phases of the design, we used a frosted acrylic material for the sign. When talking with Ted, he stated that he like the material, but the words were a bit hard to see against the semi-transparent background. We also noticed that the wiring was visible through the sign, and it was slightly distracting. So in our final design, we switched to a white acrylic material, which was more easy to read and looked cleaner.
Another major design issue we worked through was where all the electronic components were going to go. Originally, we had the idea that everything would go on the back of the sign, to be a compact device. However, this would have made the sign far too heavy for the servo motor. When speaking with Ted, he gave us the idea to create a separate box for all those components, which would sit beside the doorbell box. This turned out to work a lot better, as it was more simple and lightweight.
Lastly, our team struggled a lot with the mechanism that flipped the sign up and down. In our initial sketches, we planned to use a linear actuator to slide the sign up and down along a rail. After talking with our instructor, Zach, we ultimately ended up using a servo motor and hinge. Despite seeming like a simple mechanism, this part was the most frustrating, as (1) we didn't have a wall, so it was difficult to simulate the actual sign flipping on the doorbell, (2) the height of the box with servo & height of the doorbell with the sign had to be exact to flip it fully, and (3) the servo motor attachment wasn't long enough at first to push the sign with enough force. It took a lot of trial and error to get the right servo attachment length and height ratio of the two parts that would flip our sign fully up and down.
Part 2: Decision making as a team
While majority of the process went smoothly, we struggled a long time with how to flip the sign up. This pushed back our schedule quite a bit, and we ended up working until the last night before final critique. Because of the tight schedule, we had to rapidly go through a lot of prototyping (i.e. testing different lengths of the servo attachment, adding foam blocks to assist the flip, etc.). We all underestimated the challenges of adding a mechanical component in our device because the concept of it seemed simple.
During our critique, we learned a lot about what worked well in our project and what could be improved. Many people liked how practical and simple our idea was. One piece of feedback said "Very useful! Putting a physical device over the button is simple, yet genius. Count down makes people believe the sign is real and active. Clock brightness is great." This made us feel confident that our idea addressed Ted's problem directly, all he needed was a peaceful lunch break without delivery drivers or other people constantly ringing his bell. During the critique we also got some really helpful constructive feedback. For example, someone pointed out that it would have been better if we could have tested the device on a real wall: “Correct… easier to prototype on real wall”, which would have been ideal. Another comment talked about the practical issue of powering the device, saying that we might need a longer cord or a new outlet. Someone else also encouraged us to explore different ways to raise the sign, “Experiment with other raising sign methods.” These comments matched pretty well with the problems we actually faced, we think the flipping mechanism with the servo motor was the hardest part of designing this project.
Even though the final project in this class focued on assistive technology for a person with a disability in the path, this semester we did something new. Instead of working with a person with disabilities, we worked with Ted, a local worker on campus whose job challenges really affect his day to day life. Working with him helped us understand that assistive devices don’t always have to be for disabilities, they can simply make someone’s routine easier or less stressful. Talking with Ted reminded us how important it is to actually listen to the client. For example he told us the frosted acrylic made the text on the sign hard to read, which helped us make the decision to switch to white acrylic. He also suggested putting the electronics in a separate box, which solved the problem of the servo not being able to handle the weight of the sign. These small details when talking to him made our final design much better. As a team, one of our biggest struggles was getting the sign to flip up and down smoothly. We didn’t expect this to be so frustrating, but small adjustments like servo arm length and matching the heights of the sign and box took a ton of trial and error. This taught us not to underestimate the complexity of mechanical parts just because they seem simple implementation wise on paper.
Overall, this project taught us to communicate more, prototype more efficiently, listen to the client's advice, and accept that things most often don't work perfectly the first time. Most of all, we realized that even a small device can make someone’s everyday life better, and that made the whole project feel worthwhile. Most of all, we thank Ted for being so great and friendly to work with, and we hope our device can help him.
Schematic and Block Diagram
/* ---------------------------------------------------------------------------
Project Title: Lunch Break Reminder
Authors): the Ferns (Caden, Estee, and Summer)
Description:
This project implements a Real-Time-Clock-based lunch countdown and an
automated servo mechanism triggered during the lunch window.
System Overview:
• A DS3231 RTC module keeps accurate time.
• A 7-segment display (Adafruit LED Backpack) shows either the set time
or the active countdown.
• Three buttons allow hour/minute adjustment and mode navigation.
• A servo rotates to the “lunch position” automatically at 11:30 and
returns to its default position at 12:00.
• The system displays a live countdown (MM:SS) during the lunch window.
• Serial output logs the current time, countdown values, and mode changes.
Behavior Summary:
• Normal Mode:
- The device continuously checks current RTC time.
- Between 11:30 and 11:59, the countdown to 12:00 begins and the
servo moves to its lunch position.
- At 12:00, the countdown ends and the servo returns to its start
position.
- Outside the window, the display remains cleared.
• Time-Setting Mode:
- Pressing the SET button cycles between: normal → hour → minute → save.
- While setting, the selected field blinks.
- UP/DOWN buttons adjust hour or minute.
- When “save” is reached, the newly set time is written to the RTC.
Pin Mapping:
INPUTS:
- BTN_SET (2) ........... Enter / advance time-setting mode
- BTN_DOWN (3) ........... Decrease hour/minute
- BTN_UP (4) ........... Increase hour/minute
OUTPUTS:
- SERVO_PIN (5) .......... Servo controlling lunch mechanism
- 7-segment backpack ..... I2C (SDA/SCL)
COMMUNICATION:
- I2C (Wire) ............. RTC DS3231 and Adafruit 7-segment display
Notes:
- Lunch window is defined as 11:30:00 → 11:59:59.
- Countdown begins automatically and displays time remaining to 12:00.
- All project code was generated with assistance from ChatGPT
based on group design requirements.
--------------------------------------------------------------------------- */
#include <Wire.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>
#include <Servo.h>
RTC_DS3231 rtc;
Adafruit_7segment display = Adafruit_7segment();
Servo lunchServo;
// ==================== SERVO ====================
#define SERVO_PIN 5
#define SERVO_START_POS 0 // Position when NOT lunch time
#define SERVO_LUNCH_POS 180 // Position during lunch time
// ==================== BUTTONS ====================
#define BTN_SET 2
#define BTN_DOWN 3
#define BTN_UP 4
// ==================== TIME SET STATE ====================
int setHour = 11;
int setMinute = 30;
int setStep = 0; // 0 = normal mode, 1 = hour, 2 = minute, 3 = confirm/save
unsigned long lastBlink = 0;
bool blinkState = true;
// ==================== COUNTDOWN STATE ====================
bool countdownStarted = false;
void setup() {
Serial.begin(9600);
Wire.begin();
rtc.begin();
// Set to just before lunch time for testing
// rtc.adjust(DateTime(2025, 11, 17, 11, 29, 55));
display.begin(0x70);
// Setup servo
lunchServo.attach(SERVO_PIN);
lunchServo.write(SERVO_START_POS); // Start at 0 degrees
pinMode(BTN_SET, INPUT_PULLUP);
pinMode(BTN_DOWN, INPUT_PULLUP);
pinMode(BTN_UP, INPUT_PULLUP);
Serial.println("Lunch Timer Started");
Serial.println("Servo initialized at 0 degrees");
}
// ===================== LUNCH WINDOW CHECK =====================
bool isLunchTime(int h, int m) {
int t = h * 100 + m;
bool result = (t >= 1130 && t < 1200);
return result;
}
// ===================== BUTTON HELPER =====================
bool buttonPressed(int pin) {
if (digitalRead(pin) == LOW) {
delay(50);
while (digitalRead(pin) == LOW); // wait for release
return true;
}
return false;
}
// ===================== DISPLAY TIME (BLINKING WHEN EDITING) =====================
void showSetTime() {
unsigned long now = millis();
if (now - lastBlink > 500) {
blinkState = !blinkState;
lastBlink = now;
}
display.clear();
bool showHour = true;
bool showMin = true;
if (setStep == 1 && !blinkState) showHour = false; // blink hour
if (setStep == 2 && !blinkState) showMin = false; // blink minute
// Hour
if (showHour) {
display.writeDigitNum(0, setHour / 10);
display.writeDigitNum(1, setHour % 10);
}
display.drawColon(true);
// Minute
if (showMin) {
display.writeDigitNum(3, setMinute / 10);
display.writeDigitNum(4, setMinute % 10);
}
display.writeDisplay();
}
// ===================== COUNTDOWN TO 12:00 =====================
void lunchTimeActivities() {
DateTime now = rtc.now();
int currentHour = now.hour();
int currentMin = now.minute();
int currentSec = now.second();
// Debug output every second
static unsigned long lastDebug = 0;
if (millis() - lastDebug > 1000) {
Serial.print("Current Time: ");
if (currentHour < 10) Serial.print("0");
Serial.print(currentHour);
Serial.print(":");
if (currentMin < 10) Serial.print("0");
Serial.print(currentMin);
Serial.print(":");
if (currentSec < 10) Serial.print("0");
Serial.println(currentSec);
lastDebug = millis();
}
// Check if we're in lunch window (11:30 - 11:59)
if (isLunchTime(currentHour, currentMin)) {
if (!countdownStarted) {
countdownStarted = true;
Serial.println("*** LUNCH TIME STARTED - COUNTDOWN ACTIVE ***");
// Move servo to lunch position
Serial.println("Moving servo to 180 degrees...");
lunchServo.write(SERVO_LUNCH_POS);
delay(500); // Give servo time to move
}
// Calculate time remaining until 12:00:00
// Convert current time to total seconds since midnight
long totalNow = (long)currentHour * 3600L + (long)currentMin * 60L + (long)currentSec;
long target = 12L * 3600L; // 12:00:00 in seconds
long remaining = target - totalNow;
// Safety check
if (remaining < 0) remaining = 0;
if (remaining > 1800) remaining = 1800; // Max 30 minutes
// Convert to minutes and seconds
int mm = (int)(remaining / 60L);
int ss = (int)(remaining % 60L);
// Debug countdown
Serial.print("Countdown: ");
if (mm < 10) Serial.print("0");
Serial.print(mm);
Serial.print(":");
if (ss < 10) Serial.print("0");
Serial.println(ss);
// Display on 7-segment
display.writeDigitNum(0, mm / 10, false);
display.writeDigitNum(1, mm % 10, false);
display.drawColon(true);
display.writeDigitNum(3, ss / 10, false);
display.writeDigitNum(4, ss % 10, false);
display.writeDisplay();
}
else {
// Outside lunch window - turn off display
if (countdownStarted) {
Serial.println("*** LUNCH TIME ENDED ***");
countdownStarted = false;
// Move servo back to start position
Serial.println("Moving servo back to 0 degrees...");
lunchServo.write(SERVO_START_POS);
delay(500); // Give servo time to move
}
display.clear();
display.writeDisplay();
}
}
// ===================== LOOP =====================
void loop() {
// ----------- SET BUTTON HANDLING ------------
if (buttonPressed(BTN_SET)) {
setStep++;
if (setStep > 3) setStep = 0;
if (setStep == 3) {
DateTime old = rtc.now();
rtc.adjust(DateTime(
old.year(), old.month(), old.day(),
setHour, setMinute, 0
));
Serial.println("Time updated!");
}
if (setStep == 0) {
countdownStarted = false; // Reset countdown state
}
}
// ----------- If we are in hour or minute setting mode -----------
if (setStep == 1 || setStep == 2) {
if (setStep == 1) {
// Adjust hour
if (buttonPressed(BTN_UP)) setHour = (setHour + 1) % 24;
if (buttonPressed(BTN_DOWN)) setHour = (setHour == 0 ? 23 : setHour - 1);
}
if (setStep == 2) {
// Adjust minute
if (buttonPressed(BTN_UP)) setMinute = (setMinute + 1) % 60;
if (buttonPressed(BTN_DOWN)) setMinute = (setMinute == 0 ? 59 : setMinute - 1);
}
showSetTime();
return; // don't run countdown while editing
}
// ----------- Normal operation -----------
lunchTimeActivities();
delay(200); // Delay to prevent overwhelming the display and serial output
}