Introduction
What We Built
Our project is a ladder-mounted alarm that warns people when they get too close to the ladder. The client straps one alarm on each side of the ladder, covering the required angles while allowing Jason to climb on without setting off the alarm. It notices when people walk too close, and it flashes a red light more rapidly depending on how close the person is to the ladder. In addition, it shines a flashlight on the ground and plays a loud warning until the unlucky passerby backs off.
* One-paragraph description of what the project does in plain and spare language * One overall final image * At least one brief movie showing final project in action * At least four detail images * All images captioned * Images have alt text as needed (may not be necessary if caption is descriptive) * Narrative sketch of how the project will be used
The final devices that we made! This is from the top view where you can see all the inputs and outputs. We have two sensors and three outputs: a speaker, LED strip, and a laser.
Here you can see the bottom view of the device. The laser is not attached to the servo. We did this on purpose so that when the servo rotates, it shakes the laser and allows it to cast the laser everywhere on the ground.
Here is the right hand-side of the device. We designed the device to have a simple on and off switch with the battery inside of it so it does not get in the way of the device when it is on the ladder.
Here is a simple picture of the overall device!
Here is a quick picture comparing the device's size in-comparision to a hand. We wanted to make the device portable and compact enough to be convinient.
Here is the video of our device working. As a person gets closer to the device, the sensors work together and once they detect movement, it triggers the device to play loud music and flash red LED.
How We Got Here
Because our project device was rather unique compared to what other groups were building and what we’ve seen before on the market, our team decided to first build the overall main electrical system while Tim CADed and printed the housing. After putting together a rough physical system and putting that into the housing and seeing how everything fit, we realize that we needed to adjust not only the system itself as we had other components that we have not yet implemented such as the laser and the battery, we also have to adjust the housing height as everything was crammed in we were not physically able to keep the cover on without the speaker being in the way. From there, we continued working on the physical electrical system and added new features file continuously testing while Tim designed the second housing prototype. The second housing was a lot better, but there were some areas that we needed to fix such as sanding down supports. After finalizing the housing itself, we worked on testing our code and revising until the sensors were working together for our project.
From our first presentation, we got a lot of feedback in terms of not necessarily the device itself, but more of the usage concern. Some people had questions about the orientation or even the way the device would be attached to the ladder and had us take these different perspectives into consideration when designing the housing itself as well. From there, we designed the housing to be attachable to Velcro so that Jayson could easily put it on ladders and take it off when needed.
Process
At least six images illustrating your process * Discussion about your decisionmaking as a team and any breakthrough or breakdown moments you had * Discussion about the extent to which you followed or didn't follow your original schedule
This is a picture of our initial prototype after we build the physical system. We placed the system in the housing and quickly realized that we needed to work on figuring out the best way to fit everything needed. After multiple rounds of discussion and brainstorming, we realized that we needed to improve our housing dimensions to better accommodate additional elements such as the batteries that we haven't implemented yet in the system.
Here, we show the physical set up that is under the speaker. As you can tell, all the wires and element are crammed. It was difficult for us to get all the wires to fit with all the housing supports in the way.
Tim printed a new housing for our project and this one had much more room for no only the physical system but for additional wires as well. This allowed us to start working on the battery inputs as the laser aspect of our project. This helped us get back on schedule with getting the prototype together.
The earliest prototype, before we switched from light to speaker as our main focus.
Conclusions and Reflections
Discussion addresses all prompts below coherently and cogently, and is at least 400 words long:
* Salient findings from the final crit, which emerged from discussion and/or written feedback.
Quote feedback verbatim. * Major takeaways from working with a person with disability
* Any concluding thoughts you have about the project, lessons learned, etc.
Reflection: Overall, our project was pretty successful in what we wanted it to accomplish: being so loud and noticeable that people pay attention to where they are going. The sound and the lights both managed to stun visitors and students alike, and we are confident they will affect the distracted student body just the same.
However, one concern a few of the visitors noted was that the sound could be TOO disruptive in a school environment. One professor stated that we were "the most successful" out of all the alarm-based projects, but also the "most offensive project". The loud noise and lights could cause chaos in a crowded hallway where many people are passing by regardless, or be too annoying for a quiet classroom setting. This would limit the use-case a little too much. Another thing that we would consider if given more time is making the light detachable, as currently people can only see the warnings if they get very close to the ladder, which slightly defeats the purpose of an alarm. We also noticed that the ultrasonic ranger we used was way too imprecise and lacked the accuracy necessary to actually record if people walked by. Although the range is stated to be in the meters, we noticed a fall off in terms of accuracy past 40cm, and had frequent misfires in the 50cm range. As such, people don't have enough time to move out of the way even if they notice the warnings. Another big thing we would add would be "having a way for the end user to interact with and change settings on the device." This would solve the issue of the limited use case and make it easier for the person using the device to deal with differing situations. Perhaps there would be a dial or knob to switch sounds/volume or adjust distance. On another note, one visitor praised the "retro" look of the device and loved how it looked like a speaker or Walkman.
In conclusion, we were plenty proud of the work we put out. We managed to find a problem that was solvable within the context of this Physical Computing class without overlapping too much with what Jason already does. Working with a group, one issue we did end up having was not being able to work on the project all at the same time, as everyone was really busy over the two weeks of the final project. This was especially true closer to the end of the project, where work was piling up on all fronts. Regardless, we managed to finish on time and get some rest before presenting in front of the class.
Technical Details (Schematic)
Technical Details (Code)
/* * =================================================================
* PROJECT: Sentry Security System (Motion & Distance Triggered)
* GOAL: * - Monitor a "Safe Zone" using an Ultrasonic sensor and PIR Motion sensor.
* - ALERT ZONE (250cm): Trigger orange flashing lights and lower volume MP3.
* - DANGER ZONE (100cm + Motion): Trigger red fast-flashing lights,
* max volume MP3, and a motorized "shaking" laser pointer. *
* ARDUINO PINOUT: * - Pin 2: PIR Motion Sensor (Input)
* - Pin 3: Laser Pointer (Output via Transistor/Relay) * - Pin 4: Motion Status LED (Output) * - Pin 5: Servo Signal (PWM)
* - Pin 6: NeoPixel Data Pin
* - Pin 10: Software Serial RX (Connect to DFPlayer TX)
* - Pin 11: Software Serial TX (Connect to DFPlayer RX via 1k Resistor)
* - Pin 12: HC-SR04 Trig Pin * - Pin 13: HC-SR04 Echo Pin *
* DFPLAYER MINI PINOUT (Physical Pins): * - VCC: 5V (External power recommended)
* - GND: Ground (Shared with Arduino) * - RX: To Arduino Pin 11 (via 1k Resistor)
* - TX: To Arduino Pin 10
* - SPK1: Speaker Terminal (+)
* - SPK2: Speaker Terminal (-)
* ================================================================= */
#include <Servo.h>
#include <Adafruit_NeoPixel.h>
#include <DFMiniMp3.h>
#include <SoftwareSerial.h>
class Mp3Notify;
Servo shakeServo;
SoftwareSerial secondarySerial(10, 11); // RX, TX
typedef DFMiniMp3<SoftwareSerial, Mp3Notify> DfMp3;
DfMp3 dfmp3(secondarySerial);
class Mp3Notify {
public:
static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) {
if (source & DfMp3_PlaySources_Sd) Serial.print("SD Card, ");
Serial.println(action);
}
static void OnError([[maybe_unused]] DfMp3& mp3, uint16_t errorCode) {
Serial.print("Com Error "); Serial.println(errorCode);
}
static void OnPlayFinished([[maybe_unused]] DfMp3& mp3, [[maybe_unused]] DfMp3_PlaySources source, uint16_t track) {
Serial.print("Finished #"); Serial.println(track);
}
static void OnPlaySourceOnline([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source) { PrintlnSourceAction(source, "online"); }
static void OnPlaySourceInserted([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source) { PrintlnSourceAction(source, "inserted"); }
static void OnPlaySourceRemoved([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source) { PrintlnSourceAction(source, "removed"); }
};
// ------------------- PINS & CONFIG -------------------
const int motionPin = 2;
const int laserPointer = 3;
const int motionLed = 4;
const int servoMotion = 5;
const int trigPin = 12;
const int echoPin = 13;
#define LED_PIN 6
#define NUMPIXELS 16
Adafruit_NeoPixel strip(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
const int alertDistance = 250;
const int dangerDistance = 100;
// State Tracking
bool isAudioActive = false;
unsigned long lastPingTime = 0;
const int pingInterval = 50;
// Servo Settings
int centerPos = 90;
int shakeRange = 30;
int shakeSpeed = 15;
int shakeDirection = 1;
int currentPos = centerPos;
unsigned long lastShakeTime = 0;
void setup() {
Serial.begin(115200);
pinMode(motionLed, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(motionPin, INPUT);
pinMode(laserPointer, OUTPUT);
shakeServo.attach(servoMotion);
shakeServo.write(centerPos);
strip.begin();
strip.show();
Serial.println("Initializing MP3...");
dfmp3.begin();
dfmp3.setVolume(80);
delay(500);
Serial.println("System Ready.");
}
long getDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 25000);
if (duration == 0) return 999;
return duration * 0.034 / 2;
}
void shakeLaser() {
if (millis() - lastShakeTime > shakeSpeed) {
lastShakeTime = millis();
currentPos += shakeDirection;
if (currentPos > centerPos + shakeRange || currentPos < centerPos - shakeRange) {
shakeDirection *= -1;
}
shakeServo.write(currentPos);
}
}
void loop() {
dfmp3.loop();
static long distance = 999;
if (millis() - lastPingTime >= pingInterval) {
lastPingTime = millis();
distance = getDistance();
}
int motionDetected = digitalRead(motionPin);
digitalWrite(motionLed, motionDetected);
bool inDanger = (distance > 0 && distance < dangerDistance && motionDetected == HIGH);
bool inAlert = (distance > 0 && distance < alertDistance);
// ---------------- LOGIC ENGINE ----------------
if (inDanger) {
// DANGER ZONE: Full volume, laser shake, fast red flash
if (!isAudioActive) {
dfmp3.playGlobalTrack(1);
isAudioActive = true;
}
dfmp3.setVolume(100);
shakeLaser();
digitalWrite(laserPointer, HIGH);
flashNeoPixels(255, 0, 0, 50);
}
else if (inAlert) {
// ALERT ZONE: Lower volume, no laser, slow orange flash
if (!isAudioActive) {
dfmp3.playGlobalTrack(1);
isAudioActive = true;
}
dfmp3.setVolume(60);
digitalWrite(laserPointer, LOW);
shakeServo.write(centerPos);
flashNeoPixels(255, 50, 0, 150);
}
else {
// SAFE ZONE: Audio off, lights off
if (isAudioActive) {
dfmp3.stop();
isAudioActive = false;
}
digitalWrite(laserPointer, LOW);
shakeServo.write(centerPos);
strip.clear();
strip.show();
}
}
void flashNeoPixels(int r, int g, int b, int speedDelay) {
static unsigned long lastFlash = 0;
static bool ledState = false;
if (millis() - lastFlash > speedDelay) {
lastFlash = millis();
ledState = !ledState;
if (ledState) {
for (int i = 0; i < NUMPIXELS; i++) strip.setPixelColor(i, strip.Color(r, g, b));
} else {
strip.clear();
}
strip.show();
}
}