elpratt@andrew.cmu.edu – Intro to Physical Computing: Student Work spring 2019 https://courses.ideate.cmu.edu/60-223/s2019/work Intro to Physical Computing: Student Work Wed, 15 Sep 2021 20:28:12 +0000 en-US hourly 1 https://wordpress.org/?v=5.0.21 Interactive Itinerary by Team Irv: final documentation https://courses.ideate.cmu.edu/60-223/s2019/work/interactive-itinerary-by-team-irv-final-documentation/ Fri, 10 May 2019 21:07:53 +0000 https://courses.ideate.cmu.edu/60-223/s2019/work/?p=7648 Introduction

For our final project, our team was paired with an older friend, Irv, to develop a “convenience machine” he could use to improve his life. Over the course of a month, we interviewed him on his daily activities, developed a prototype, and refined a final model that Irv could take home and use. By employing methods of Physical Computing, including programming, circuitry, and physical fabrication, we created an “interactive itinerary” device unique to Irv’s busy lifestyle.

What we built

The Interactive Itinerary is a digital reminder system (think Google Calendar) that feels like an analog device. The user can set alarms for tasks or events without having to type on a small and sensitive touchscreen. Instead, the user can write down the task on a piece of paper and set the alarm using built in knobs.
The interactive itinerary prototype has 3 key components: 1) Two knobs that set the task and alarm 2) the digital display that shows task, time, and set time 3) a vibrating motor that acts as an alarm. To use the interactive itinerary, the user writes down a task on a piece of paper with an empty list from 1 – 10. Using the task knob, the user can turn to the desired task number turn the alarm on. Then, they would set the time using the time knob. When the alarm starts to buzz, the user can turn off the alarm with the task knob.

Outer housing of itinerary is bound with elastic. The knobs and buttons are protected by the sides but still accessible without having to open the device.

Inside of itinerary displays an LCD screen, casing for electronics, and notepad.

 

“Task” and “time” knobs for programming the device, indicator LED, and sliding mechanism to access electronics.

The top side of the electronics housing reveals the on/off button, “snooze” button for offsetting an alarm, and charging port.

A small manual is mounted under the notepad for troubleshooting and quick reference.

Sliding mechanism allows access to RTC for battery changes, arduino reset button, and any other troubleshooting issues.

How it’s used:

On a normal day, Irv wakes up and unplugs the device from the charging port. On the notepad, he writes down his tasks for the day and the time they occur (i.e., medications, tennis meetings, cultural events). He can then use the knobs on the device to set reminders for the tasks he would like to be reminded of. Irv then closes the journal and takes it with him throughout the day. When a reminder goes off, the journal will buzz and flash, and the task will appear on screen. He can then press a button to turn off the alert, or push “snooze” to delay the reminder for another 15 minutes.

How we got here

Following the formative critique phase of this project, our team created a list of milestones we intended to hit for our final meeting with Irv. After showcasing our first prototype at the formative critique to Irv, we learned that a 15 minute snooze button would be a useful addition to the device. We learned that Irv preferred to set alarms in military time and would like an on/off switch on the device to conserve power.

We created a to do list with Irv to ensure that the final product suits his needs and ranked it based on importance.

The snooze button and on/off button were relatively easy to set up. The most important part about the snooze and on/off button is picking a button that has the right tactile feeling. After the formative critique, we went to the physical computing lab and pulled out many button options for Irv to test. He settled on a red momentary push button for the snooze button and a black latching push button for the on/off switch.

Irv tests different buttons for the new features on his interactive itinerary.

The next thing we wanted to add to the interactive itinerary is displaying the task “home page” when the alarm for that task goes off. This feature, which wasn’t in our first iteration, makes sense because when the alarm goes off, we would want to know which task alarm was going off. So, when the alarm goes off now, the task number that is ringing is also displayed on the LCD. Without this feature, the user would have to look at the written list of tasks and check each alarm time to see which task was going off.

 

In order to manage all our coding iterations and keep track of our goals, we wrote comments on our new versions to communicate what was working, what wasn’t, and what our next steps should be.

To make the device portable, we intended to make the device battery powered. We ordered a lithium ion battery and a chip so that Irv can charge the device at night. The chip ensures that the battery charges without overcharging the lithium ion battery. After setting up the battery, we soldered the on/off switch to the battery, which acts as an on/off switch for the device. SInce the lithium ion battery is quite large, our goal to make the device smaller was getting harder.

Once all the necessary components were bought and collected, we laid out the device components to determine the best way to stack the device to minimize the space. As shown in the picture below, the device would already be very cramped, even before soldering everything together. Since we were no longer considering bootloading our device onto a smaller device, we had to stick to the arduino uno. So at this point in the process, our goal to make the device “pocket-sized” was becoming less and less feasible.

In an ideal set up, the LCD screen would sit at the top of the device. The charging port is in the top left of the box. The snooze button and the on/off button would rest on the top, closer to the spine of the box.

 

While we knew what the general layout of our itinerary would be, we explored ways we could configure the electronic and tactile components to save space. We also thought of ways we could construct a sliding mechanism with lasercut material that would allow the electronics to be accessible without force.

While designing the prototype for the device casing, we considered several materials for the electronic housing. Acrylic, while sturdy and aesthetically pleasing, is prone to shattering. So if Irv decided to put this device in his back pocket, or applied too much pressure to it, it might crack under pressure, rendering the casing useless. Styrene is a plastic that is a bit more flexible but sturdy as well. Ultimately, styrene would not have been ideal to use as our electronic casing because we needed to make a case that had precise cuts and we would not be able to laser cut styrene. So, we decided that ⅛” birch plywood was the best material to use for the device. We also decided to include a sliding lid on the electronic casing so that if Irv needed to replace the RTC battery or reset the arduino to troubleshoot.

