Brief Explanation

A physical reminder with customizable timing options ranging from 28 seconds to 24 hours.

Images

 

top of the reminder which displays the current timer setting

The switch on top activates a sound alarm if it is turned on. The reminder uses a 9V battery to power it.

(usage example – reminding to drink water)

Place next to object you want to be reminded about, and set the timer to the desired reminder frequency.

Once the timer runs out, the alarm will sound (quiet mode uses LEDs as shown in picture but you can have it use sound as well – plays a little song instead of lighting up). After removing and returning the water bottle from in front of the sensors, the timer resets.

If the water bottle is removed before the timer runs out and the alarm goes off, the timer is reset.

Process Images and Review

I began by attempting to use HC-06 Bluetooth modules to be able to communicate between a sensor and the actual “reminder” which would sound the alarm. That way the sensor could be a few feet from you but the alarm would go off right next to you. Tried switching to the nRF24L01 but the devices wouldn’t connect with each other

Tried to use the Arduino nano for the reminder but couldn’t get it to work reliably so I decided to use the regular Arduino. I was trying to create a more compact design, but since this is the first iteration, I thought I should focus more on the functionality

This was the separate sensor portion from when I was attempting to use the Bluetooth chips to communicate between two Arduinos

Got rid of the bluetooth chips and made it compact by using only one Arduino. Although not my original design, I thought the bluetooth chips would be too finicky and unstable, so I decided to eliminate them entirely.

I added an LCD screen that shows the number of hours/minutes/seconds that the timer is currently set to. This was the final prototype before I started soldering and creating the housing.

Everything all soldered up

Discussion

Quotes from crit:

  • “I like that there are a lot of parts that you can play with on the box and it looks nice”
  • “Good form factor and clean presentation.”
  • “I like how you have the knobs and the smoky arcyllic; I also like the quiet and sound setting.”
  • “I like the series of potentiometers that can be used to customize the interaction. Also, the box is a nice form factor besides the battery being outside.”

Reflection:

I think that people enjoyed the aesthetic of the arctic frost acrylic housing around the circuitry for this project. It created a slight techy view into the inner workings of the box, while also making the LED usage inside the box look really cool. I think that one of the components that I should have worried about was the battery. I wanted this project to not be constricted by having to be plugged in but didn’t think far enough ahead, in terms of housing, for the battery’s location.

As for my own goals that I set for myself regarding the final outcome of this project, I feel good about my final product, even though I encountered a few hiccups along the way. I wanted to use the Bluetooth chips because they would allow some proximity sensor to detect the lack of motion then send that data to another chip that was in my pocket, so I would be able to receive the alarm even if I was in the other room.

I got a bit fixated on the usage of the Bluetooth in my project when I could have been creating something that would do essentially the same things I wanted it to do without Bluetooth with more simplicity and with fewer errors. After seeing all of the other projects, I really think that my project and Nathan’s project (see next paragraph) could be brought together and used to create a really effective reminder. The adjustable timing from my project would have been great with his box. If each slot had a timer for when you’d have to have it back in the box by, the box could remind you to either take things out of the box and/or remind you to put things back in the box. This double functionality could be used to help remind you of things to remember to grab in the morning and for reminding you to replace your things at night.

Nathan’s project – a box with compartments and it the alarm would go off if there was something missing from its area. He used this to organize all of his jewelry because he has quite a bit. Most were rings and bracelets, so I can see how it would be easy to lose them.

Schematic

 

 

Code

