This project was created as part of an Introduction to Physical Computing course that partnered with Carnegie Mellon’s Facilities Management Services to design tools that make campus maintenance work safer and more efficient. We collaborated with carpenters through interviews (documentation link) to understand the challenges they face in busy campus environments. Our result is a portable barrier system that helps workers clearly mark and protect their area, using simple cues to make students and staff more aware of their surroundings.
Description
We built a barrier for carpenters that uses light and sound to warn when someone gets too close to a restricted work area. It’s meant to prevent passersby on campus from interfering with construction, especially when they’re distracted. The design includes two rectangular poles that slide into each other for easy carrying and separate when in use. The smaller pole sends an invisible beam to the larger pole, which reflects it back. When the beam is broken in low security mode, the lights flash, and in high security mode, the lights flash red and a voice yells out.
Final Images/Video
Two prototype barrier poles, one housing electronics and LEDs and the other marked with red and white reflective tape, shown side by side.
A person steps through the two barrier poles, causing the LED lights on the system to switch to red, indicating a restricted crossing.
Video showing a user approaching the barrier, which flashes green in low security mode. After switching to high security, close proximity makes the LEDs flash red and sound an alarm, and the user resets the system to green using an RFID tag.
The security mode switch labeled for high and low modes, alongside four LED light strips and an opening for the ultrasonic sensor.
Power switch and break beam sensor components used to activate the system and detect interruptions up to four meters away.
One side of the barrier covered in red and white reflective tape, with the square top lid attached to the side by Velcro.
High angle view of the barrier with the top lid secured, showing the form of the base.
Narrative
When Adam and Ryan arrive on campus early in the morning, their manager assigns them to fix a set of misaligned doors in Tepper. They grab their tools and head over, setting up a ladder in one doorway and propping open the other. A few students start slipping through the propped open door out of convenience, even though several other doors are available. Their presence disrupts Ryan on the ladder and creates an avoidable safety risk. Adam remembers the new barrier and sets it up to protect their workspace. The flashing lights make students pause and choose a different entrance, and the occasional shouted warning startles others just enough to keep them alert. With the barrier in place, Adam and Ryan can work without interruption, and people become more aware of the space around them.
This prototype was designed to help answer the design question: How can we ensure that people are not disturbing our client's workspaces without adding additional load to their work?
The prototype consisted of a nested stanchions that separate into two stands for a physical barrier. Additionally an electronic system sits on top of the smaller stanchion, detecting and alerting motion in two directions. When motion is detected in the first direction (someone approaching the barrier) the LED will light up or blink to alert the person. The prototype's second measurement of motion detects when someone passes between the two set up work barriers signaling an actual noise alert
These are the two stanchions standing up side by side without the electrical system
Here is the two stanchion set up across from each other with the electrical system on top.
This image demonstrates how the second stanchion is able nest inside of the other for easy transporation.
Discussion with our client about additional features and changes we could make to our prototype in order to improve the current design.
Here was two different ideas we had for power supply. One was a battery supply, the other was a plug in source.
This image depicts the initial breadboarding process for the electrical components.
From our prototyping process, we confirmed that the barrier is lightweight and compact enough for workers to carry easily between locations, and several carpenters specifically appreciated the modular design that allows the two poles to nest inside one another. We also found that the sound and visual alerts were noticeable, but not always strong enough to reliably catch distracted passersby, which was an insight that pointed us toward future improvements.
Based on critique feedback, we integrated several key changes into the final design: we added an RFID badge system to allow workers to silence the alarms quickly, chose not to include a physical tether between the poles since workers frequently enter and exit the space, adjusted the maximum operating distance to accommodate their preference for a 6-foot buffer, and added weight and a circular base to increase stability. Some feedback, however, was intentionally not incorporated. We chose not to differentiate “caution” versus “danger” with distinct sounds, instead relying on a single set of light cues and a high-security audio alert. We also did not add wheels or adjustable feet due to time constraints.
A notable surprise during prototyping was realizing that our estimated dimensions for the electronic components were slightly off. This caused misalignment when laser-cutting openings for the hardware and when spacing the stacked poles, requiring additional adjustments and rework.
Left: Here we are taping electrical components to our prototype to determine where they will physically fit and wire to.
Right: Here we are taking the physical dimensions of our placed electrical components to finalize our designs for the laser cut stanchions.
Left: The soldering process for our electrical components on the inside of the stanchion. Wires were condensed down onto a small PCB to save space.
Right: Creating the base for the stanchion. We glued layers of laser cut wood to stack up and form a nice heavy base for the stanchions.
Left: Finalizing the physical fabrication of the stanchion. Here we are connecting the vertical part of the stanchion to the base.
Right: Making a end of the line design change for the cap of the large stanchion. Initially we thought a hinge would be a good idea, but we ended up making it far simpler and used velcro to secure the lid to the side of the stanchion when they are nested.
Overall, we did a good job planning out the steps we needed to take in our design process., but there were still a few road bumps on along the way. The biggest issue we face in our design was using a thru-beam sensor. Our clients wanted our stanchions to have the capability to work over a distance of 6 feet apart. This required a special ordered thru-beam sensor that. This sensor required a voltage of 26 V, so our design had to be heavily built surrounding this component. Our power supply had to become a plug in source in order to meet the necessary voltage and then the Arduino required a voltage regulator to step down the 26 V to 5V. On top of this it was also difficult to understand the wiring for the component since it had a built in relay. We considered using alternative components at this stage because of all the hassle this component was going to cause, but ultimately we ended up sticking with it. The rest of the project was much simpler compared to this and far more easy-going.
The schedule for completing our tasks went smoothly. It was pretty easy for us all to get the required steps done since our tasks were assigned based mainly on expertise in the area. We all focused on stuff we were good at and wanted to do.
The most salient findings from the final crit centered around power sources, signaling, and durability. The most consistent piece of feedback we received was the need to incorporate a battery. Multiple carpenters emphasized the importance of “considering power sources such as a battery because older buildings do not have outlets in the hallways.” We had explored this earlier but didn’t have a sufficiently strong battery available in the lab. One comment that pushed our thinking was the suggestion to “look at tool companies to see how they solve the power issue,” which pointed us toward designing around existing, standardized battery ecosystems going forward.
A second major theme was improving visibility and alert systems. One person recommended “integrating a louder sound alarm, a person’s voice yelling, and reflective tape on all sides to have more attention-grabbing elements.” This made us realize that our current alarm, while functional, is not competitive with the noise and visual clutter of a hallway during busy passing periods. Another suggestion was to add a light that shows when the two barriers are aligned, which would make setup faster and more intuitive. Feedback also encouraged “using a camera or computer vision to detect a wider range of proximity,” which could have solved the limitation of our ultrasonic sensor only detecting motion along a single axis. A more practical recommendation was to include a small box that could be velcroed on to hold the RFID tags, power cord, and other loose components. This helped us better understand how to design for workers who will store, transport, and maintain the device in real conditions.
Working with our two clients highlighted how differently people in the field imagine and prioritize needs compared to designers or engineers. What surprised us most was how much emphasis they placed on reliability and convenience, where details like batteries, storage, durability, and setup time mattered far more to them than the sensing system itself. If we were to do this again, we would test prototype models on campus earlier to identify areas for improvement sooner. The process also reminded us that even simple constraints, like available power or environmental noise, can reshape an entire design direction. It pushed us to think more holistically about how our product fits into workflows, not just how it functions in isolation.
The project reinforced how important it is to design for the realities of a specific environment rather than ideal lab conditions. With a second chance, we would simplify the system, choose more robust sensing methods, and build around modular components that carpenters already trust. This experience ultimately taught us how to communicate more clearly with clients, adapt quickly when assumptions don’t hold, and prioritize decisions that make the design genuinely usable in the field.
Schematic and Block Diagram
Code
/* ---------------------------------------------------------------------------
Project Title: Work In Progress Barrier
Author: Cole Franklin, Wendy Lin, Sarah Fernandes
Description:
This project implements a multi-sensor security / monitoring system using:
• A beam-break (photoelectric) sensor to detect intrusions.
• An MFRC522 RFID reader to clear a latched alarm using authorized tags.
• An ultrasonic distance sensor (HC-SR04 style) to create a dynamic
LED color fade (yellow → red) based on object proximity.
• A Pololu/WS281x LED strip for visual feedback and alarm strobing.
• A buzzer that chirps while an alarm is latched.
• A mode switch that toggles between distance-fade mode and a solid
green “safe/override” mode.
System Behavior Overview:
• Breaking the beam latches an alarm: buzzer chirps and LEDs strobe
red/white until an authorized RFID tag is presented.
• A valid RFID tag clears the alarm.
• When no alarm is active and the mode switch is HIGH: LEDs fade
from yellow (far) to red (near) based on ultrasonic distance.
• When no alarm is active and the mode switch is LOW: LEDs are solid green.
• Serial output logs beam events, RFID UIDs, and distance readings.
Pin Mapping:
INPUTS:
- SWITCH_PIN (2) ........ Mode switch (INPUT_PULLUP)
- beamPin (4) ........... Beam-break sensor, NO output (INPUT_PULLUP)
- TRIGGER_PIN (7) ....... Ultrasonic trigger
- ECHO_PIN (8) .......... Ultrasonic echo
- RC522 SS_PIN (10) ..... RFID reader SDA/SS
- RC522 RST_PIN (9) ..... RFID reset
OUTPUTS:
- LED_PIN (3) ........... Addressable LED strip (Pololu LED library)
- buzzerPin (5) ......... Active-high buzzer
- statusLedPin .......... Built-in LED (mirrors beam-break state)
COMMUNICATION:
- SPI (RC522) ........... Uses MOSI/MISO/SCK hardware pins
Libraries Used and Credits:
• MFRC522 library by Miguel Balboa (MIT License)
https://github.com/miguelbalboa/rfid
• PololuLedStrip library by Pololu Robotics
https://github.com/pololu/pololu-led-strip-arduino
• NewPing library by Tim Eckel — improves ultrasonic sensor stability
https://bitbucket.org/teckel12/arduino-new-ping
• Portions of logic structure inspired by examples included in the
above libraries; all integrated and expanded for this custom system.
• Using the above library sketches, ChatGPT was used to generate the final code.
Notes:
- Beam sensor is wired so CLEAR = HIGH, BROKEN = LOW.
- Four authorized RFID tag UIDs included in the sketch.
- Alarm state is latched until a correct RFID tag clears it.
--------------------------------------------------------------------------- */
#include <SPI.h>
#include <MFRC522.h>
#include <PololuLedStrip.h>
#include <NewPing.h>
// ---- Pins & constants ----
const int SWITCH_PIN = 2;
const int LED_PIN = 3;
const int NUMLEDS = 20;
const int TRIGGER_PIN = 7;
#define ECHO_PIN 8
#define MAX_DISTANCE 200
// Beam-break sensor (E3JK-R4M2)
const int beamPin = 4; // Black (NO)
const int statusLedPin = LED_BUILTIN;
// Buzzer
const int buzzerPin = 5; // Active-high buzzer
// RFID RC522 (SPI)
const byte SS_PIN = 10; // SDA on module
const byte RST_PIN = 9;
MFRC522 mfrc522(SS_PIN, RST_PIN);
// ---- Objects ----
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
PololuLedStrip<LED_PIN> ledStrip;
// LED color buffer
rgb_color testing[NUMLEDS];
// Colors
rgb_color black = rgb_color(0, 0, 0);
rgb_color white = rgb_color(255, 255, 255);
rgb_color red = rgb_color(255, 0, 0);
rgb_color yellow = rgb_color(255, 255, 0);
rgb_color green = rgb_color(0, 255, 0);
rgb_color blue = rgb_color(0, 0, 255);
// (Old distance thresholds; not used anymore but kept if you want them later)
const int VERY_CLOSE = 6;
const int CLOSE = 20;
const int MEDIUM = 50;
const int FAR = 100;
// Alarm latch
bool alarmLatched = false;
// --- Buzzer chirp pattern (ON/OFF in ms) ---
const unsigned long BUZZER_ON_TIME = 120;
const unsigned long BUZZER_OFF_TIME = 250;
bool buzzerState = false;
unsigned long lastBuzzerToggle = 0;
// --- LED strobe pattern when alarmLatched ---
const unsigned long STROBE_INTERVAL = 150;
bool strobeState = false;
unsigned long lastStrobeToggle = 0;
// === AUTHORIZED RFID TAG UIDS (4 tags) ===
byte allowedUID1[] = { 0xB3, 0x60, 0x3F, 0xDD };
byte allowedUID1Length = 4;
byte allowedUID2[] = { 0x9C, 0xC5, 0x4B, 0x06 };
byte allowedUID2Length = 4;
byte allowedUID3[] = { 0x73, 0x2C, 0x10, 0xA6 };
byte allowedUID3Length = 4;
byte allowedUID4[] = { 0x63, 0xD1, 0xDD, 0xA6 };
byte allowedUID4Length = 4;
// --- Distance fade range (for yellow -> red) ---
const int FADE_NEAR = 50; // fully red at or closer than this (cm)
const int FADE_FAR = 100; // fully yellow at or farther than this (cm)
// ----------------- Helpers -----------------
void fillStrip(rgb_color color) {
for (int i = 0; i < NUMLEDS; i++) {
testing[i] = color;
}
}
bool uidEquals(byte *uid, byte uidSize, byte *ref, byte refSize) {
if (uidSize != refSize) return false;
for (byte i = 0; i < uidSize; i++) {
if (uid[i] != ref[i]) return false;
}
return true;
}
bool isAuthorizedTag(byte *uid, byte uidSize) {
if (uidEquals(uid, uidSize, allowedUID1, allowedUID1Length)) return true;
if (uidEquals(uid, uidSize, allowedUID2, allowedUID2Length)) return true;
if (uidEquals(uid, uidSize, allowedUID3, allowedUID3Length)) return true;
if (uidEquals(uid, uidSize, allowedUID4, allowedUID4Length)) return true;
return false;
}
// Map distance to a color fading from yellow (far) to red (near)
rgb_color colorFromDistance(unsigned int distance) {
// Treat out-of-range or zero as "far"
if (distance == 0 || distance > MAX_DISTANCE) {
return yellow;
}
// Clamp into fade range
if (distance <= FADE_NEAR) {
return red;
}
if (distance >= FADE_FAR) {
return yellow;
}
// Linear fade: red (near) -> yellow (far)
// Red stays 255; green goes 0 -> 255 as distance increases
unsigned int d = constrain(distance, FADE_NEAR, FADE_FAR);
uint8_t g = map(d, FADE_NEAR, FADE_FAR, 0, 255); // near=0, far=255
return rgb_color(255, g, 0);
}
// Check if a valid RFID tag is presented this loop
bool checkRFIDForValidTag() {
if (!mfrc522.PICC_IsNewCardPresent()) return false;
if (!mfrc522.PICC_ReadCardSerial()) return false;
// Print UID so you can verify/debug
Serial.print("RFID UID: ");
for (byte i = 0; i < mfrc522.uid.size; i++) {
if (mfrc522.uid.uidByte[i] < 0x10) Serial.print("0");
Serial.print(mfrc522.uid.uidByte[i], HEX);
Serial.print(" ");
}
Serial.println();
bool authorized = isAuthorizedTag(mfrc522.uid.uidByte, mfrc522.uid.size);
if (authorized) {
Serial.println("Valid RFID tag detected. Clearing alarm.");
} else {
Serial.println("Unknown/invalid RFID tag.");
}
// Clean up for next read
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
return authorized;
}
// ----------------- Setup & Loop -----------------
void setup() {
pinMode(SWITCH_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
// Beam sensor
pinMode(beamPin, INPUT_PULLUP);
pinMode(statusLedPin, OUTPUT);
// Buzzer
pinMode(buzzerPin, OUTPUT);
digitalWrite(buzzerPin, LOW);
Serial.begin(115200);
while (!Serial) { ; }
Serial.println("System starting...");
Serial.println("Beam: CLEAR=HIGH, BROKEN=LOW");
Serial.println("Present RFID tags to see UIDs.");
// RFID init
SPI.begin();
mfrc522.PCD_Init();
Serial.println("RFID reader initialized.");
delay(100);
}
void loop() {
delay(20); // small debounce / pacing
unsigned long now = millis();
// -------- Beam sensor handling --------
static int lastBeamState = HIGH; // assume clear at start
int beamRaw = digitalRead(beamPin);
bool beamBroken = (beamRaw == LOW);
// Mirror beam state on built-in LED (ON when broken)
digitalWrite(statusLedPin, beamBroken ? HIGH : LOW);
// Detect changes for logging and alarm latching
if (beamRaw != lastBeamState) {
if (beamRaw == LOW) {
Serial.println("Beam BROKEN (relay closed, pin LOW)");
} else {
Serial.println("Beam CLEAR (relay open, pin HIGH)");
}
}
// Latch alarm on CLEAR -> BROKEN
if (!alarmLatched && (lastBeamState == HIGH) && (beamRaw == LOW)) {
alarmLatched = true;
Serial.println("Alarm latched due to beam break.");
}
lastBeamState = beamRaw;
// -------- RFID handling (only needed if alarm is latched) --------
if (alarmLatched) {
if (checkRFIDForValidTag()) {
alarmLatched = false;
}
}
// -------- Buzzer chirp pattern --------
if (alarmLatched) {
unsigned long interval = buzzerState ? BUZZER_ON_TIME : BUZZER_OFF_TIME;
if (now - lastBuzzerToggle >= interval) {
buzzerState = !buzzerState;
lastBuzzerToggle = now;
}
digitalWrite(buzzerPin, buzzerState ? HIGH : LOW);
} else {
buzzerState = false;
digitalWrite(buzzerPin, LOW);
}
// -------- Distance sensor --------
unsigned int distance = sonar.ping_cm();
if (distance == 0) {
distance = MAX_DISTANCE + 1; // treat as "out of range"
}
Serial.print("Ping: ");
Serial.print(distance);
Serial.println(" cm");
int flipswitch = digitalRead(SWITCH_PIN);
// -------- LED strip behavior --------
if (alarmLatched) {
// Red/white strobe while alarm is active
if (now - lastStrobeToggle >= STROBE_INTERVAL) {
strobeState = !strobeState;
lastStrobeToggle = now;
}
fillStrip(strobeState ? red : white);
} else {
// Normal mode (no alarm)
if (flipswitch == HIGH) {
// Fade from yellow (far) to red (near) based on distance
rgb_color c = colorFromDistance(distance);
fillStrip(c);
} else {
// SWITCH DOWN: simple safe state
fillStrip(green);
}
}
// Final state for this loop
ledStrip.write(testing, NUMLEDS);
}