The sliding mechanism consisted of two pieces of plywood glued together that fit into the top facing of the case. To keep the lid on, a support bar was built under the top facing. That way, the lid can rest on the support bar.

In addition, the laser cutters at TechSpark burn more, cut slower, and are more volatile than the laser cutters in IDeATe. Luckily, the first print was just a prototype; so we planned on printing the final casing in IDeATe. The first prototype was also larger than we needed. There was a lot of room inside the casing. We were able to make the case thinner and narrower. While the notebook would still not be pocket-sized, it was still considerably smaller.

After considering different methods of fabrication for the outer casing, we decided traditional “bookbinding” techniques would best fit Irv’s aesthetic. Inspired by moleskine journals, we used flexible chipboard, faux leather, and elastic to create a housing that would be sturdy, comfortable, and stylish.

Conclusion

After the final crit, we added one last feature to our box because of a comment made to “make the alarm stronger” if it couldn’t be kept in his pocket. Since we were planning to make the box small, we didn’t account for possible issues if it was too large to fit into a pocket. Some of these issues would be would Irv notice the alarm going off if it wasn’t on his person. Our solution was to add a small LED next to the task and time knobs that would blink at the same rate that the buzzer would be going off. This would allow Irv to see the alarm going off as well as feel it. As he’s told us that his hearing isn’t the best, we thought we’d try to stimulate his other senses with the alarm.

Working with Irv was more than just an opportunity to gain insight on the life of an older person, but a beneficial experience in collaborating with a client. Not only did learning about Irv’s lifestyle allow us to empathize with his daily needs, it also taught us how to iterate and design under constraints that can assist virtually anyone. While the itinerary was developed for his particular lifestyle and activities, all of us can benefit from a method of keeping track of lists with time notifications. In principle, this project was a great introduction to universal design. By solving the problems of overlooked populations rather than the “average person,” we can innovate more effectively and inclusively.

Moreover, we believe that having a person to design for other than ourselves pushed us further to create something functional and intuitive. Since we realized Irv wouldn’t have the means to fix the RTC if it reset, for example, we decided late into the project to build in a time-setting function into the program. This mindset also prompted us to add in a sliding compartment to access the electronics, a “sleep” mode to save power, and a reference manual for troubleshooting. If we hadn’t had an actual client to work with, it would have been easier to let these considerations slide when you know you can can quickly reupload, solder or glue something back together. Knowing that Irv will be keeping this in his home and hopefully trying it out, we feel more confident knowing that we built in features to extend the project’s lifespan.

Code and Files

schematic

Code
/*  Reminder - Final Project
    Eliza Pratt
    Helen Yu
    Eric Mendez

***********************************************************
description:
  Use "Task" and "Time" button knobs to set alarms throughout the day. The LCD display shows
  the current task (1 to 9) and the set alarm time. If the task button is pushed, the alarm
  is turned on. There is a snooze button as well, so if you'd like to be snooze the alarm, the
  button adds 15 min to the on-going alarm. The display will reflect that the alarm was snoozed.
  

Pin mapping:
  - The task and time knobs have 3 input pins each and those are pins 2-7
  - The snooze button is 8
  - The buzzer pin is 9
  - The pin for the LED is 11
  - The SCA/SCL pins are used on both the LCD screen and RTC (real time clock)
  - If adding a Lipo battery and power regulating chip (see our schematic)
    - use a switch to interupt the connection from the chip to Vin on the Arduino

example code used:
  - Used examples from TimeLib, LiquidCrystal, DS1307RTC, and Encoder to help set up
  their usage in this project.

***********************************************************
*/
#include <Wire.h>
#include <TimeLib.h>
#include <LiquidCrystal_I2C.h>
#include <DS1307RTC.h>
#include <Encoder.h>

// set up lcd
LiquidCrystal_I2C screen(0x27, 16, 2);

// time elements
tmElements_t tm;

Encoder taskKnob(2, 4);
Encoder timeKnob(3, 6);

// task and time knobs / buttons
const int TASK_BUTTON = 5; // yellow wire
const int TIME_BUTTON = 7; // yellow wire
const int SNOOZE_BUTTON = 8; // white wire
const int MOTORPIN = 9;
const int LEDPIN = 11;

long oldTaskPosition  = -999;
long oldTimePosition  = -999;

unsigned long motorTimer = 0;
unsigned long screenLight = 0;

bool motorState = false;
bool oldTimeState = false; // stores button state
bool oldTaskState = false; // stores old button state (time)
bool oldSnoozeState = false; // stores old button state (snooze)

// task
int task_pos = 0; // dial position
int time_pos = 0; // time dial position
int currentBuzz = -1;
// stores task position that is currently buzzing (-1 = nothing)
int timeMax = 24; // limit for dial turn (changes for hours/min/am-pm)
int timeButtonCount = 0; // hours/minutes/ampm
int lcdHour = 0; // for printing hour on LCD screen
int lcdMinute = 0;
int lcdTask = 0;
int rtcHour = 0;
int rtcMinute = 0;

