By Sharon Li
The corrective lenses tracker and holder allow an individual to store their contact lenses and glasses in the two separate compartments in addition to serving as a tracking device for how long weekly contact lenses have been opened.
Process Images and Review
During the beginning stages of developing my idea, I had a lot of components and functions on this box that didn’t provide any supplementary support but rather were just extra embellishments for design. As a result, I decided to simplify my box more for easier use and decided to add an extra side component to store my glasses since I have more than one corrective lens. I reduced the number of buttons to one for a much cleaner look and to have the display on the entire time. Furthermore, I was able to add additional parts to my box for better functionality, such as a real-time clock that can track the days as well as an IR sensor to track if the lid was closed or not.
Following this, Professor Zacharias was able to help me with the CAD design of this box for the final product and all of its features. Specifically, I was able to construct the false floor of my project so that it could hide all of the hardware, and users would be able to operate this box seamlessly and would not see any of the wires or the Arduino. It was difficult to decide on the dimensions of this box without knowing how I was able to fit all of the hardware inside the false floor. Therefore, I had to estimate and allot more space than needed in the case where it might not fit entirely.
While assembling the product after laser cutting the plywood using the CAD design, it was arduous to make sure that the code was working well. Meaning that I had to figure out the logistics of how I wanted this box to operate. Specifically, how I wanted the lid to function and how it would work in terms of tracking the days. As a result, I decided that the box would update itself at the end of the day on a daily basis even if the contacts were not used because my contacts are for a 7-day use regardless if I use them every day or not. I also had to do research here since initially, I did not know it was only for 7-day use, so I had to figure out a way to accommodate the fact that it can only be used for this certain time period. To solve this, I decided on the box updating automatically every night. By opening the lid, it would update automatically so users can see the most recent number of how many days the contacts have been opened.
While assembling the product after laser cutting the plywood using the CAD design, it was arduous to make sure that the code was working well. Meaning that I had to figure out the logistics of how I wanted this box to operate. Specifically, how I wanted the lid to function and how it would work in terms of tracking the days. As a result, I decided that the box would update itself at the end of the day on a daily basis even if the contacts were not used because my contacts are for a 7-day use regardless if I use them every day or not. I also had to do research here since initially, I did not know it was only for 7-day use, so I had to figure out a way to accommodate the fact that it can only be used for this certain time period. To solve this, I decided on the box updating automatically every night. By opening the lid, it would update automatically so users can see the most recent number of how many days the contacts have been opened.
During this process, I encountered many difficulties and problems when writing the code, as it would not show up on the display or the timing would not match up, and it would continue to count even after 7 days. To solve this problem, I added many booleans to track all the different variables that I didn’t expect to consider earlier.
Discussion
Despite my initial concern throughout the ideation process that I would not be able to brainstorm a viable product that would ultimately be useful for me, I am proud of my progress throughout this process. Especially seeing my project literally come out of the lines in my sketches into an actual and tangible product is lively. I satisfied my goals for this project since I was able to target a reoccurring problem I have with keeping track of my contacts and finding a place to store my glasses, so it’s like hitting two birds with one stone. It was super helpful to receive feedback from Professor Zacharias and my peers during the ideation process, and it helped me look at my project from a different perspective.
However, some improvements could be made to my project after seeing the final product. Specifically, during the final critique where my peer commented, “Portability if you want to bring it when you travel? Like is it possible to make it a bit flatter? Do you need such a big screen?”. I agree with this comment, as it was one of my biggest concerns while prototyping and figuring out the measurements. Specifically, it was difficult to estimate the space needed for the hardware. I would have loved to make it smaller so it would not take up as much space in one’s room, especially since the contact lens case is usually the size of an eraser. Another comment I agreed with was, “ What if you have contacts that are monthly/yearly? How easy would it be to change it?”. Adding more features to my box would have been helpful and added to its functionality. Since this box was tailored to me, I did not need to think about the lens past the seven-day use. However, it could be helpful to have a feature that could manually change the days the contacts can be used or, more generally, track any item that could be used.
After this project, I would definitely build another iteration of this project that heavily revolves around the concerns I had that were directly related to the critiques I received. For example, I would make the box smaller and more compact by using another microcontroller and a smaller LCD display. In addition, I would definitely try to add more to the programming side and allow users to change the days, amongst other things. Overall, I learned that I had difficulty coding this project, specifically integrating a time aspect into it. Furthermore, I enjoyed the hands-on aspect of building the project and laser cutting it, particularly the ideation portion of coming up with this idea and sketching it.
Functional Block Diagram and Schematic
Code
/* Corrective Lens Tracker and Holder Sharon Li The code below keeps track of the duration of time a pack of contact lens has been open for using real-time data information from a real time clock that is displayed on a LCD display. This tracker will update once every day either manually by the user when they open the lid of the box for the first time that day or automatically at 11:59PM. After 7 days (the maximum number of days a pair of contacts can be used for), the LCD display will warn users to open a new pair of contacts. The code below additionally includes a demo mode where 24 hours is converted to 10 seconds. Pin Map: Pin | role | Description ---------------------------------------- 2 | input | Arcade Push Button input A0 | input | IR Proximity Sensor input SCL | input | SCL pin on Real Time Clock (DS3231) SDA | input | SDA pin on Real Time Clock (DS3231) A4 | input | SCL pin on I2C LCD display A5 | input | SDA pin on I2C LCD display 5V | output| VL53L0X sensor power GND | input | Ground for all components Code Credit: RTC DS3231 code sourced from the DS3231 library example code. IR Proximity Sensor code sourced from the NewPing library example code. isLeapYear and changing from date format to day of the year code (Lines 65-66 & 102-109) sourced from https://stackoverflow.com/questions/19110675/calculating-day-of-year-from-date. */ #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C screen(0x27, 20, 4); #include <DS3231.h> DS3231 rtc(SDA, SCL); const int IRSENSOR = A0; const int BUTTONPIN = 2; int contactsLife = 0; bool lidReset = true; bool dayUpdated = false; bool oldContacts = false; unsigned long buttonStart; unsigned long elapsedTime; unsigned long regTimer; unsigned long timeChecker; int resetButton; Time t; int month; int year; int day; bool isLeapYear(int year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } void setup() { pinMode(IRSENSOR, INPUT); pinMode(BUTTONPIN, INPUT); Serial.begin(9600); screen.init(); screen.backlight(); rtc.begin(); //// The following lines can be uncommented to set the date and time // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(9, 49, 00); // Set the time to 12:00:00 (24hr format) // rtc.setDate(, 11, 2022); // Set the date to January 1st, 2014 } void loop() { /****************************************************************************************************** Code for updating the tracker using the IR Proximity Sensor or automatically and 7-day warning ******************************************************************************************************/ // Get data from the IR Proximity Sensor int lidSensor; lidSensor = analogRead(IRSENSOR); delay(1000); // Get data from the DS3231 t = rtc.getTime(); month = t.mon; day = t.date; year = t.year; // 2d table mapping the days of the year to each month int daysToMonth[2][12] = { { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }, }; // function that converts the date format to the day of the year int dayOfYear = daysToMonth[isLeapYear(year) ? 1 : 0][month - 1] + day; int contactsStart; //the constant date when the contacts are opened int startChecker = true; // if the start date is stored or not int contactsCurr = 0; //the most recent checked date int dayChecker; //checks what day it is if (startChecker) { // if it is the start date contactsStart = dayOfYear; // sets the start date to the current date startChecker = false; } if (lidSensor <= 50 and lidReset and not dayUpdated and not oldContacts) { // adds one day if lid opened lidReset = false; contactsLife = contactsLife + 1; dayUpdated = true; } if (dayUpdated == false and contactsCurr - dayChecker >= 1 and not oldContacts) { // adds one day automatically contactsLife = contactsLife + 1; dayUpdated = true; } if (contactsCurr - dayChecker >= 1 and not oldContacts) { // checks if it has been one day dayUpdated = false; timeChecker = regTimer; } //// The following lines can be uncommented to start DEMO MODE and comment lines 111-135 // regTimer = millis(); // if (lidSensor <= 50 and lidReset and not dayUpdated and not oldContacts) { // adds one day if lid opened // lidReset = false; // contactsLife = contactsLife + 1; // dayUpdated = true; // } // // if (dayUpdated == false and regTimer - timeChecker > 9000 and not oldContacts) { // adds one day automatically // contactsLife = contactsLife + 1; // dayUpdated = true; // } // // if (regTimer - timeChecker >= 10000 and not oldContacts) { // checks if it has been 10 secs // dayUpdated = false; // timeChecker = regTimer; // } if (lidSensor > 50 and not lidReset and not oldContacts) { // closed lid lidReset = true; } if (contactsLife >= 7) { // show warning message after it has been 7 days oldContacts = true; screen.clear(); screen.home(); screen.print("Time For New Contacts!"); while (resetButton == LOW) { // if the button is pressed to reset, resets the tracker resetButton = digitalRead(BUTTONPIN); } contactsLife = 0; oldContacts = false; startChecker = true; delay(1000); resetButton = LOW; } /****************************************************************************************************** Code for arcade button functions and LCD display resets ******************************************************************************************************/ resetButton = digitalRead(BUTTONPIN); Serial.println(resetButton); if (resetButton == HIGH and buttonStart == 0) { // starts timer when button is pressed buttonStart = millis(); } if (resetButton == HIGH and buttonStart != 0) { // pressed button and timer is on resetPrint(); elapsedTime = millis(); if (elapsedTime - buttonStart >= 3000) { buttonStart = 0; contactsLife = 0; oldContacts = false; screen.clear(); defaultPrint(); } else { defaultPrint(); } } if (resetButton == LOW) { // when button is not pressed defaultPrint(); clearPrint(); } } // function that displays the reset screen on the LCD display void resetPrint() { screen.setCursor(0, 2); screen.print(String("Hold for 3 seconds")); screen.setCursor(0, 3); screen.print(String("to reset")); } // function that displays the default screen on the LCD display void defaultPrint() { screen.home(); screen.print(String(" Contacts Life Span:")); screen.setCursor(7, 1); screen.print(contactsLife + String(" day(s)")); } // function that clears the screen on the LCD display due to some bugs void clearPrint() { screen.setCursor(0, 2); screen.print(String(" ")); screen.setCursor(0, 3); screen.print(String(" ")); }