Overview
Summary
My project was an alarm clock that forces the user to get up and get active – the alarm will only stop ringing when the user goes to certain locations in their room in a specific, randomized order.
I noticed that I can only really wake up if I’m forced to get out of my bed and get moving. A lot of people also feel similarly, so it isn’t uncommon to place a phone alarm across the room to force one to get up and turn it off. But after that, it quite easy to slip back into bed and drift into sleep again. What if you had to go to multiple locations in your room, maybe in hard to reach nooks and crevices, in a specific order that is generated by the alarm? That way, you have to really get moving in order to truly turn it off. By that point, ideally, you won’t feel as strong of an urge to slip into bed.
Process
Getting the RFID scanner to work was the first hurdle I needed to pass. At first, I merely used female to male jumper cables to connect the scanner to the Arduino, which I expected to work perfectly. However, I was constantly getting error messages that no scanner was actually connected. Sometimes I got lucky and I would get a stray couple of bytes to show that something is hooked up before the same error messages would pop up again. I checked the wiring over and over again and replaced the scanner module multiple times. After a couple of hours, I was at my wit’s end and finally decided to solder the wires instead of just using jumper cables. After soldering, it worked perfectly. I still don’t know what the problem was, but if I didn’t decide to take the soldering approach, perhaps I would have opted to not use an RFID scanner at all. I’m really glad that it ended up working because the scanner ended up being a key part of this project’s appeal.
I didn’t wire my components with the understanding that I would later be putting in some kind of housing, I just wired it in the way that seemed the easiest and fastest at the moment. When it came to actually placing it in the box I cut out, I realized I would have to do a huge overhaul of the way I had everything organized, essentially tearing out all the wires and starting all over again. In future projects, I’ll keep in mind the final presentation while I design the hardware layout to save myself a lot of pain.
Discussion
Response
“The LED strips look a little messy on the outside. Maybe put something on top of them to diffuse the light?“
I totally agree. Currently, my LED strip is held on by its own stickiness, extra double-sided tape, and prayers. I tried to make it look as straight as possible, but it definitely could be a lot straighter and neater. My original hope was that I could use an LED strip that was wrapped in white/clear silicone, so it would nicely diffuse the lights while maintaining brightness, but I didn’t know if we had this in the Physical Computing Lab. Of course, it is an alarm so we do want the lights to be a little jarring, so maybe diffusing may not necessarily be the way to go. However, I think maybe it could be in a sort of housing so that the LED strip isn’t just nakedly sitting on the box.
“If the tags are placed permanently in [a] different location, maybe you could put the RFID scanner on the opposite side of your interface so the buttons don’t interfere with you holding the box against the tags.“
I also agree with this critique. I realized as I was putting all the wires and components into the box that maybe it would be hard to scan the tags from the front, given there are buttons and knobs. I tried it out by sticking a tag on the wall and trying to scan it, and it did work after I tilted the box a little bit. This is definitely a design flaw that I should have kept in mind. This is not something I actively thought about while building because I simulated the walls by just bringing the tags to the RFID scanner location. Maybe it would have been better to put the RFID facing the back, which is flat and can be brought up to the wall.
Self-Critique
I’m pretty happy with how the project turned out. Visually, it looks very similar to my original drawings/concepts. However, I would probably not have a hole for the RFID sensor in a more refined project. I put it in this prototype because I thought that I would want to see the exact place of the sensor for debugging purposes, and I was unsure if it could scan through the wood. Now that I know it actually has quite a considerable range, I would not put a hole there and would merely etch a symbol to let the user know that this is the location to scan at. This would look a lot cleaner than the version I have now. I also think that some of my code is a little hacky, for lack of a better word, and that its efficiency can be improved considerably. If given more time, I would consider cleaning up my code so that maybe the project would run smoother.
What I Learned
There were points in the project that if I decided to fully pivot there, I would have gotten it to a functioning state much faster. An example is when I noticed that the RTC wasn’t showing the correct time, and in fact, would generate random times at bootup. For almost a week, this issue didn’t improve because the library I was using simply wasn’t capable of properly flashing the correct time to the RTC. It wasn’t until after I finally used another library did it fix itself. However, if I was just more willing to switch libraries earlier on, I could have fixed this and focused on other stuff. So advice to both past and future self: don’t be afraid to have to redo things to get something to function, sometimes you’re going to have to pivot from what you are currently using to a totally new tool, and you’re going to have to be okay with that.
Next Steps
My original vision for this project was that the RFID would just be one component of many. I’d also have to play with other sensors to turn off the alarm as well. For example, the alarm would need a photoresistor to read values above a certain threshold, either by bringing the alarm to the light or by binging my phone flashlight up to it. This would end up as almost like a “bop-it” alarm clock, as you have to complete certain commands in rapid succession to turn it off. I still think this is a fun idea and is probably the approach I would take if I decide to keep working on it. Also, currently, the only way to “cancel” an alarm a user has already set up is by ripping out the battery. I would definitely make a reset/off/cancel button in an improvement of this project.
I would also like to integrate this with a way to measure and display information sleep as well, perhaps with a mobile/web app. It would be great to record the number of hours slept, probably by adding another button to set when the user goes to sleep and then tracking until the alarm is turned off. I think displaying this information on a graph and running some analytics on it could be extremely useful to the user when deciding how to change their sleeping habits.
Schematic
Code
/* Active Alarm * Neeharika Vogety (nvogety) * * * Summary: An alarm will ring, vibrate, and light up at a time that a user sets * to wake up at. The only way to turn off the alarm is to scan RFID tags set around * the room in a specific, randomly-generated order. The idea is to get the user up * and moving to turn off the alarm, rather than just hitting a button and going back to * sleep. * * Inputs: * * Arduino Pin | Input * 5 LED Strip Pin * 2 Button Pin * 9 RFID Pin * A1 Potentiometer Pin * * Outputs: * * Arduino pin | Output * 7 Vibrating Motor Pin * 4 Piezo Buzzer Pin */ #include <Wire.h> #include <Time.h> #include <LiquidCrystal_I2C.h> #include <RTClib.h> #include <SPI.h> #include <MFRC522.h> #include <FastLED.h> // Define important pins for RFID #define RST_PIN 9 #define SS_PIN 10 #define TASKSLEN 5 // Define length of tasks array, used throughout code // Define important constants for LED strip #define LED_PIN 5 #define NUM_LEDS 45 #define BRIGHTNESS 200 #define LED_TYPE WS2811 #define COLOR_ORDER GRB CRGB leds[NUM_LEDS]; #define UPDATES_PER_SECOND 100 CRGBPalette16 currentPalette; TBlendType currentBlending; typedef struct{ char *tagName; char *tagUID; } Tag; // An array of Tag structs that links together // the name of the tag and the ID of the tag. // If this is changed, must change TASKLEN at // the top! Tag tasks[TASKSLEN] = { {"A", "437B172845C81"}, {"B", "450B072845C80"}, {"C", "42FB172845C81"}, {"D", "461DF72845C80"}, {"E", "49ED972845C80"}, }; int nums[TASKSLEN]; // Create nums array int numOrder[TASKSLEN]; // Create num Order array int nOindex = 0; // Index to traverse num Order // Bools that we will use to execute certain parts of the code bool startGeneration = false; bool readRFID = false; bool setAlarm = true; bool alarmSet = false; // Hour and Minute, will set with RTC int alarmHour; int alarmMin; LiquidCrystal_I2C screen(0x27, 16, 2); //Create Screen object MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance DS1307 RTC; // Create RTC object // Initialize constant i/o pins const int BUTTONPIN = 2; const int POTPIN = A1; const int VIBRPIN = 7; const int BUZZERPIN = 4; void setup() { Serial.begin(9600); // Set up INPUTS AND OUTPUTS pinMode(BUTTONPIN, INPUT_PULLUP); pinMode(POTPIN, INPUT); pinMode(VIBRPIN, OUTPUT); pinMode(BUZZERPIN, OUTPUT); // Set up RFID SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 delay(4); mfrc522.PCD_DumpVersionToSerial(); // Make sure RFID is up and running // Start RTC RTC.begin(); //Set up LED String FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); FastLED.setBrightness( BRIGHTNESS ); currentPalette = RainbowStripeColors_p; currentBlending = NOBLEND; clearLEDs(); // Clear LCD screen and signal set up is over screen.init(); screen.backlight(); screen.home(); screen.print("Booting up.."); delay(1000); screen.clear(); } void loop() { // If we still need to set an alarm time, // display the current time and wait for button press // to set the hour, then the minute of the alarm, and // set the alarm if(setAlarm){ // Display time until button is pressed while(digitalRead(BUTTONPIN) == LOW){ DateTime now = RTC.now(); screen.clear(); screen.setCursor(0, 0); screen.print("Current Time:"); screen.setCursor(0, 1); if(now.hour() <= 9){ screen.print("0"); } screen.print(now.hour()); screen.print(":"); if(now.minute() <= 9){ screen.print("0"); } screen.print(now.minute()); screen.print(":"); if(now.second() <= 9){ screen.print("0"); } screen.print(now.second()); delay(1000); } delay(1000); // Allow user to set up hour of alarm until button is pressed again while(digitalRead(BUTTONPIN) == LOW){ screen.clear(); screen.setCursor(0, 0); screen.print("Set Alarm Hour:"); // Set alarm hour with potentiometer alarmHour = map(analogRead(POTPIN), 0, 1023, 0, 24); screen.setCursor(0, 1); if(alarmHour <= 9){ screen.print("0"); } screen.print(alarmHour); delay(250); } delay(1000); // Allow user to set up minute of alarm until button is pressed again while(digitalRead(BUTTONPIN) == LOW){ screen.clear(); screen.setCursor(0, 0); screen.print("Set Alarm Minute:"); // Set alarm minute with potentiometer alarmMin = map(analogRead(POTPIN), 0, 1023, 0, 60); screen.setCursor(0, 1); if(alarmMin <= 9){ screen.print("0"); } screen.print(alarmMin); delay(250); } delay(1000); // Show when alarm is set for screen.clear(); screen.setCursor(0, 0); screen.print("Alarm set for:"); screen.setCursor(0, 1); if(alarmHour <= 9){ screen.print("0"); } screen.print(alarmHour); screen.print(":"); if(alarmMin <= 9){ screen.print("0"); } screen.print(alarmMin); setAlarm = false; alarmSet = true; } // Keep checking if current hour and minute is what we set for the alarm if(alarmSet){ DateTime now = RTC.now(); if(now.hour() == alarmHour && now.minute() == alarmMin){ startGeneration = true; alarmSet = false; screen.clear(); screen.print("ALARM STARTED"); // Set off buzzer, will make a humming sound tone(BUZZERPIN, 100); vibrate(); vibrate(); vibrate(); Serial.print("ALARM STARTED!!!!!"); } } // If alarm went off, start to create the random list of Tags if(startGeneration){ // Fill nums in with just numbers counting from 0 up for(int i = 0; i < TASKSLEN; i++){ nums[i] = i; } // Form new numOrder array by grabbing different parts of numArray for(int currlen = TASKSLEN; currlen > 0; currlen--){ // Seed differently everytime randomSeed(analogRead(A0)); // Get random number, which will be the index for the number to grab from num int randi = random(currlen); numOrder[nOindex] = nums[randi]; nOindex++; // "Remove" the number we just picked from num by shifting over the other numbers // This will guaruntee we don't pick that number again for(int k = randi; k < currlen; k++){ nums[k] = nums[k+1]; } } // Loop through the tasks in the order that we generated for(int i = 0; i < TASKSLEN; i++){ screen.clear(); screen.print("GO TO "); screen.print(tasks[numOrder[i]].tagName); readRFID = true; while(readRFID){ // Keeping sounding the alarm, even while user is still scanning tags soundAlarm(); // Keep checking if a new tag has been shown if ( ! mfrc522.PICC_IsNewCardPresent()) { continue; } if ( ! mfrc522.PICC_ReadCardSerial()) { continue; } // Print the tag info scanned for debugging purposes Serial.print("CARD SCANNED!!!!!: "); String readtagID = ""; // The MIFARE PICCs that we use have 4 byte UID for ( uint8_t i = 0; i < 7; i++) { readtagID.concat(String(mfrc522.uid.uidByte[i], HEX)); // Adds the 4 bytes in a single String variable } readtagID.toUpperCase(); mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); // If the tag scanned is the correct one in the order specified. // move on to checking for the next tag if(readtagID == tasks[numOrder[i]].tagUID){ screen.clear(); if(i < TASKSLEN - 1){ screen.print("Good! Next one.."); vibrate(); screen.clear(); } readRFID = false; } } } // Show that user has finished screen.print("FINISHED"); noTone(BUZZERPIN); vibrate(); screen.clear(); clearLEDs(); startGeneration = false; setAlarm = true; loopCounter++; } } // What the user should see while alarm is going off, // start filling the LEDs with color void soundAlarm(){ static uint8_t startIndex = 0; startIndex = startIndex + 1; /* motion speed */ FillLEDsFromPaletteColors( startIndex); FastLED.show(); FastLED.delay(1000 / UPDATES_PER_SECOND); } // Fill LED strip based off of variables set at the beginning void FillLEDsFromPaletteColors( uint8_t colorIndex) { uint8_t brightness = 255; for( int i = 0; i < NUM_LEDS; i++) { leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending); colorIndex += 3; } } // Clear all the LEDs void clearLEDs(){ for( int i = 0; i < NUM_LEDS; i++) { leds[i] = CRGB::Black; } FastLED.show(); } // Pattern of vibration when alarm first goes off void vibrate(){ digitalWrite(VIBRPIN, HIGH); delay(1000); digitalWrite(VIBRPIN, LOW); delay(500); }
Comments are closed.