// for each task (10 tasks)
int alarmHour[] = {12, 12, 12, 12, 12, 12, 12, 12, 12, 12};
int alarmMinute[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int alarmOn[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

bool snoozeOn[] = {false, false, false, false, false, false, false, false, false, false};


void setup() {
  pinMode(MOTORPIN, OUTPUT);
  pinMode (TASK_BUTTON, INPUT_PULLUP);
  pinMode (TIME_BUTTON, INPUT_PULLUP);
  pinMode (SNOOZE_BUTTON, INPUT_PULLUP);
  pinMode(LEDPIN, OUTPUT);
  Serial.begin (9600);

  setSyncProvider(RTC.get);   // the function to get the time from the RTC

  screen.init();
  screen.backlight();
}

void loop() {
  //------------------------------------
  // Snooze
  //------------------------------------
  int snoozeState = digitalRead(SNOOZE_BUTTON); // task: enabled or not

  if (!snoozeState && oldSnoozeState) {
    screenLight = millis();
    Serial.println("SNOOZE");
    
    if (currentBuzz > -1) {
      if (alarmMinute[currentBuzz] < 45) {
        alarmMinute[currentBuzz] += 15;
         
      } else { 
        // alarmMinute[currentBuzz] >= 45
        alarmHour[currentBuzz] += 1;
        alarmMinute[currentBuzz] += (currentBuzz - 45);
      }
      
      snoozeOn[currentBuzz] = true;
      currentBuzz = -1;
    }
  }
  
  oldSnoozeState = snoozeState; // button thing

  //------------------------------------
  // Buzz Alarm
  //------------------------------------

  // loops through tasks
  for (int i = 0; i < 10; i++) {
    // checking if alarm needs to be activated
    
    if (hour() == alarmHour[i] && minute() == alarmMinute[i] && alarmOn[i] == 1) {
      screen.backlight();
      buzzing(); // pulses motor
      Serial.println("ALARM ON");
      currentBuzz = i; // save task position of current alarm going off
    }
  }
  
  if (currentBuzz == -1) {
    analogWrite(MOTORPIN, 0);
    digitalWrite(LEDPIN, LOW);
  }

  taskFunction();
  taskButton();


  //---------------------------------------
  // Time knob
  //---------------------------------------

  if (!(timeButtonCount % 3 == 0)) {
    
    int timeKnobMax = (timeMax) * 4;
    long newTimePosition;

    // account for 4 times extra readings
    if (timeKnob.read() > timeKnobMax) timeKnob.write(0);
    else if (timeKnob.read() < 0) timeKnob.write(timeKnobMax);

    newTimePosition = timeKnob.read();

    //TIME IS CHANGED
    if (newTimePosition != oldTimePosition) {
      screenLight = millis();
      oldTimePosition = newTimePosition;
      time_pos = oldTimePosition / 4;
      Serial.println(time_pos);
    }
  } else {
    timeKnob.write(0);
  }

  //------------------------------------
  // Time button
  //------------------------------------

  //Read time button
  int timeState = digitalRead(TIME_BUTTON);

  if (!timeState && oldTimeState) {
    screenLight = millis();
    screen.clear();
    Serial.print("LCD hour: ");
    Serial.println(lcdHour);
    timeKnob.write(0); // reset time knob position back to 0

    // display correct task and alarm time corresponding for that task
    if (task_pos < 9) {
      if (timeButtonCount % 3 == 1) alarmHour[task_pos] = time_pos;
      else if (timeButtonCount % 3 == 2) alarmMinute[task_pos] = time_pos;
    }
    // RESET time mode
    else if (task_pos == 9) { 
      if (timeButtonCount % 3 == 1) rtcHour = time_pos;
      else if (timeButtonCount % 3 == 2) rtcMinute = time_pos;
    }

    Serial.print(alarmHour[task_pos]);
    Serial.print(" : ");
    Serial.print(alarmMinute[task_pos]);
    Serial.print(" : ");
    Serial.println(alarmOn[task_pos]);

    timeButtonCount++;
    Serial.println(timeButtonCount);
    time_pos = 0;
    delay(300);
  }
  oldTimeState = timeState;
  
  // BUZZING
  if (currentBuzz > -1) {
    //display current task
    lcdHour = alarmHour[currentBuzz];
    lcdMinute = alarmMinute[currentBuzz];
    taskKnob.write(currentBuzz);
    task_pos = currentBuzz;
  }
  // set real time clock
  else {
    if (timeButtonCount % 3 == 0) {
      if (task_pos == 9) {
        lcdHour = rtcHour;
        lcdMinute = rtcMinute;
        
      } else {
        lcdHour = alarmHour[task_pos]; // display set hour on LCD
        lcdMinute = alarmMinute[task_pos];
        
      }
    }
    else if (timeButtonCount % 3 == 1) { //setting hour
      timeMax = 24;
      lcdHour = time_pos; //displays changing hour on LCD
      
      if (task_pos == 9) {
        lcdMinute = rtcMinute;
        
      } else {
        lcdMinute = alarmMinute[task_pos];
        
      }
    }
    else if (timeButtonCount % 3 == 2) { //setting minute
      timeMax = 60;
      lcdMinute = time_pos;
      
      if (task_pos == 9) {
        lcdHour = rtcHour;
        
      } else {
        lcdHour = alarmHour[task_pos];
        
      }
    }
  }


  screen.home();
  if (task_pos == 9) {
    screen.print("Reset Time");
  } else {
    screen.print("Task ");
    screen.print(task_pos + 1);
    if (snoozeOn[task_pos]) screen.print("*");
  }

  screen.setCursor(11, 0);
  if (hour() < 10) screen.print("0"); // 0 offset if < 10
  screen.print(hour());
  screen.setCursor(13, 0);
  screen.print(":");
  if (minute() < 10) screen.print("0"); // 0 offset if < 10
  screen.print(minute());

  screen.setCursor(0, 1);
  if (lcdHour < 10) screen.print("0"); // 0 offset if < 10
  screen.print(lcdHour);

  screen.setCursor(2, 1);
  screen.print(":");
  if (lcdMinute < 10) screen.print("0"); // 0 offset if < 10
  screen.print(lcdMinute);

  screen.setCursor(6, 1);

  if (alarmOn[task_pos] == 1) { // set alarm on
    // alarm on
    screen.setCursor(13, 1);
    if (task_pos == 9) {
      screen.print("SET");
    } else {
      screen.print("ON");
    }
  } else if (alarmOn[task_pos] == 0) { // set alarm off
    // alarm off
    screen.setCursor(13, 1);
    if (task_pos == 9) {
      screen.print("SET");
    } else {
      screen.print("OFF");
    }
  }

  //After a minute of inactivity, turn off the LCD backlight to save power
  if (screenLight + 60000 <= millis()) screen.noBacklight();
  else screen.backlight();
}


//pulses motor
void buzzing() {
  if (motorTimer + 1000 <= millis()) {
    motorState = !motorState; //flip state
    motorTimer = millis(); // reset timer
  }
  if (motorState) {
    analogWrite(MOTORPIN, 200);
    digitalWrite(LEDPIN, HIGH);
  }
  else {
    analogWrite(MOTORPIN, 0);
    digitalWrite(LEDPIN, LOW);
  }
}


//TASK knob
void taskFunction() {
  //Zachs method for looping the knob
  if (taskKnob.read() > 36) taskKnob.write(0);
  else if (taskKnob.read() < 0) taskKnob.write(36);
  long newTaskPosition = taskKnob.read();

  //TASK IS CHANGED
  if (newTaskPosition != oldTaskPosition) {
    oldTaskPosition = newTaskPosition;
    screenLight = millis();

    // reset time position and button count when task is changed
    timeButtonCount = 0;
    time_pos = 0;
    screen.clear();

    //print task position and time set for that task
    Serial.print("old task: ");
    Serial.print(oldTaskPosition);
    Serial.print(" / task_pos: ");
    Serial.println(task_pos);
    Serial.print(" / printing: ");
    Serial.println(newTaskPosition / 4);
  }

  task_pos = newTaskPosition / 4;
}


/*------------------------------------
  Task button
    if task knob is on position 11 -
    DISPLAY "RESET TIME" instead of "task 11"
    use time button to set current time
    hit task button to set
    when pressed, rtc.setTime(hours, minutes, seconds)
------------------------------------*/
void taskButton() {
  int taskState = digitalRead(TASK_BUTTON); // task: enabled or not

  if (!taskState && oldTaskState) {
    screenLight = millis();

    // RESET time on task 10
    if (task_pos == 9) {
      // set hour:min:sec
      tm.Hour = rtcHour;
      tm.Minute = rtcMinute;
      tm.Second = 0;
      // Apr 22 2019
      tm.Month = 4;
      tm.Day = 22;
      tm.Year = CalendarYrToTm(2019);
      if (RTC.write(tm)) {
        setSyncProvider(RTC.get);
      }
    }
    else { // regular alarm function
      if (snoozeOn[task_pos]) snoozeOn[task_pos] = false;
      
      // ***change 0 and 1 -> off and on for printing
      // setting the alarm: if alarm is off, turn it on
      if (alarmOn[task_pos] == 0 && currentBuzz == -1) {
        alarmOn[task_pos] = 1;
      }
      
      //if the alarm is set as on (and not buzzing), turn it off
      else if (alarmOn[task_pos] == 1 && currentBuzz == -1) alarmOn[task_pos] = 0;

      //if alarm is buzzing, we know alarm is on, so we turn it off
      if (currentBuzz > -1) {
        screen.clear();
        alarmOn[currentBuzz] = 0; // disable alarm
        analogWrite(MOTORPIN, 0); // turn off buzzing alarm
        digitalWrite(LEDPIN, LOW);
        Serial.println("ALARM OFF");
        currentBuzz = -1;
        taskKnob.write(0);
      }

      Serial.print("alarm on: ");
      Serial.println(alarmOn[task_pos]);

      // Alarm on
      if (alarmOn[task_pos] == 1) {
        screen.clear();
        screen.setCursor(13, 1);
        
        if (task_pos == 9) {
          screen.print("SET");
          
        } else {
          screen.print("ON");
          
        }
      } else if (alarmOn[task_pos] == 0) {
        // alarm off
        screen.clear();
        screen.setCursor(13, 1);
        
        if (task_pos == 9) {
          screen.print("SET");
          
        } else {
          screen.print("OFF");
          
        }
      }
      delay(300);
    }
  }
  oldTaskState = taskState; // button thing
}

 

]]>
Team Irv Prototype Documentation https://courses.ideate.cmu.edu/60-223/s2019/work/team-irv-prototype-documentation/ Wed, 10 Apr 2019 02:30:49 +0000 https://courses.ideate.cmu.edu/60-223/s2019/work/?p=7245 By Eric Mendez, Eliza Pratt, and Helen Yu