/*
   Eric Mendez
   emendez
   Project 2: "The Reminder"

   Description: Detects the lack of motion of an object for
   programmable time intervals to help remind the user to do 
   a certain task at each of those time intervals.

   Inputs: switch(quiet mode), ultrasonic ranger(distance measuring),
           2 potentiometers (hour and min)
   Outputs: speaker, LED strip, LCD screen
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <NewPing.h>
#include <TimerFreeTone.h>
#include <PololuLedStrip.h>

// set up devices and set const variables
LiquidCrystal_I2C lcd(0x3F, 16, 2);

#define TRIGGER_PIN  9  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     8  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

// Create an ledStrip object and specify the pin it will use.
PololuLedStrip<6> ledStrip;

// Create a buffer for holding the colors (3 bytes per color).
#define LED_COUNT 25
rgb_color colors[LED_COUNT];


const int QUIET_SWITCH = 7;
const int LED = 6;
const int SPEAKER = 5;
const int POT_PIN_HOUR = A1;
const int POT_PIN_MIN = A2;

const unsigned long SCALE_POT = 86400000;
const unsigned long HOUR_MS = (unsigned long)60*(unsigned long)60*(unsigned long)1000;
const unsigned long MIN_MS = (unsigned long)60*(unsigned long)1000;
const unsigned long SEC_MS = (unsigned long)1000;

// set up global changable variables
unsigned long reset_threshold = 0;
unsigned long run_time = 0;
unsigned long prev_time = 0;
unsigned long led_start_time = 0;

bool led_on = false;

int quietMode = 0;
int sonar_zeros_in_row = 0;

// note intervals for song
int a3 = 220;
int Asharp3 = 233;
int b3 = 246;
int c4 = 261;
int csharp4 = 277;
int d4 = 293;
int dsharp4 = 311;
int e4 = 329;
int f4 = 349;
int fsharp4 = 369;
int g4 = 392;
int gsharp4 = 415;
int a4 = 440;
int asharp4 = 466;
int b4 = 493;
int c5 = 523;
int eighth = 125;
int quarter = 250;
int half = 500;
int melody[] = { c5, b4, a4, g4, g4, a4 };
int duration[] = {(quarter + half), quarter, half, half,
                  (half + eighth), (half + half)
                 };

void setup()
{
  Serial.begin(9600);

  // start LCD screen
  lcd.init();
  lcd.backlight();
  lcd.home();

  // set modes for all output/inputs
  pinMode(QUIET_SWITCH, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  pinMode(SPEAKER, OUTPUT);
  pinMode(POT_PIN_HOUR, INPUT);
  pinMode(POT_PIN_MIN, INPUT);

  // inital state of speaker
  digitalWrite(SPEAKER, LOW);
}

void loop()
{
  char data = '0'; // state
  int distance = sonar.ping_cm(); // ultrasonic ranger
  int deltaX = 5; // distnance between sonar and object
  int potVal_hour = analogRead(POT_PIN_HOUR); // knob for hour increment
  int potVal_min = analogRead(POT_PIN_MIN); // knob for min increment
  bool movement = false; // if object was moved -> true (deltaX > detection_zone)

  // map values from potentiometers to hour/min/sec scale - range = [14sec, 24 hours]
  reset_threshold = calculate_threshold(potVal_hour, potVal_min);
  
  // translate potVal to ms scale (1 - reset_threshold)
  lcd.clear();
  lcd.print("hour: ");
  lcd.print(reset_threshold / HOUR_MS);
  lcd.setCursor(0,1);
  lcd.print("min: ");
  lcd.print((reset_threshold / MIN_MS) % (unsigned long)60);
  lcd.setCursor(9,1);
  lcd.print("sec: ");
  lcd.print((reset_threshold / SEC_MS) % (unsigned long)60);

  run_time = millis();

  // Quiet mode detection
  if (digitalRead(QUIET_SWITCH) == HIGH) {
    // mode - true (LEDs)
    quietMode = 1;
  } else {
    // mode - false (Sound)
    quietMode = 0;
  }

  // Sonar distance detection (lack of motion detection)
  if (distance > deltaX) {
    sonar_zeros_in_row += 1; // smoothing fn
    if (sonar_zeros_in_row == 3) { // 3 in a row to avoid false positives
      // object was moved for sure
      movement = true;
      data = '1'; // change state
      sonar_zeros_in_row = 0; // reset this smoothing variable
    } else {
      // stay in the same state of '0'
      data = '0';
    }
  } else {
    // distance stays under 5
    movement = false;
    sonar_zeros_in_row = 0;
    data = '0'; // stay in the same state of '0'
  }

  // object moved - set state
  if (movement == true) {
    data = '2'; // state of object has moved
  }
  
  // object has been unmoved for too long
  if ((run_time - prev_time) >= reset_threshold) {
    prev_time = run_time; // reset timers
    data = '1'; // change state to '1' - sound the alarm
  }

  // reset led after 5 seconds
  if (led_on == true && (run_time - led_start_time) > 5000) {
    led_on = false;
    // turn off LEDs
    for (int i = 0; i < LED_COUNT; i++)
    {
      colors[i] = rgb_color(0, 0, 0);
    }
    ledStrip.write(colors, LED_COUNT);
  }

  // STATE '1'
  if (data == '1') {
    if (quietMode == 1) {
      // quiet alarm
      led_start_time = run_time;
      led_on = true;
      
      // upload rainbow color based on time to LEDs
      byte time = millis() >> 2;
      for (uint16_t i = 0; i < LED_COUNT; i++)
      {
        byte x = time - 8 * i;
        colors[i] = rgb_color(x, 255 - x, x);
      }

      // Write the colors to the LED strip.
      ledStrip.write(colors, LED_COUNT);
      delay(10);
      
    } else {
      // play sound alarm
      for (int thisNote = 0; thisNote < 6; thisNote++) {
        // Loop through the notes in the array.
        TimerFreeTone(SPEAKER, melody[thisNote], duration[thisNote]);

        // Play thisNote for its coresponding duration.
        delay(50); // Short delay between notes.
      }
    }
  // STATE '2' - reset reminder
  } else if (data == '2') {
    prev_time = run_time;
  // STATE '0' - do nothing
  } else if (data == '0') {
    Serial.print("waiting");
  }
  Serial.println("");
}

/*    Usage: Function used to scale potentiometer values (2 of them - one for
 * hours and one for min) to a scale of [14sec, 24 hours] as evenly as 
 * possible
 * map potvals (0-1023)  
 */
unsigned long calculate_threshold(int potVal_hour, int potVal_min) {
  unsigned long one_percent_hour = SCALE_POT / 100;
  unsigned long one_percent_min = SCALE_POT / (100 * 60);
  unsigned long result_hour;
  unsigned long result_min;

  float hour_percent = ((float)potVal_hour / 1023.0) * 100;
  float min_percent = ((float)potVal_min / 409.0) * 100;

  result_hour = (unsigned long)hour_percent * one_percent_hour;
  result_min = (unsigned long)min_percent * one_percent_min;

  return result_hour + result_min;
}