Introduction

In the past two weeks, our team synthesized observations from our meeting with Irv to develop a “convenience machine” he could use to improve his daily life. From our insights, we decided to create a reminder device that’s unique to Irv’s unique and busy lifestyle (e.g., tennis meetings, gardening, cultural events). In this post, we’ve documented our thought process, experience with different components, and the reasoning behind the coding, electrical, and design choices we’ve made.

Interactive Itinerary Prototype

The Interactive Itinerary is a digital reminder system (think Google Calendar) that feels like an analog device. The user can set alarms for tasks or events without having to type on a tricky touchscreen. Instead, the user would write down the task on a piece of paper and set the alarm using built in knobs.

The time and task knob add to the analog inputs and the screen prints the desired outputs, such as current time, task number, andd alarm settings

The interactive itinerary prototype has 3 key components: 1) Two knobs that set the task and alarm 2) the digital display that shows task, time, and set time 3) a vibrating motor that acts as an alarm. To use the interactive itinerary, the user would write down a task on a piece of paper with an empty list from 1 – 10. Using the task knob, the user would turn to the desired task number turn the alarm on. Then, they would set the time using the time knob. When the alarm starts to buzz, the user can turn off the alarm with the task knob.

The LCD screen displays the current task that the task knob is on, the current time in the top right corner, the set time (hour:minute AM/PM) in the bottom left corner, and whether or not the alarm for the specific task is on or off.

The housing for the device was modelled after a notebook/notepad. This interactive notebook makes it easy to keep tasks that need to be completed by a certain time. 

The mockup of the Interactive Itinerary housing is made out of foam core. The rectangle shows where the LCD screen would live. The two circles represent the task and time rotary encoders.

The electronics would live on the left side of the housing and the task list would live on the right side, making it easy for Irv, who is right-handed, to write down his daily tasks.

Process

All the components of the prototype hooked up and ready to go

After meeting with Irv, we decided to move forward with the task reminder device that is more of a physical alarm, as opposed to a audible or visual alarm. Our team started by making a list of goals and potential features for the device.

After making a list of problems Irv mentioned, we branched off each idea to find ways to help Irv. The ideation tree helped us deterine basic goals for the design and feel of the device for Irv

Alarm Notification

Because Irv’s hearing is not great and because purely visual alarms are not noticeable when put away, our team chose a vibrating notification system. The micro vibration motor is very small but strong and noticeable, making it the perfect fit for this device. As shown in the picture below, we secured the soldering with heat shrink to keep the vibration motor attached.

Heat shrink to secure soldered wires to the micro vibration motor because when it vibrates too much, the soldered wires fall apart.

Real Time Clock

Setting up the real time clock was relatively simple. We used a built-in example from the RTC library to set the time on the RTC. To get the time from the RTC and use it as an alarm, we used a built-in function from the Time.lib library called setSyncProvider(RTC.get).

When we initially ran the code without this line, the alarm did not work. WIth this line, we can also easily display the current time. After putting this in void setup(), we can use functions like hour() or minute() to collect the current hour and time data from the RTC.

Since the time on the RTC runs on military time and we wanted to display the time with AM and PM, we had adjust the logic of the alarm setting. We ran into trouble when we were trying to compare the PM times to the 24-hour time because the numbers do not match up. In this section of the code, we are storing an alarm hour for a specific task into an array title alarmHour. By modding the timeButtonCount by 5, we can get 5 states to condition over.

This section says that if we are setting the hour for a PM event, we will add 12 to the alarmHour for that specific task so that it matches the 24-hour time.

Rotary encoders

Since Irv is not comfortable using the touchscreen on his iPhone, we aimed to make the device as intuitive and analog as possible. The rotary encoders we used have 20 detents which provides a good tactile indication for the user. It also has built in push button that acts as a “confirmation” button for the time button. For the task button, the push button turns the alarm on or off.

The task rotary encoder cycles from 1 to 10 as the user rotates the knob. The time rotary encoder cycles from 1 to 12 on the hour state, 0 to 59 in the minute state, and AM or PM in the time of day state.

To keep each task alarm independent from other task, the alarm hour, minute, time of say, and on/off states are stored in matrices. Each matrix has 10 elements for the 10 tasks.

The alarm on/off button was initially dependent on the task position beause it was inside that if statement. To keep everything independent from one another, we kept each part of the device separate. So the time knob, time button, task knob, and task button are all in separate conditionals.

LCD Display

Our group wanted to use a Nokia 5510 graphic LCD 48 rows x 84 display because it had a better finish and display that the large blue LCD display. This graphic LCD proved to be a large challenge, partially because there is little documentation on the screen. The Nokia 5510 would involve bitmapping, which is something the group was unfamiliar with. After hooking up the Nokia 5510, and uploading a sample we found online, the screen remained blank but the LEDs in the back lit up. After troubleshooting for a while and a couple dead ends, we decided to transition to blue LCD and return to the Nokia 5510 at a later time.

The Nokia 5510 has a small an clean interface that requires bitmapping. The Nokia display is preferred over the blue LCD.

Discussion

Our prototype was overall functional for the crit on April 8th. We demonstrates the buzzing alarm function to Irv and taught him how to set the task and time on the device. However, before the presentation, when our group powered the device using a 9 volt battery, the RTC reset it’s clock to 0:00. We managed to reset the current time on the RTC and reupload the code onto the device. However, we were only able to run the device on a laptop.

We received many helpful comments and feedback from the Osher group, Irv, and people in this course. One idea our team, including Irv, really liked was the snooze button because it is a function that will most definitely come in handy for Irv. After consulting Irv, we planned to add a snooze button that specifically snoozes for 15 minutes after the alarm. We also pulled out several different switches and buttons for Irv to try out to see which part felt best for him. Zach also suggested adding a cursor to the LCD display and reminded us to fix the current time display on the LCD screen so that the time reads in the 00:00 format. This change will make it less confusing for Irv and more uniform.

After the crit, the team, including Irv, decided set some goals for the final design of the Interactive Itinerary, We want to make the device as small and thin as possible so that it could ideally fit in Irv’s back pocket. This also means that the material should be flexible enough to maintain its structure when there is pressure applied to it. To make the Interactive Itinerary smaller, we would have to explore ways to rearrange the rotary encoders, which are relatively thick. So, we plan on exploring flexible but sturdy materials that can withstand a certain amount of stress as well.

Moving forward, our team plans on adding features and improvements to our existing prototype. In addition to the snooze button, cursor, and the time display, we also plan to display the task number when its alarm goes off. Since Irv prefers to set the time using military time, we will be taking out the AM/PM time format. We will have to figure out how to position the knobs to minimize the thickness. We want to troubleshoot how to power the device with a rechargeable battery without it resetting the RTC. While the LCD screen is easy to use and completely functional for our use, we still want to revisit the nokia screen and see if we can get it to work. Lastly, we would want to add a blue feature to the device because that is Irv’s favorite color.

 

]]>
Meeting with Irv https://courses.ideate.cmu.edu/60-223/s2019/work/meeting-with-irv/ Sun, 31 Mar 2019 20:47:39 +0000 https://courses.ideate.cmu.edu/60-223/s2019/work/?p=7131

Irv and his wife Lois welcome us into their house with snacks and a friendly cat, Buttons

This meeting’s purpose was to meet with our Osher student Irving “Irv” Lieberman and get to know his daily routine so we would be able to narrow down what we should design for his convenience machine. We planned to meet with him Sunday morning, March 24th, in his home to discuss his lifestyle. We wanted to go to his house so we would also be able to see how he lived. Our goals for the meeting were to get as much information about Irv’s hobbies, daily routines, responsibilities, and aspects of life that we could make more convenient. We want to make sure we keep Irv in the loop when it comes to creating this convenience device because it is for him after all.

Meeting Agenda

Before meeting with Irv, we planned out how we wanted to conduct the interview and what we hoped to learn from this experience.

Meeting Overview

Irv’s Background

Irv and his wife, Lois, live in a house at the top of the Squirrel Hill neighborhood. Their house has rough stone steps, steep staircases, and plenty of room for gardening. Irv, originally from Bronx, NY, has a PhD in electrical engineering. Throughout his career, Irv worked with lasers and atomic clocks, and was involved with many patents. His career brought him to Westinghouse in Pittsburgh where he mainly worked with energy. Irv and Lois have no children and two cats. Since Irv and Lois do not have children (and as a result, no grandchildren), they do not have members of the younger generation to teach them how to use new technology. So, while they both have iPhones, they struggle with this new interface that is less analog. Overall, Irv is a very capable and handy person, always fixing things around the house and comfortable working on technical projects.

A Day in Irv’s Life

Irv stays active by maintaining his garden around the house, by taking care of weeding, laying manure, and by trying to keep the deer away from his plants. His house is very old, so it needs constant work. He told us that he’s had to repair sinks, and redo the electrical in some of the rooms. His kitchen is very decked out with shelves on wheels that you can hide under the kitchen counter, adjustable LED lighting over all his counters, and electrical outlets all around the island in the center of the kitchen.

The video below shows innovative kitchen shelf unit that Irv designed and constructed.

Irv installed adjustable LEDs inside the frosted cabinets and around the perimeter of his kitchen counter

He also plays tennis and works out. He keeps his mind active by going to Osher classes, and since he has a Ph.D. in electrical engineering, he is able to take some of the more technically challenging classes like astronomy. Him and his wife Lois also enjoy going to cultural events like the opera, symphony, ballet, and dinner parties with friends. Even though they have a car, they enjoy walking and taking the bus if they have time.

Some Obstacles

In spite of maintaining a very active and social lifestyle, Irv admitted to facing certain obstacles as a result of aging. To start, he told us that understanding new software (like iphones) was often difficult for him, especially since he had no children or younger people around to help explain the technology.

Eliza shows Irv how to add a vibration to his phone so that he knows when he gets a notification

Additionally, his desire to complete his own housework, like weeding and washing his car, is hindered by physical exertion and a bad knee. Irv also mentioned having some problems with hearing. Over the course of the meeting, we noticed that Irv didn’t hear the clock chime or the new texts on his phone since they were prompted solely with audio notifications. While this doesn’t drastically impair his daily activities, we noted that we should use non-audio sensory alerts (like vibrations and visual cues) when brainstorming potential devices. Nearing the end of the interview, we learned that Irv has trouble staying on time and keeping his reminders organized.

Irv takes notes and makes a list of reminders for himself during the meeting

He seemed to take interest in this issue as a point for intervention, so we started to develop ideas for a type of portable reminder device that could keep him on schedule via vibrations or flashing lights.

Discussion

Our first meeting with Irv was very successful and productive. We wanted the meeting to be less like a interview and more like a conversation between a group of people, which we succeeded in doing. In other words, we did not try to structure our meeting in parts. Instead, we bounced between conversations about Irv’s background, our own backgrounds, and Irv’s current lifestyle. We concluded that based on his active lifestyle, work around the house, and customized kitchen, Irv is a very capable person and doesn’t require much assistance. After having a productive meeting with Irv, we decided to lean on the convenience side of this project, as opposed to the assistive aspect.

While Irv was very willing to talk about his work as an electrical engineer and his life in Pittsburgh with his wife, Lois, he was reluctant to give details about things he struggles with. For instance, when we were discussing the difficulties of gardening and maintaining the house, even with some prodding, Irv did not specify what specifically was hard and only said that gardening is a tiring task. However, having Lois sit in on the meeting was very beneficial because she would interject when Irv was vague about what he struggles with. She brought Irv’s bad knee, back, and hearing  to our attention. Overall, having Lois for a second input helped us narrow down the ways in which we could work with Irv.

Some things we could do differently next time is get more insight to his daily routine by getting a tour of their house or seeing them demonstrate different parts of their daily lives. We got a glimpse into Irv’s capabilities when he and Lois showed us the all the gadgets and renovations in the kitchen. He is a very independent, smart, and active person. Overall, the meeting was very successful and we feel like we built a solid foundation with Irv. We got to learn a lot of Irv, as a person and as a client, and discover many interesting aspects of his life here with Lois.

]]>
Reluctant Wallet https://courses.ideate.cmu.edu/60-223/s2019/work/reluctant-wallet/ Wed, 20 Mar 2019 07:10:08 +0000 https://courses.ideate.cmu.edu/60-223/s2019/work/?p=6713 OVERVIEW

In an effort to save money, I created a difficult wallet to bombard you with guilt-inducing questions and will only unlock if you’ve proven your desperation and need.

 

 

Process
Discussion

While the double transducer gave me the opportunity to test sensors and different technologies, I was glad this project allowed me to explore more aspects of the physical structure. In the critique, there was a positive response to the design of my case. I received comments such as, “Very finished design!” and “Clean and smooth. I want to actually use this in my everyday life.” I’m happy that all the work I put into the final box paid off and that people appreciated the design. While I ideally would have covered the wires with an interior casing instead of zip-tying them under the lid, I’m satisfied with how it looks and enjoyed experimenting with latches and living hinges.

During the process, I was excited work with laser cutting in a way I had never considered and had fun testing how different cuts, dimensions, and materials affected the living hinges. One mistake I kept making, however, was underestimating how much space I needed in the box for all my electrical components. After spending hours trying to figure out how I could fit everything into the tiny box I had already cut, I finally gave in and created a larger case. In addition, from learning how to use the LCD screen with just internet resources, I feel a lot more confident in my ability to teach myself more about the Arduino and it’s capabilities for future projects.

If I had a chance to make another iteration, I believe I could get more complex with the coding of the questions. Instead of asking the same 5 questions every time and counting the “yes” responses to open the box, I think it would be more exciting if the responses affected the questions being asked (i.e., “Is this food related?” [Y]> “This isn’t another late night Chipotle run, is it?”). I’d also like to address the issue of my box locking me out due to technical failures. During my demonstration, my reset button came unpinned and prevented me from reopening the box. While my first thought was to solder everything to keep wires from coming loose, I received some interesting suggestions for an “emergency latch to bypass the lock.” Although it would probably still be helpful to solder my wires, I think the emergency latch would be an exciting and helpful solution to this common problem. In spite of all these alterations I would like to make, I enjoyed this project for giving me the opportunity to explore different making techniques and their relationship to physical computing.

SCHEMATIC

code
// Reluctant Wallet
// Eliza Pratt

//Description: This project asks a user questions about their potential spending on an LCD
//and keeps a counter of the "yes" and "no" responses that are input through buttons. 
//Depending on the user's responses, a servo will rotate to "open the wallet". 

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>

LiquidCrystal_I2C screen(0x27, 16, 2);
Servo myservo;

const int YESBUTTON = 2;
const int NOBUTTON = 3;
const int SWITCH = 4;

bool yOn = false; 
bool nOn = false;
bool off = false;

int yCount = 0; // yes counter
int nCount = 0; // no counter 
int qCount = 0; // number of questions asked

int pos = 75; // "locked" servo position

//Questions are split into two arrays so all text will display on the LCD without scrolling
String question[ ] = { "Do you even want this?", "Is it on sale?", 
  "Will you regret not buying this?", "Will this make", 
  "Would you save  it from a fire?" };

String question2[ ] = { "this?", "", 
  "not buying this?", "your life better?", 
  "it from a fire?" };
  
void setup() {
  Serial.begin(9600);
  pinMode(YESBUTTON, INPUT);
  pinMode(NOBUTTON, INPUT);
  pinMode(SWITCH, INPUT);

  myservo.attach(9);

  //at setup, light up LCD and print first question
  screen.init();
  screen.backlight();
  screen.home();
  screen.print(question[qCount]);
  myservo.write(pos);

}

void loop() {
  int yes = digitalRead(YESBUTTON);
  int no = digitalRead(NOBUTTON);
  int on = digitalRead(SWITCH);

  Serial.println(on);
  screen.home();
  
  //ASKING QUESTIONS
  //display current question on LCD
  if (qCount < 5) {
    screen.print(question[qCount]);
    screen.setCursor(0, 1);
    screen.print(question2[qCount]);
  }
  
  //AFTER 5 QUESTIONS
  else { 
    screen.clear();
    //if at least four responses were "yes," rotate servo to let them in
    if (yCount > 3 && !off) {
      screen.print("Fine.");
      screen.setCursor(0, 1);
      screen.print("you can come in.");
      myservo.write(20);

    }
    //With less than 4 "yes"s, display sorry message and turn off device
    else {
      screen.print("Sorry.");
      screen.setCursor(0, 1);
      screen.print("Not this time.");
      delay(5000);
      turnOff();
    }
  }
  
  //if "yes" button is pressed
  if (yes == 0 && !yOn) {
    Serial.println("YES");
    screen.clear();
    yOn = true;
    yCount++;
    qCount++;
  }
  //if "no" button is pressed
  else if (no == 0 && !nOn) { 
    Serial.println("NO");
    screen.clear();
    nOn = true;
    nCount++;
    qCount++;
    
  }

  // reads buttons as "off" when unpressed
  if (yes == 1) yOn = false;
  if (no == 1) nOn = false; 

  //if both buttons are pressed, close latch and turn off screen
  if (yes == 0 && no == 0) turnOff();
  delay(50);
}


///when "turned off", turn off LCD display and reset servo position
void turnOff() {
  off = true;
  screen.clear();
  screen.noDisplay();
  screen.noBacklight();
  myservo.write(pos);
  delay(500);
  
}

 

 

]]>
Double Transducer: Heartbeat Visualizer https://courses.ideate.cmu.edu/60-223/s2019/work/double-transducer-heartbeat-visualizer/ Mon, 18 Feb 2019 05:16:41 +0000 https://courses.ideate.cmu.edu/60-223/s2019/work/?p=5968 By Alton Olson and Eliza Pratt

Description

This project detects a user’s pulse and triggers a servo motor to move in sync. When a heartbeat is detected, the servo pushes a micro switch, which in turn lights up a configuration of LEDs.

Project Images

Overview: Double transducer contains a pulse sensor with pipecleaner cover, a servo, a microswitch, and LEDs with a heart display.
Transducer reading a pulse
Intermediate interaction: a servo is positioned to push a micro switch
 

Double transducer in action

Process Images

Testing a force sensor as the secondary input. While we had originally imagined using a button, we needed a component the servo could realistically push.
Ziptying the servo to the breadboard to prevent it from pushing itself upwards.

Pulse sensor picking up too much noise and detecting false pulses.

Device adjusted successfully with accurate pulse representation.

Schematic

Code

/*
 * Heartbeat Visualizer
 * By Alton Olson and Eliza Pratt
 * 
 * Description: This program reads input data from a pulse
 * sensor and tracks the maxes and mins to determine heart rate. 
 * When a heartbeat is detected, it triggers a servo to push
 * a switch that turns on a configuration of LEDs. 
 * 
 * Credit: Code for measuring heart rate was adapted from 
 * user VE7JRO's contribution to the StackExchange Arduino forum.
 * View discussion: https://tinyurl.com/y3vuvgpp

 */

#include <Servo.h>

// Pin constants
const int BUTTONPIN = 2;
const int SERVOPIN = 3;
const int LED1PIN = 4;
const int LED2PIN = 5;
const int LED3PIN = 6;
const int LED4PIN = 7;
const int LED5PIN = 8;
const int PULSEPIN = A1;

// Servo position constants
const int SERVO_DOWN_POSITION = 155;
const int SERVO_UP_POSITION = 135;

// We have two thresholds to detect a pulse
const int RISING_THRESHOLD = 520;
const int FALLING_THRESHOLD = 510;
// Ignore reading keeps track of the state of the pulse
bool ignoreReading = false;
// Time in ms of the last beat
long lastBeatTime = 0;

Servo servo;

void setup(){
  Serial.begin(9600);
  servo.attach(SERVOPIN);
  pinMode(BUTTONPIN, INPUT);
  pinMode(LED1PIN, OUTPUT);
  pinMode(LED2PIN, OUTPUT);
  pinMode(LED3PIN, OUTPUT);
  pinMode(LED4PIN, OUTPUT);
  pinMode(LED5PIN, OUTPUT);
  pinMode(PULSEPIN, INPUT);
}

void loop(){
  int reading = analogRead(PULSEPIN);

  Serial.println(reading);
  
  // Heart beat leading edge detected.
  if(reading > RISING_THRESHOLD && !ignoreReading
    && millis() - lastBeatTime > 500){
    // Trigger servo if <120 bpm
    servo.write(SERVO_DOWN_POSITION);
    ignoreReading = true;
    lastBeatTime = millis();
  }

  // Heart beat trailing edge detected.
  if(reading < FALLING_THRESHOLD && ignoreReading){
    servo.write(SERVO_UP_POSITION);
    ignoreReading = false;
  }

  // Turn on LEDs if the switch is pressed
  digitalWrite(LED1PIN, digitalRead(BUTTONPIN));
  digitalWrite(LED2PIN, digitalRead(BUTTONPIN));
  digitalWrite(LED3PIN, digitalRead(BUTTONPIN));
  digitalWrite(LED4PIN, digitalRead(BUTTONPIN));
  digitalWrite(LED5PIN, digitalRead(BUTTONPIN));

  delay(150);
}

 

Discussion

Decision Making: Throughout this project, one of our biggest realizations was that we can’t rely on physical components to behave exactly as we expect. While we knew we wanted a servo to be our initial output, finding the proper device to respond to it proved to be harder than we expected. We ended up testing buttons, force sensors, and a variety of switches in order to find the right fit. Large buttons presented a problem as they were too springy and would require a stronger servo to actuate. FSRs solved the recoil issue, but we weren’t able to get a solid reading from the small servo arm. We ended up opting for the micro switch as it required very little force to actuate but provided a reliable binary input.

One design decision we had to make early on was whether to have the transduced signal be continuous or discrete. Originally we were going to transduce the user’s heartrate, having the servo move to different positions based on the frequency of the user’s pulse. It was difficult to get a reliable heartrate reading, though, and we thought that reading individual pulses would be a simpler problem and easier to tune.

Challenges: Getting reliable input from the pulse sensor was by far our biggest challenge. The raw data was noisy and unreliable, and it was difficult to pinpoint the source of the noise. We discovered that where the sensor is on your finger, how hard you press on the sensor, and the amount of oil and sweat on your skin all affect the data. Our first algorithm used a simple threshold, where we’d count a heartbeat if the pulse sensor data crossed from below to above the threshold. The noise in the signal generated lots of false positives. So we added a second “falling” threshold, below the first, such that the signal had to drop below the falling threshold before the rising threshold would count again. This helped isolate only the bigger spikes in the waveform and filter out some of the noise. Lastly, to try and throw out more false positives, we added a max heartrate, so that the algorithm would ignore pulses that were within a certain time of other pulses.

Three small fixes we could have made:

  1. A better filtering algorithm. We still had issues with noise fooling our algorithm, and maybe an additional filter could have helped. Perhaps a low pass filter could eliminate some of the higher frequency noise while keeping the pulses intact.
  2. Adjustable thresholds. We hardcoded the rising and falling thresholds, but allowing the user to adjust these with a potentiometer could allow the device to perform better under different conditions.
  3. Taking pulse readings from somewhere else. The documentation for the pulse sensor recommends to try using an ear clip attachment to take readings from a user’s ear. We didn’t have the ear clip attachment, but this could have provided better data than the finger.
]]>
Arduino Digital Pet https://courses.ideate.cmu.edu/60-223/s2019/work/arduino-digital-pet/ Tue, 15 Jan 2019 22:29:05 +0000 https://courses.ideate.cmu.edu/60-223/s2019/work/?p=5615

Project title: Arduino Tamagotchi

Project creator: Alojz Jakob

Description: With an OLED display and an arduino, this device simulates an interactive pet dinosaur similar to a Tamagotchi. The user can care for the dinosaur and regulate its hunger, health, and happiness levels.

Caring for the dinosaur’s health

Response: This project seems like a great way to envision game design from a physical computing perspective! I have a lot of appreciation for my old toys and love the idea of using these skills towards toy design. If I were to make my own, I think I would modify the code or develop my own game for the platform. I’ve only ever created games/animations for browsers before, and I would enjoy creating something designed to interact with a physical environment.

]]>