Final project – Intro to Physical Computing: Student Work fall 2019 https://courses.ideate.cmu.edu/60-223/f2019/work Intro to Physical Computing: Student Work Mon, 16 Dec 2019 16:02:49 +0000 en-US hourly 1 https://wordpress.org/?v=5.2.20 The fountain of poof: Team Jim Final Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/team-jim-final-documentation/ Mon, 16 Dec 2019 07:08:24 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=9078 Introduction

Team Jim consisted of Nicholas, Jeena, Leland, and Jim. We were tasked with helping Jim in his daily life with an electronic device that we could build for him. At first it was hard to find a real problem that we could help fix, but with a little more exploration of his daily life and house, we found that Jim has a piano in his living room that needs to be at certain humidity in order to be maintained.  We combined this with the fact that Jim has a lot of fountains in his house, so we made a fountain that could read the humidity in the living room and humidify the room if needed.

You can see our initial meeting post here and our prototype post here

What we built

We built a fountain that will humidify Jim’s living room based on the humidity level that he wants maintained. The humidity is measured by a remote part that can be placed wherever in the room, and the fountain can then take the data from the remote part and activate the humidifier when needed. The fountain itself has a knob for which Jim can turn to set the humidity level that he wants the room to be at. The purpose of this fountain is to automatically maintain the humidity in the room if he wants to while also serving an indoor fountain that supplies the calming sound of flowing water.

 

Narrative Sketch:

Its the time of the year again where Jim knows he needs to bring in an external humidifier to maintain the humidity for his piano. However, he remembers that a couple of CMU students built him a fountain to monitor the humidity and humidify the room. Jim then plugs in the fountain if it isn’t already, then he sits back in a chair in his living room watching the fountain spewing a satisfying mist of vaporized water.

A photo of a working running second version of the final project. The LEDs are not on because the remote part was not turned on during the photo shoot session, but everything's working, including the pump, LED strip, humidifier, low-voltage LED indicator and the humidifier set point potentiometer.

A photo of a working running second version of the final project. The LEDs are not on because the remote part was not turned on during the photo shoot session, but everything’s working, including the pump, LED strip, humidifier, low-voltage LED indicator and the humidifier and set point potentiometer.

First iteration
The main fountain part of the first iteration.

The main fountain part of the first iteration.

The first iteration of the main fountain part has a round base that traps the mist underneath it. In the gif, you can see the mist only as you lift up the top part.

The first iteration of the main fountain part has a round base that traps the mist underneath it. In the gif, you can see the mist only as you lift up the top part.

Second iteration
A second iteration of our final project. Here you can see a new 'stage case' design of the top part where the water can create an ambient water sound while flowing down. The humidifier is exposed in the air such that it can directly humidify the room (as opposed to being underneath the top part in our first iteration and not able to humidify the environment).

A second iteration of our final project. Here you can see a new ‘stage case’ design of the top part where the water can create an ambient water sound while flowing down. The humidifier is exposed in the air such that it can directly humidify the room (as opposed to being underneath the top part in our first iteration and not able to humidify the environment).

Turning the set point potentiometer allows the user to adjust the threshold that determines when the humidifier gets turned on. When the humidity is slightly above the threshold (within 10%), the LED strip shows a rainbow color. When the humidity is above the threshold + 10%, the LED becomes blue. The LED shows full red color when the humidity is below the threshold and the humidifier gets turned on.

Turning the set point potentiometer allows the user to adjust the threshold that determines when the humidifier gets turned on. When the humidity is slightly above the threshold (within 10%), the LED strip shows a rainbow color. When the humidity is above the threshold + 10%, the LED strip becomes blue. The LED strip shows full red color when the humidity is below the threshold and the humidifier gets turned on.

Detail of the nozzle of the second iteration of the final project. This is where the water comes out directly from the pump. This nozzle creates a height such that the water creates an ambient water sound.

Detail of the nozzle of the second iteration of the final project. This is where the water comes out directly from the pump. This nozzle creates a height such that the water creates an ambient water sound.

A top-down view of the fountain main part. The humidifier lays among the rocks.

A top-down view of the fountain main part. The humidifier lays among the rocks.

The main control panel of the second iteration of the main fountain part.

The main control panel for the second iteration of the main fountain circuit box. The potentiometer has a nice numerical label that shows the set point for the humidity. The switch has on/off indication.

The second iteration of the main circuit box needs 'only' 2 power supplies. The power supply holes are labeled with permanent marker.

The second iteration of the main circuit box needs ‘only’ 2 power supplies. The power supply holes are labeled with permanent marker.

The look of the second remote box. It has an embedded radio sender (inside the box) and a humidity detector (where the white part is).

The look of the second remote box. It has an embedded radio sender (inside the box) and a humidity detector (where the white part is).

How we got here

One thing our group seemed to be very good at was making things difficult for ourselves. From the beginning, the journey from conception to delivery of this fountain was plagued by a variety of setbacks. We had left our initial meeting with Jim, quite convinced that we would be solving one of the two largely mechanical problems he had lain out for us as clear difficulties in his life. Upon further inspection (and prompting from Zach), we reached the conclusion that perhaps we hadn’t though broadly enough about the problem statement and possibilities for this project.
As our team has done time and again, we decided to revise our approach and try again, returning to gym with fewer expectations and only a vague goal of getting to know his and his wife’s lifestyles better rather than find a specific problem to solve right off of the bat. What we learned from this approach turned out be far more stimulating for the ideation process than our prior meeting. We left knowing that Jim and his wife both enjoy music (their Boston grand-piano being a centerpiece of their living room) as well as the ambient sounds of running water. And so we resolved to create a fountain that would provide a pleasant trickle as well as automatically regulate the humidity in the room to maintain the health of their piano.

The shelf were we intended to place the fountain in Jim’s house..

First iteration
Getting the materials for the first version of the main fountain part from Home Depot.

Getting the materials for the first version of the main fountain part from Home Depot.

The first version of the main fountain part.

The materials for the first version of the main fountain part.

The design of the first iteration top part.

The design of the first iteration top part.

The laser-cut side panel for power supplies for the first iteration final project. The holes were cut manually without drill bits. side

The laser-cut side panel for power supplies for the first iteration final project. The holes were cut manually without drill bits.

The main fountain part circuit box of the first iteration. It has 4 power supplies.

The main fountain part circuit box of the first iteration. It has 4 power supplies.

From this point onward, we were sure we knew what our biggest challenges were. Though there would have to be some technical/electrical work behind our design, the most daunting task would surely be engineering and integrating the various physical/mechanical elements of our design. How would we print or manufacture the curvature of a custom bowl? How could we keep things waterproof? And what kind of pump fit our use case?

A successful prototype critique brought with it a renewed confidence that we were on schedule.

Despite a slightly shortened timeline, the prototype critique came and went about as successfully as we could have asked. Our core hardware seemed to work as intended (at least when lain out on a breadboard) we had planned a tight schedule that emphasized starting our manufacturing and building as soon as possible. With the awkward timing of thanksgiving some delays did start to pile out. We didn’t order new pump or humidifier as early as we had intended and the vacuum forming needed to create the base and top basin for our fountain couldn’t be completed until after the break or the Sunday before the project was due.

These delays were result of a variety of factors. Not least of which was the fact that in many ways were in a bit in over our heads and unprepared for the amount of work still left to do to produce a finished product. So, when the eve of the final critique came around, it was all hands on deck. We first had to redesign and adapt to the fact that our original base design could not work. The vacuum former simple hadn’t provided the necessary minimum of four inches of depth to allow it to work, so we improvised by purchasing a base and using our original base as our new basin.
By the time we finished our “final” product, it was nearly seven in the morning, but we felt confident that we had been successful in our effort—event if we had required attaching four separate power sources to our base due to voltage supply and current draw issues we had been unable to solve earlier in the week.
When we arrived for our final critique, we confidently plugged our fountain in. To our surprise, it seemed to be a definitive success with a better stream of water than we had seen the night before and at least some humidity streaming out from the bottom. Of course, this was promptly followed by a smoking power-supply, a quick pop, and all of our electronics dropping immediately dead.

Second iteration
Remote part final box

Remote part final box

Nick was cutting the foam for vacuum forming the second iteration of the main fountain part.

Nick was cutting the foam for vacuum forming the second iteration of the main fountain part.

The main control panel for the second iteration of the main fountain circuit box. The potentiometer has a nice numerical label that shows the set point for the humidity. The switch has on/off indication.

The main control panel for the second iteration of the main fountain circuit box. The potentiometer has a nice numerical label that shows the set point for the humidity. The switch has on/off indication. The middle hole is for the low-voltage LED indicator that lights up when the remote box’s batteries are low.

For the second version, we made a mistake of soldering an Arduino nano directly onto our main circuit board. The nano stopped working and then we had to brutally destroy the entire Arduino nano with a heat gun and remove it from the board. In the photo, you can see the cut off pins that were connected to the nano.

For the second version, we made a mistake of soldering an Arduino nano directly onto our main circuit board. The nano stopped working and then we had to brutally destroy the entire Arduino nano with a heat gun and remove it from the board. In the photo, you can see the cut off pins that were connected to the nano.

Assembling the circuit box for the second version of the final project that needs only two power supplies. All internal connections are labelled.

Assembling the circuit box for the second version of the final project that needs only two power supplies. All internal connections are labelled.

This is the head of a beheaded Arduino Nano. We soldered an arduino nano onto the second iteration of the main circuit box and ended up having to destroy it because it stopped working. Then, for the second iteration.

This is the head of a beheaded Arduino Nano. We soldered an arduino nano onto the second iteration of the main circuit box and ended up having to destroy it because it stopped working. Then, for the second iteration we switched to an Arduino Uno as we did for the first version of the final project.

The second iteration of the main circuit box needs 'only' 2 power supplies. The power supply holes are labeled with permanent marker.

The second iteration of the main circuit box needs ‘only’ 2 power supplies. The power supply holes are

In hindsight, this sort of outcome could have been at least expected if not anticipated. The continuous last-minute scrambles we seemed to create for ourselves surely bred minor mistakes or oversights that culminated at the worse possible moment.
In the end, with the combined efforts of our team, the understanding of Jim, and the grace of a certain instructor, we were given further time to rethink elements of our fountain and come together to produce a final product. Major steps included reforming our basin, replacing the pump, and re-soldering our circuit inside a new box with only two power outlets (thanks to a new 12v 5A power supply). With all of this, the new fountain is actually able to humidify a room properly, regulate its own water level passively, and actively change its LEDs in response to the measured humidity of the room.

Conclusions and lessons learned:

There was a lot to be learned from this project. As a group, we spent a lot of time learning from our mistakes and shortcomings and most importantly trying again and again when certain things didn’t go our way. At these times, what was often most helpful was taking a second to reconsider our design and consult the right people before we decided a specific course of action. For example, when we decided to redo the top basin of our fountain using a vacuum former once again, it was Zach who not only suggested we try using the better quality architecture vacuum former, but who also put Nick in contact with someone who could help with the actual production when he couldn’t find a contact of his own.

Despite the clear failure of our final critique, we received a lot of helpful information to guide us as we worked to revise our fountain towards its “real” final iteration. Some of the most useful were to actually order and external power supply with the specs we needed, as well as position our humidifier on the top layer of the fountain rather than the bottom. In some ways these should have been common sense, but after all of the rushing we had done to finish our work, we first needed to hear the ideas suggested by others to actually implement them ourselves.

In this end, this was not an ideal project. We should have been finished with certain things earlier and should have planned for the delays we had later. Through our trial and error, we learned about the process of asking the right questions and not settling for the obvious solution or project idea. We learned pumps are temperamental and that integrating hardware requires planning ahead. Moreover, we found that simple solutions can exist if we are open to them. If we had considered sooner our power requirements, we would have realized that we could accomplish what we needed with no more than two cables, if not one. Most importantly, we attempted something we weren’t initially sure of or comfortable with and put our best effort into learning and creating our vision as we progressed—and there’s got to be some value in that.

Of course, even with hectic nature of our design process, working with Jim was always a pleasure. Besides being a clearly brilliant and impressive human being, father, grandfather, and husband, he was always more than willing to be involved in the project with us. As we struggled during our initial ideation, he and his wife helped a lot by continually pressing the conversation even when it seemed to reach a lull—suggesting new ideas and probing our thoughts as we worked together on a solution. After our prototype, we spent nearly an hour considering the different features that could be considered for a fountain of this time. Everything from the visual design and form (we had initially considered modeling something after Falling Water) to the stats we could provide in terms of estimated humidification time (something we would have had to derive using the diffusion equation).

Though we didn’t spend much time with him, working with Jim was certainly the of this experience. He was never short or impatient—always friendly and intensely curious about not only our ideas and our lives. Although we never expected anything different, we know it couldn’t have been easy dealing with some of our shortcomings and for that we thank and learn from him. He gave us a chance and we were given the opportunity to deliver on something that at times I’m not sure any of us believed that we actually could.

Technical details

Code

Main fountain part code

#include <AutoPID.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <PololuLedStrip.h>

RF24 radio(9, 10); // CE, CSN

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

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

// LED DEFINITIONS
const int HumOutputPin = 3; // humidifier control pin

int HUMIDITY_SETPOINT = 0;
int RangeLow = HUMIDITY_SETPOINT-10;   // humidity low range
int RangeHigh = HUMIDITY_SETPOINT+10;  // humidity high range

//PIN DEFINITIONS
const int SETPOINT_POT = A0;
const int LOW_VOLTAGE_PIN = 5;

//Radio Defintions:
const byte address[6] = "00001";
const unsigned int RADIO_UPDATE = 1000; //Update period in ms

//Controller Definitions
const double KP = .12;
const double KI = .0003;
const double KD = 0.0; //No Derivative Control Needed

const unsigned long HUMIDITY_READ_DELAY = 30000; //Every ~30s humidity is read

const double OUTPUT_MIN = 60; //Minimium output speed is every 60 min
const double OUTPUT_MAX = 1; //Maximum output speed is every 1 min

//Controller Global Variables
int motor_val = 0;
double setPoint, outputTiming; 
unsigned long lastUpdate; //Time of last PID updated

double humidity = 0.0;

int transmit_state = 0;

int setpoint = 0;

int humidity_timing = 60; //Time in seconds between puffs
const char Lchar = 'L';
const char Vchar = 'V';
const char Rchar = 'R';

AutoPID controller(&humidity, &setPoint, &outputTiming, OUTPUT_MIN, OUTPUT_MAX, KP, KI, KD);

void setup() {
  //Pin Setup
  pinMode(SETPOINT_POT, INPUT);
  pinMode(LOW_VOLTAGE_PIN, OUTPUT);
  digitalWrite(LOW_VOLTAGE_PIN, HIGH);

  //LED SETUP
  pinMode(HumOutputPin, OUTPUT);
  
  Serial.begin(9600);

  //Radio Setup
  radio.begin();
  radio.openReadingPipe(0, address);   //Setting the address at which we will receive the data
  radio.setPALevel(RF24_PA_MIN);       //You can set this as minimum or maximum depending on the distance between the transmitter and receiver.
  radio.startListening();              //This sets the module as receiver

  //Humidifier Setup
  setpoint = digitalRead(SETPOINT_POT);
  char text[32] = "";
  
  //Controller Setup
  controller.setBangBang(10); //Possible range is +- 10%
  controller.setTimeStep(4000); //Update PID every 4 secs
  delay(1000);
  digitalWrite(LOW_VOLTAGE_PIN, LOW);
}

void loop() {

  if(humidity < RangeLow) {
    humidifierWrite(true);
  } else {
    humidifierWrite(false);
  }

  // set led colors based on humidity
  updateLED(humidity);
  
  HUMIDITY_SETPOINT = analogRead(SETPOINT_POT);
  HUMIDITY_SETPOINT = map(HUMIDITY_SETPOINT,0,1023,0,100);
  RangeLow = HUMIDITY_SETPOINT - 10;
  RangeHigh = HUMIDITY_SETPOINT + 10;

  //Radio Code
  char text[32] = "";                 //Saving the incoming data
  double tempVal;

  if (radio.available()) {
    radio.read(&text, sizeof(text));    //Reading the data
    radio.read(&tempVal, sizeof(humidity));    //Reading the data
 
    if(text[0] == Rchar) {
      // Read failure
      Serial.println("Read Failure");
    } else if(text[0] == Lchar){
      // Low voltage
      //Don't update the humidity;
      digitalWrite(LOW_VOLTAGE_PIN, HIGH);
      Serial.print("Turn on LED on PIN ");
      Serial.println(LOW_VOLTAGE_PIN);
    } else if (text[0] == Vchar) {
      // Voltage fine
      digitalWrite(LOW_VOLTAGE_PIN, LOW);
    }else{
      humidity = tempVal;
    }
    Serial.println(text);
    Serial.println(humidity);
  }
  //Updating PID
  setPoint = analogRead(SETPOINT_POT);
  controller.run();

  humidify(outputTiming);

  delay(500);
} 

bool checkRadio(char *text, double *humidity) {
  static unsigned long lastUpdate = millis(); //Only happens onces
  if(lastUpdate > millis()) lastUpdate = millis(); //for overflow condition
  if(millis() - lastUpdate > RADIO_UPDATE) {
    if(radio.available()) {
      radio.read(text, sizeof(*text));
      radio.read(humidity, sizeof(*humidity));
      if(text[0] == Rchar) {
        Serial.println("Read Failure");  
      } else {
        Serial.println(*text);
        Serial.println(*humidity);
      }
    }
    return true;
  } else {
    return false;
  }
}

// Converts a color from HSV to RGB.
// h is hue, as a number between 0 and 360.
// s is the saturation, as a number between 0 and 255.
// v is the value, as a number between 0 and 255.
rgb_color hsvToRgb(uint16_t h, uint8_t s, uint8_t v)
{
  uint8_t f = (h % 60) * 255 / 60;
  uint8_t p = (255 - s) * (uint16_t)v / 255;
  uint8_t q = (255 - f * (uint16_t)s / 255) * (uint16_t)v / 255;
  uint8_t t = (255 - (255 - f) * (uint16_t)s / 255) * (uint16_t)v / 255;
  uint8_t r = 0, g = 0, b = 0;
  switch((h / 60) % 6){
    case 0: r = v; g = t; b = p; break;
    case 1: r = q; g = v; b = p; break;
    case 2: r = p; g = v; b = t; break;
    case 3: r = p; g = q; b = v; break;
    case 4: r = t; g = p; b = v; break;
    case 5: r = v; g = p; b = q; break;
  }
  return rgb_color(r, g, b);
}

void humidifierWrite(bool state) {
  if(state) {
    digitalWrite(HumOutputPin, HIGH);
  } else {
    digitalWrite(HumOutputPin, LOW);
  }
}

void updateLED(int humidity) {
  uint16_t time = millis() >> 2;
  if(!humidity) return;
  if(humidity < RangeLow) {
    // update all colors to red
    for(uint16_t i = 0; i < LED_COUNT; i++) {
      colors[i] = rgb_color(255, 0, 0);
    }
  } else if(humidity > RangeHigh) {
    // update all colors to blue
    for(uint16_t i = 0; i < LED_COUNT; i++) {
      colors[i] = rgb_color(0, 0, 255);
    }
  } else {
    for(uint16_t i = 0; i < LED_COUNT; i++) {
      byte x = (time >> 2) - (i << 3);
      colors[i] = hsvToRgb((uint32_t)x * 359 / 256, 255, 255);
    }
  }
 
  // Write the colors to the LED strip.
  ledStrip.write(colors, LED_COUNT);

  delay(10);
}

Remote part code

#include <SPI.h>
#include <nRF24L01.h>
#include "cactus_io_AM2302.h"
#include <RF24.h>
#include "LowPower.h"

const int VOLTAGE_CHECK_THRESHOLD = 30000;
const int RADIO_THRESHOLD = 50;
const int LOW_VOLTAGE_THRESHOLD = 650; //Corresponds to just around 5.5V
const int HUMIDITY_PIN = 4;
const int VOLTAGE_PIN = A1; //Measuring low voltage state
AM2302 dht(HUMIDITY_PIN);

RF24 radio(9, 10); // CE, CSN         

const byte address[6] = "00001";     //Byte of array representing the address. This is the address where we will send the data. This should be same on the receiving side.
int transmit_state;

long unsigned int last_voltage_check = 0;
long unsigned int last_transmission = 0;

void setup() {
  pinMode(HUMIDITY_PIN, INPUT);
  pinMode(VOLTAGE_PIN, INPUT);
  radio.begin();                  //Starting the Wireless communication
  radio.openWritingPipe(address); //Setting the address where we will send the data
  radio.setPALevel(RF24_PA_MIN);  //You can set it as minimum or maximum depending on the distance between the transmitter and receiver.
  radio.stopListening();          //This sets the module as transmitter
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  if(millis() < last_voltage_check) last_voltage_check = millis(); //Overflow condition
  if(millis() < last_transmission) last_transmission = millis();


  if(millis()-last_voltage_check > VOLTAGE_CHECK_THRESHOLD) { //Low voltage handling condition
    last_voltage_check = millis();
    if(analogRead(VOLTAGE_PIN) < LOW_VOLTAGE_THRESHOLD) { //Voltage is less than 5v 
      
      const char low_voltage_text[32] = "Low Voltage"; 
      double dummy = analogRead(VOLTAGE_PIN);
      radio.write(&low_voltage_text, sizeof(low_voltage_text));
      radio.write(&dummy, sizeof(dummy));
      Serial.println("Voltage LOW: ");
      Serial.println(analogRead(VOLTAGE_PIN));
      
    } else {
        const char ok_voltage_text[32] = "Voltage Fine";
        double dummy = (double)analogRead(VOLTAGE_PIN);
        radio.write(&ok_voltage_text, sizeof(ok_voltage_text));
        radio.write(&dummy, sizeof(dummy));
        Serial.println("Voltage ok");
        Serial.println(analogRead(VOLTAGE_PIN));
    }
    delay(4000);
  } 

  if(millis()-last_transmission > RADIO_THRESHOLD) {
    last_transmission = millis();
    dht.readHumidity();
    dht.readTemperature();
    const char success_text[32] = "Transmitting: ";
    const char failure_text[32] = "Read Failure";
    bool failure = false;
    if(isnan(dht.humidity) || isnan(dht.temperature_C)) {
      failure = true;
    }
  
    double humidity = dht.humidity;

    Serial.println(humidity);
  
    transmit_state = millis();
    if(failure) {
      radio.write(&failure_text, sizeof(failure_text));
    } else  {
      radio.write(&success_text, sizeof(success_text));  
    }
    radio.write(&humidity, sizeof(humidity));  //Sending the message to receiver 
    delay(4000); 
  }
}
Schematic and design files

Main fountain part schematic

Main fountain part schematic

Main fountain module schematic

Remote fountain module schematic

The Schematic of the Remote Transmission Module. Uses a voltage divider to map the input voltage (normally > 5v) to a range that is readable by the Arduino’s ADC through pin A1 that allows it to detect low input voltages.

 

]]>
Trivia Machine by Team Enid: Final Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/trivia-machine-final-documentation/ Sat, 14 Dec 2019 00:28:23 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=9014
Introduction

Team Members: Neeharika, Mike, Maria, and Enid

Tasked to create a device that could help an older individual, we worked closely with Enid to see what she needed assistance within her daily life. She noted that she often finds the cleaning-up process after a meal to be boring and tedious, and would like a way to make it less so. Keeping in mind that she enjoys books, movies, and puzzles, we decided to combine her interests in creating a Trivia Machine that she can keep in her kitchen and keep her entertained. Since cleaning up can get her hands messy, she can play the game in a hands-free way by waving a utensil in a designated answer slot to lock in her answer. The retro-futuristic design both stands out yet integrates well within the appliances in a common kitchen. The device can be hung in the kitchen off of a cabinet for easy viewing, or can be removed and taken anywhere around the house in a portable fashion. 

You can see our Initial Meeting documentation here and our Prototype Documentation here

 

What We Built

This device displays a question on the top screen and up to four answer choices on the bottom screen, waiting for the user to select an answer. In order to do so, hold a fork, spoon, small plate or even your hand in the answer area you want to select (Red for 1st option, Orange for 2nd option, Yellow for 3rd option and White for 4th option). Once selected, the bottom screen will tell you if you are right or wrong, and what the correct answer is. It then displays a new question/answer set and repeats this process.

Front View, removable panel on the side reveals battery pack

Back View

Side View

Other side view

Shot of the answering portion, you can see the bulbs within each section and the ultra sonic sensor at the top

Easily accessible battery pack, just pop open the panel!

Example of how to answer – LED indicates which section you are in

Placed in the kitchen

Trying it out for the first time, device can also sit on any surface

Video 1: How to use the device

Video 2: How to change the batteries

Narrative Sketch:

Enid and her husband have just finished dinner. By the end of the day, they always end up extremely tired and the boring activity of cleaning the dishes makes their fatigue even worse.  Both enter the kitchen to place the plates into the sink. And there it hangs, the Trivia Machine. Enid turns the switch on and the game starts. Forks,  spoons, plates all are turned into game parts to answer the trivia questions. After half an hour all the plates are clean. After two hours, Enid and her husband go eventually to sleep!

How We Got Here

We started off with many ideas about what to build for Enid but we quickly converged on two contenders – a plant watering/monitoring system and a trivia machine. We decided against the first option because many commercial solutions are already available. A trivia machine would be more personal and allow us to explore and leverage physical interactions between the user and the device in a more interesting way.

Because we wanted the device to be usable while Enid is doing dishes, we began by exploring different hands-free methods of interaction. In terms of delivering questions, we wanted to explore the option of using text-to-speech. However, this would require connecting to the internet for an online API, which we decided was too ambitious for the timeframe. Additionally, Enid did not want yet another internet device in her home. We decided on using two liquid crystal displays for the question and answer options, respectively.

We wanted to integrate the answering process with the dishwashing process. The basic principle was to allow the player to “lock in” on an answer choice via a utensil or plate that is being cleaned. We decided against any method of detecting a “lock” with contact between the potentially dirty dishes and electronic components. We decided to use the distance between an object as input for the device, and tested different ways of measuring proximity. The laser time-of-flight sensor proved to be inaccurate with different ambient light conditions and material, and the ultrasonic ranger had adequate accuracy for our design.

Based on the prototype crit, we scaled down the device and improved the way in which questions are displayed on the LCDs for better viewing.

Scaling down the device involved rethinking the way in which distance sensing was done. Enid was concerned that large objects would accidentally come into sensing range, so we restricted the sensing area to within the dimensions of the device. This meant the the answer choice regions can only accept small utensils or fingers as input. 

The new device would be suspended in front of Enid at a distance that is reachable but not obtrusive

An early design for the scaled-down version. We decided to flatten out the bottom to make the device able to stand freely.

We also wanted to make the device portable, so that Enid can remove the device when she wanted to. This also allowed for other use cases, where the game can be played anywhere with a flat surface. This also means making the device battery powered, and we decided on placing the battery pack on the panel that would be leaning against the wall.

The first printed design contained many dimension errors that were corrected in the final version.

After the first print, we also removed the hanging ledge in the question selection area, added a removable panel for batteries, and added a power switch on the top side. Out of concern that the second print will not be printed in time, we also explored other enclosures that could be laser cut.

A more box-like design that could be created more quickly, but less aesthetically pleasing.

However, we managed to reduce the print time by subdividing the entire body into sections that are later assembled together. We also added LEDs behind the answer selection region to provide better feedback to the user who is selecting the answers.

One of the three segments of the enclosure. Here we are test fitting the LEDs and ultrasonic ranger.

Protoboards inside the enclosure for the final product. The screens are also secured, but can be removed if necessary.

The second major issue raised from the prototype crit was the method in which questions were displayed. Because some questions were too long to be displayed on the LCD, we used a “scrolling” method to display the text, using only one of the 4 lines on the LCD.

The original side scrolling display that was too difficult to read.

Per Enid’s suggestion, the questions that are too long to be displayed in a screen are “scrolled” from top to bottom. Because Enid would not be constantly viewing the screen while cleaning, we looped the scrolling and added a long pause at the beginning of each loop to indicate the beginning of a question. Unfortunately, the answer options that are too long still needed to be scrolled from side to side. We reduced the speed of the scrolling and added a pause at the beginning to reduce the cognitive overhead of figuring out how to read the screen.

The new display method, with the questions filling the full screen and the answers scrolling (if necessary).

After addressing these major issues, we also added over 1700 new questions to the SD card and a strap for hanging the machine on the cabinet walls. Finally, we sealed the segments together for delivery.

The finished assembly before glueing.

Generally, we followed our anticipated/loose schedule. We were briefly concerned about the  3D print time, but we managed to finish assembly on time.

Final Crit

During the final feedback session, we were able to show the final product to Enid as well as getting feedback from our peers and other members of the community. Some good points and suggestions were made:

  • “The sensing action is demanding as it requires a floating hand in space with precision at arm’s length” – This was a common point brought up by many people. While it was easy for us to hold a utensil in the air for a couple seconds, we can see why it may be difficult for an elderly user, especially one that may have Arthritis or Parkinson’s, to do the same motion. This is a critical component of the mechanism of answering, and in our eyes was key to keeping the device clean from anything that may be on the hands or utensil. However, what we could do to remedy this accessibility issue and keep a somewhat clean device is to create small ledges or nubs in the back of the answer space that the user can rest the utensil on, but not let go of, to alleviate some pain. This way, one can still use the utensil to keep answering questions, but if it is getting tiring, they can use the small ledge to relax.
  • “Sensor position below would make it more playable and have stronger ties to dishwashing” – This was another good point brought up. This means that instead of having the answer space to the right of the device and in a vertical orientation, it would be below the device in a horizontal orientation. In this design, it may be easier to bring dishes and forks under to the answer space right out of the sink that in our current design. Actually, this was one of the initial designs we had in mind, but Enid indicated to us that she liked the version we have now better. It’s all up to preferences about the user.

Major takeaways 

This was the first time the members of our team built something for an elderly individual. Before starting this project, we learned a little in class about potential hardships the elderly community faces. It turns out that there are a lot of things that we take for granted as young, abled people that may be difficult for someone else. Thinking about potential projects to pursue required us to put ourselves in another person’s shoes and try to see the world from their perspective, and what they could potentially want in design and utility. Our meetings with Enid proved to be very useful to collect this kind of information. 

On a similar note, we learned how truly meaningful feedback can be. Every meeting with Enid, we were able to present our current stage in development and receive ideas about certain things that should be changed to make the device more effective for her. Usually, during development, we tend to get very wrapped up in the technical aspects. However, the various feedback sessions allowed us to step back and look at the bigger picture, especially from the user’s perspective.

Being part of a team is a lot of work but ultimately a rewarding experience. Clear communication between members and equal participation is critical for a well functioning team. However, no matter how enthusiastic we were to complete this project, we learned that things definitely take a lot more time than what is expected. Certain small tweaks we thought would take a day ended up taking a week. Keeping this in mind while pursuing any project is good preparation for the many hours of work ahead.

Concluding Thoughts

If we were to continue building on this project, we would probably want to integrate some sort of voice capabilities that would rid the need to have to look at a tiny LCD. We could use basic text-to-speech to read both questions and answers to make it easier to still perform tasks in the kitchen. We could also add a score-keeping system too, where a user could set the number of players and the device could keep track of each player’s points to declare a definite winner. Right now, the device has a fixed ~1700 questions in its bank, but if we had internet capabilities, we would be able to dynamically request many, many more – perhaps it would never run out! With this, Enid would be able to select her favorite categories as well, allowing for even more personalization. 

It was an amazing experience to work with Enid to create the Trivia Machine. We were able to dive into many different branches of product development – electronics, software, design, and fabrication – all while receiving valuable feedback along the way. We hope that Enid and her husband enjoy using the Trivia Machine, and hopefully now cleaning up is a little less boring!

Technical Details

Code

/*
 * Trivia Machine Arduino Code
 * Code for the Arduino in the Trivia Machine.
 * The code reads a random question from the SD card,
 * Display the question and answer options on two LCDs,
 * and awaits input from the ultrasonic ranger. After a 
 * question is answered, the screen displays feedback and 
 * resets the Arduino.
 * 
 * Pins:
 *  Ultrasonic Ranger
 *    Echo: D3
 *    Trig: D2
 *    
 *  LEDs
 *    Option A: D7
 *    Option B: D6
 *    Option C: D5
 *    Option D: D4
 *    
 *  LCDs - I2C SDA and SCL
 *  SD Card: 
 *    MOSI -  11
 *    MISO -  12
 *    CLK -   13
 *    CS -    10
 *    
 *  Connect Pin A0 to the Reset pin
 */

#include <SPI.h>
#include <SD.h>
#include <LiquidCrystal_I2C.h>

const int WIDTH = 20;
const int HEIGHT = 4;

LiquidCrystal_I2C lcd0(0x27, WIDTH, HEIGHT);
LiquidCrystal_I2C lcd1(0x23, WIDTH, HEIGHT);

const int TRIGPIN = 2;
const int ECHOPIN = 3;
const int RESET_PIN = A0;


// New Stuff
const int LEDAPIN = 7;
const int LEDBPIN = 6;
const int LEDCPIN = 5;
const int LEDDPIN = 4;

//LCD Display Params
const int ANS_CHANGE_THRESHOLD = 2000;
const int SCREEN_CHANGE_THRESHOLD = 1500;
const int INITIAL_SCREEN_FACTOR = 2;
const int EXTRA_SCROLLS = 2;
const int OPTION_CHANGE_THRESHOLD = 500;
const int NUM_QS = 1703;


File file;

const int arrayLength = 5;
int lines = 0;
String qArray[arrayLength];
int perm[arrayLength - 1];

void setup()
{
  digitalWrite(RESET_PIN, HIGH);
  pinMode(TRIGPIN, OUTPUT);
  pinMode(ECHOPIN, INPUT);
  pinMode(RESET_PIN, OUTPUT);
  // New Stuff
  pinMode(LEDAPIN, OUTPUT);
  pinMode(LEDBPIN, OUTPUT);
  pinMode(LEDCPIN, OUTPUT);
  pinMode(LEDDPIN, OUTPUT);

  digitalWrite(RESET_PIN, HIGH);
  Serial.begin(9600);
  delay(analogRead(A2));
  randomSeed(analogRead(A1)*analogRead(A2)+ analogRead(A3));
  Serial.println();

  lcd0.init();
  lcd0.backlight();
  lcd0.home();
  lcd0.noAutoscroll();

  lcd1.init();
  lcd1.backlight();
  lcd1.home();
  lcd1.noAutoscroll();

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(10)) {
    while (1);
  }

  //open the file here
  lines = loadQuestions(String(random(NUM_QS)) + ".TXT", qArray);
  permute(lines - 1, perm);
  lcd0.setCursor(0, 0);
  //scrollQ(qArray[0]);
  displayAns(qArray, perm, lines, 0);
}

void loop() {
  //scroll answers
  static int screenInd = 0;
  static long lastS = 0;
  int numofScreens = INITIAL_SCREEN_FACTOR + qArray[0].length() / (WIDTH) - HEIGHT + EXTRA_SCROLLS;
  if (millis() - lastS > SCREEN_CHANGE_THRESHOLD) {
    lastS = millis();
    if (screenInd == 0 || screenInd > INITIAL_SCREEN_FACTOR) {
      printQScreen(qArray[0], max(screenInd - INITIAL_SCREEN_FACTOR, 0));
    }
    screenInd = (screenInd + 1) % (numofScreens);
  }

  //scroll questions
  static int optOffset = 0;
  static long lastScroll = 0;
  if (millis() - lastScroll > OPTION_CHANGE_THRESHOLD) {
    lastScroll = millis();
    displayAns(qArray, perm, lines, optOffset);
    optOffset++;
  }

  //lock in on choices
  static long lastChange = millis();
  static int lastChoice = 0;
  int dist = getDist();
  int choice = map(dist, 0, 120, 0, 6);
  if (lastChoice != choice) {
    lastChange = millis();
  }

  if (1 <= choice && choice < lines) {
    lcd1.cursor();
    lcd1.blink();
    lcd1.setCursor(19, choice - 1);
    if (millis() - lastChange > ANS_CHANGE_THRESHOLD) {
      feedbackAndReset(perm[choice - 1] == 0, qArray[1]);
    }
  } else {
    lcd1.noCursor();
    lcd1.noBlink();
  }

  lightLEDs(choice);

  lastChoice = choice;
  delay(100);
}


int loadQuestions(String path, String arr[]) {
  file = SD.open(path, FILE_READ);
  int index = 0;
  while (file.available()) {
    //A inconsistent line length may lead to heap memory fragmentation
    arr[index] = file.readStringUntil('\n');
    arr[index].trim();

    index++;
  }
  file.close();
  return index;
}

//Generate random permutation of n numbers
void permute(int n, int perm[]) {
  int ord[n];
  for (int i = 0; i < n; i++) {
    ord[i] = i;
  }
  for (int i = 0; i < n; i++) {
    int ind = random(n - i);
    perm[i] = ord[ind];
    for (int j = ind; j < n - 1; j++) {
      ord[j] = ord[j + 1];
    }
  }
}

//get Distance from ultrasonic
int getDist() {
  digitalWrite(TRIGPIN, LOW);
  delayMicroseconds(5);
  digitalWrite(TRIGPIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGPIN, LOW);
  long duration = pulseIn(ECHOPIN, HIGH);
  int distance = duration * 0.34 / 2;
  Serial.println(distance);
  return distance;
}

//Display answer choices and scroll
void displayAns(String qArray[], int perm[], int lines, int offset) {
  for (int i = 0; i < lines - 1; i++) {
    lcd1.setCursor(0, i);
    int scrollsNeeded =
      qArray[perm[i] + 1].length() - (WIDTH - 2) + INITIAL_SCREEN_FACTOR + EXTRA_SCROLLS;
    if (scrollsNeeded <= INITIAL_SCREEN_FACTOR + EXTRA_SCROLLS) {
      lcd1.print(qArray[perm[i] + 1]);
    } else {
      int cur_off = offset % (scrollsNeeded) - INITIAL_SCREEN_FACTOR;

      if (-INITIAL_SCREEN_FACTOR < cur_off && cur_off < 1) {
        continue;
      }

      cur_off = max(cur_off, 0);
      lcd1.print("                   ");
      lcd1.setCursor(0, i);
      lcd1.print(qArray[perm[i] + 1].substring(cur_off, cur_off + WIDTH - 2));
    }
  }
}

//Send reset signal
void feedbackAndReset(bool correct, String ans) {
  lcd1.noCursor();
  lcd1.noBlink();
  lcd1.clear();
  lcd1.home();

  if (correct) {
    lcd1.print("Correct!");
  } else {
    lcd1.print("Incorrect.");
    lcd1.setCursor(0, 1);
    lcd1.print("Correct Answer is:");
    lcd1.setCursor(0, 2);
    lcd1.print(ans);
  }

  delay(1000);
  digitalWrite(RESET_PIN, LOW);
}

//Print question based on screen index
void printQScreen(String q, int s) {
  int qLen = q.length();
  int area = WIDTH * HEIGHT;

  if (qLen <= area) {
    for (int i = 0; i < qLen; i++) {
      int x = i % WIDTH;
      int y = i / WIDTH;
      lcd0.setCursor(x, y);
      lcd0.print(q[i]);
    }
    return;
  }

  lcd0.clear();
  for (int i = 0; i < area && ((s * WIDTH) + i) < qLen; i++) {
    int x = i % WIDTH;
    int y = i / WIDTH;
    lcd0.setCursor(x, y);
    lcd0.print(q[(s * WIDTH) + i]);
  }
}

void lightLEDs(int choice) {
  digitalWrite(LEDAPIN, LOW);
  digitalWrite(LEDBPIN, LOW);
  digitalWrite(LEDCPIN, LOW);
  digitalWrite(LEDDPIN, LOW);
  switch (choice)
  {
    case 1:
      digitalWrite(LEDAPIN, HIGH);
      break;
    case 2:
      digitalWrite(LEDBPIN, HIGH);
      break;
    case 3:
      digitalWrite(LEDCPIN, HIGH);
      break;
    case 4:
      digitalWrite(LEDDPIN, HIGH);
      break;
    default:
      break;
  }
}

Schematic diagram of wiring

 

]]>
Exercise Reminder Clock (by Team J.A.N.): Final Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/exercise-reminder-clock-by-team-j-a-n-final-documentation/ Fri, 13 Dec 2019 21:42:27 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8951 The Intro:

This Exercise Clock was created as a final project submission for CMU Ideate’s Physical Computing class. Our prompt was to meet with an older person in our community (selected for us from CMU’s OSHER classes) and create an assistive device personalized to them.

Our group was paired with Jan, and through our previous discussions with her, we learned that she enjoyed going on walks, but felt that she wasn’t as active as she should be. Since she didn’t care for the exercise apps she had tried, we created a prototype clock for her to use to track her physical activity.

We then finalized the project with this version, according to Jan’s feedback to the prototype.

The Product:

Our final product is a clock that reminds Jan to exercise and keeps track of how long she exercises. The clock cycles between three screens,  the first displays the time and date, the second displays bar graph of how long Jan exercised each day for the past two weeks, and the third compares the time Jan spent exercising the current week and last week. There is also a row of LEDs that display how many days from the past week that Jan has exercised. If Jan hasn’t met her exercise goal for the day, the clock will beep every hour if it senses someone in the room. When the button is pressed, the screen displays a timer.  When the button is pressed again, the timer is turned off and the time is added to the graph and if the exercise goal is met, one of the LEDs turns on. There is also a mute switch that puts makes the screen dim and makes the clock stop beeping.

Overall Photo:

An overall photo of our final product.

Basic Operation:

Pressing the button to start and stop the timer.

Twisting the button to set the time.

Flipping the mute switch on and off.

Detail Photos:

The display showing the time and date.

The display showing the graph of time spent exercising for the past two weeks.

The display comparing the amount of exercise this week and last week.

The display when the clock is in muted mode.

The LED row with one LED on, and the motion sensor.

The speaker and the off switch.

Usage Photos:

Pressing the button to stop the timer.

Turning the button to set the time and date.

Flipping the switch and putting the clock in muted mode.

The Process:

Following the formative critique, we created a schedule to guide us through the remainder of the project.

After completing our prototype we created this plan to finish the project.

Our first tasks were to complete the functionality of the device, and we were able to stay on schedule while doing so.

We wanted Jan to be able to view her recent workout history from a distance.   Our group decided to use a row of 7 Red-Green LED’s on our reminder clock to display the information in an manner that was easily noticeable but not out of place in her kitchen.  Each Red-Green LED would represent a day in the past week, appearing green if she worked out but red otherwise.  The easiest way to attach these lights would be with one pin per color for every light, which would use 14 pins.   However, due to the limited number of outputs on the Arduino we needed to condense this feature into just 7 pins.  To achieve this goal, we took advantage of each light only needing to be red or green at a certain time and used transistors to select between the two options with a single pin.   We also ran into early problems powering all 7 Red-Green LEDs at once, but using the 5v pin as the main power source for the lights fixed this problem for the time being.

Initial ideas for reducing the number of pins needed for the LEDs.

Our final circuit for the Red-Green LEDs.

Furthermore, Jan mentioned multiple features that she believed would improve her experience with the device.  She worried that the clock would continue to provide alerts while she was out of town with her neighbor looking after the house.  Our group decided to include a mute switch which dimmed the screen and stopped alerts in this situation.  She also expressed multiple concerns about the longevity of the device, so we decided on several changes to improve this area.  We added a more precise time keeping element, so the clock would skew less overtime.  In software, we fixed bugs that would occur when the date had an overflow error.  Also, for any unexpected errors ,as well as daylight savings time and leap years, we added the ability to change the time and date manually.  This feature required a new input to choose between times, so we changed the button on the device into a rotary encoder to increase the functionality while keeping the interface minimal.

The rotary encoder we replaced our button with to enable the time changing functionality.

A test of changes we made to our code to prevent overflow errors.

After completing the functionality of the reminder clock we began to assemble the final product, but the construction took longer then we anticipated.  We originally planned to finish before Thanksgiving break, but our group had to do considerable work after we returned.  This delay was largely due to us underestimating the work needed to finish the case.  When initially designing the outside, we combined math and intuition to create an overall shape.  We wanted the device to be large enough to sit between two wall trims without leaving too much space, and the top to be at an angle that she could easily view while standing.

A sketch used in deciding the angle of the clock’s top.

Our first setback in manufacturing occurred when choosing how to assemble the case.  We originally designed a file to 3d print, but afterwards decided to change to laser engraving due to size constraints on the 3d printer.  When we tried to assemble our final box our group faced multiple other issues.  We decided to use a “5 minute” epoxy to connect the pieces.  However, we did not mix the components correctly, which created a messy layer of residue on our product.  This initial failure made later attempts to glue box less effective, as the original epoxy blocked the new adhesive.  Later, when putting components into the box, we accidentally shattered one of the sides.  These two errors led to us re-engraving the case.  The second time was much neater, as we were more careful and used acrylic glue.

A cardboard prototype of our box used to optimize hole sizes before our final print.

A shattered side of our box after a panel mounting accident.

Unfortunately, when assembling the final circuitry using an Arduino nano we ran into a problem powering all 7 LEDs similar to our earlier issue.  This time, however, our solution of using the 5v pin as the main power source for the lights was not working.  Since we had fallen behind schedule, we did not have time to solve this problem, so we decided to replace the Red-Green LEDs with normal LEDs for our final clock.

The Red-Green LEDs were replaced with simple blue LEDs due to problems when making the final circuitry.

The Feedback:

Our project received mostly positive feedback, though, some valid criticisms and suggestions were raised. One commenter noted, for example, that

“LED lights + day of week on display should go in same direction”

in reference to the fact that our LED display on the front of the device represented the most recent day on the left of the device, while our bargraph on the LCD had  the most recent day on the right. This is an aspect of the device we hadn’t noticed, however changing it did make the different displays of the device more intuitive to comprehend at a glance.

Another comment we received regarded the physical presence of the device:

“Consider making the knob a bit bigger – it might make it easier to use.”

As a group, we also agreed with this criticism, to the extent that we were originally planning to make the knob much larger than it is currently in our final project. While unfortunately we weren’t able to get the custom part created in time, Jan at least seemed pleased with the replacement knob we did end up using.

One of the most important things we learned while creating something for another person, is the importance of listening. Many of the design choices we made to customize this clock for Jan were the result of minor comments she made during the interview process. Things like the size of the device, and our method of interaction we as effective as they could be because we noted specifically how Jan expected to use the device.  If we were to do this project another time, we would most likely pay more attention to the physical for and aesthetics of the device earlier in the design process, to ensure we wouldn’t have another plastic box panic the night before the project was due.

If we were to do this project again, one of the most useful modifications to the design process would be to include some time for “beta testing.” While we were able to demonstrate a prototype of our project to Jan to get some basic feedback, the feedback we got was somewhat limited in that we collected it in a classroom setting. Being able to let Jan take the device home with her for a few days of testing could potentially bring light to some more minor issues which we wouldn’t be able to discover within a classroom environment.

The Details:

The electrical schematic of our project.

The Code:

/*
 * Workout_Clock.ino
 * 
 * Exercise Reminder Clock
 * Karen Abruzzo, Justin Kiefel, George Ralph
 * 
 * This code runs a clock, which can be used to track the duration of
 * exercise intervals with stopwatch-like functionality whenever TIMER_BUT_PIN
 * is pressed. The clock also tracks exercise history over a 2 week period, 
 * and reminds the user through audio tones to exercise whenever they are 
 * detected by the motion sensor. (Though this feature can be disabled)
 * 
 * Inputs
 *    0   -   Motion Sensor
 *    2   -   Rotary Encoder Clock Pin
 *    3   -   Rotary Encoder Data Pin
 *    4   -   Rotary Encoder Button
 *    5   -   Power/Mute Switch
 * 
 * Outputs
 *    6     - Speaker Pin
 *    7..13 - Bargraph LEDs
 *    
 * Outputs
 * 
 * NOTE: This project must be compiled with compiler warnings disabled due to 
 *       aspects of the libraries we use, which are beyond our control.
 */

#include <Encoder.h>
#include <Wire.h>
#include <DS3231M.h> //library for the rtc
#include <LiquidCrystal_I2C.h>
#include "pitches.h"

/* Create an LCD display object called "screen" with I2C address 0x27
   which is 20 columns wide and 4 rows tall. You can use any name you'd like. */
LiquidCrystal_I2C screen(0x27, 20, 4);
DS3231M_Class DS3231M;

//Make buffer size the size of the screen area, just to be safe
const uint8_t  SPRINTF_BUFFER_SIZE = 80;
char inputBuffer[SPRINTF_BUFFER_SIZE];

const uint32_t SERIAL_SPEED = 115200;
const int MOTION_PIN         = 0;
const int ENC_CLK_PIN        = 2;
const int ENC_DT_PIN         = 3;
const int TIMER_BUT_PIN      = 4;
const int POWER_SWITCH       = 5;
const int SPEAKER_PIN        = 6;
const int LED_BASE_PIN       = 7;

const int LED_CNT = 7;

//Goal time is 40 minutes
const int GOAL_TIME = 60*40;

Encoder enc(ENC_CLK_PIN, ENC_DT_PIN);

const char weekLetters[] = {'S', 'M', 'T', 'W', 'H', 'F', 'S'};
const String weekDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};


// 2 = half note, 4 = quarter note, ect.

int openSound[] {2, 8, 8, NOTE_B3, NOTE_B4};
int workoutSound[] {2, 8, 16, NOTE_B3, NOTE_B5};
int clockSound[] {1, 8, NOTE_A5};
int sadSound[] {2, 4, 4, NOTE_F3, NOTE_C3};
int happySound[] {4, 8, 8, 8, 8, NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5};


unsigned long start;
bool timerOn = 0;
int pastTimes[28];
int timeSeconds;
boolean isMidnight = false;


long lastPing = 0;
long pingTimeout = 3600;

bool advancePast = false;
bool timerPast = false;
long updateTime, buttonDownTime;
int screenState = 0;

bool pastPowerState = true;
bool powerState = true;

void setup() {
  // Initialize pins
  pinMode(TIMER_BUT_PIN, INPUT_PULLUP);
  pinMode(POWER_SWITCH, INPUT_PULLUP);
  pinMode(SPEAKER_PIN, OUTPUT);
  pinMode(MOTION_PIN, INPUT);

  digitalWrite(SPEAKER_PIN, LOW);
  
  //Initialize the LED pins as a consecutive block of pins
  for(int i = 0; i < LED_CNT; i++) {
    pinMode(LED_BASE_PIN + i, OUTPUT);
  }
  
  //setup pins
  //Serial.begin(SERIAL_SPEED);

  while (!DS3231M.begin())
  {
    //Serial.println(F("Unable to find DS3231MM. Checking again in 3s."));
    delay(3000);
  }

  // initialize the screen (only need to do this once)
  screen.init();
  screen.backlight();
  
  powerState = !digitalRead(POWER_SWITCH);
  pastPowerState = powerState;
  
  DateTime now = DS3231M.now();
  lastPing = now.unixtime();

  updateTime = millis();

  //setTime();
}

void loop() {
  bool timerState = !digitalRead(TIMER_BUT_PIN);
  bool powerState = !digitalRead(POWER_SWITCH);

  //On button down
  if (timerState && !timerPast) {
    buttonDownTime = millis();
  }

  //On button up
  if (!timerState && timerPast) {
    //If the button has been down for more than a second
    //Enter settings dialog
    if(buttonDownTime + 1000 <= millis()) {
      setTime();
    }
    else
    //Otherwise, start the timer
    {
      timer();
    }
    
    updateTime = millis() - 3000;
  }

  //In timer mode, draw the elapsed time so far
  if (timerOn) {
    //But only, once a second
    if ((updateTime + 1000) <= millis()) {
      drawTimer();
      updateTime = millis();
    }
  }
  else
  {
    if(powerState) {
      //Cycle the screen every 3 seconds when power is on
      if ((updateTime + 3000) <= millis()) {
        switch (screenState) {
          case 0:
            drawHome();
            break;
            
          case 1:
            drawWeekCompare(getTotalTime(14, 21), getTotalTime(21, 28));
            break;
            
          case 2:
            drawTwoWeekGraph(pastTimes);
            break;
        }
        
        updateTime = millis();
        screenState = (screenState + 1) % 3;  
      }
    }
    else
    {
      //Update the clock every few seconds when power is off
      if ((updateTime + 5000) <= millis()) {
        drawHome();
        updateTime = millis();
      }
    }

    //If no time is logged for today (and device is on)
    if (pastTimes[27] == 0 && powerState) {
      //If the motion sensor detects motion
      if (digitalRead(MOTION_PIN)) {
        //If it's been a while since we last pinged
        DateTime now = DS3231M.now();
        if (now.unixtime() >= (lastPing + pingTimeout)) {
          //Ping the user
          playSound(sadSound);
          lastPing = now.unixtime();
        }
      }
    }
  }

  if (isNewDay() && !isMidnight)
  {
    newDaySetup();
    isMidnight = true;
  }

  updateLEDs();
  
  //Turn the screen on/off if the power switch is flipped
  if (powerState != pastPowerState) {
    if (powerState) {
      screen.backlight();
      updateTime = millis();
    }
    else {
      screen.noBacklight();
      screenState = 0;
      drawHome();
    }

  }

  pastPowerState = powerState;
  timerPast = timerState;
}

/* The time-setting dialog menu */
void setTime() {
  screen.clear();

  //Grab the current time
  DateTime now = DS3231M.now();
  int hour = now.hour();
  int minute = now.minute();
  int day = now.day();
  int month = now.month();
  int year = now.year();
  
  //Initialize buffers to print before and after the number we choose
  char beforeBuffer[SPRINTF_BUFFER_SIZE];
  char afterBuffer[SPRINTF_BUFFER_SIZE];

  char* header = "      Set Time      ";

  //For each time, format the string around it with the previously set time
  sprintf(beforeBuffer, "%s (", header);
  sprintf(afterBuffer, "):%02d %d/%02d/%04d", minute, month, day, year);
  hour   = getNumInput(24,    beforeBuffer, afterBuffer,   hour, 0);
  
  sprintf(beforeBuffer, "%s %2d:(", header, hour);
  sprintf(afterBuffer, ") %d/%02d/%04d", month, day, year);
  minute = getNumInput(60,    beforeBuffer, afterBuffer, minute, 0);

  sprintf(beforeBuffer, "%s %2d:%02d (", header, hour, minute);
  sprintf(afterBuffer, ")/%02d/%04d", day, year);
  month  = getNumInput(12,    beforeBuffer, afterBuffer,  month, 1);

  sprintf(beforeBuffer, "%s %2d:%02d %2d/(", header, hour, minute, month);
  sprintf(afterBuffer, ")/%04d", year);
  day    = getNumInput(31,    beforeBuffer, afterBuffer,    day, 1);
  
  sprintf(beforeBuffer, "%s %2d:%02d %2d/%02d/(", header, hour, minute, month, day);
  sprintf(afterBuffer, ")");
  year   = getNumInput(10000, beforeBuffer, afterBuffer,   year, 0);

  DateTime newTime = DateTime(year, month, day, hour, minute, 0);
  DS3231M.adjust(newTime);

  //Make sure we show the clock screen after this
  screenState = 0;
}

/* Creates a number input dialog, with strings before and after the number 
   An initial value can be specified, 
   Input is modular about bound (ie 60 for values 0-59)
   The bound range can be offset via minOffset (ie 1 for 1-60 in the above example) */
int getNumInput(int bound, String before, String after, int initial, int minOffset) {
  int value = 0;
  int offset = enc.read() / -4;
  //Make the screen update at least once when we enter this dialog
  bool forceDraw = true;

  while (digitalRead(TIMER_BUT_PIN)) {
    int pos, oldPos;
    pos = (enc.read() / -4) - offset + (initial - minOffset);
    if (pos != oldPos || forceDraw) {
      value = ((pos + bound) % bound) + minOffset;
      screen.clear();
      screen.print(before);

      sprintf(inputBuffer, "%2d", value);
      
      screen.print(inputBuffer);
      screen.print(after);
      oldPos = pos;
      forceDraw = false;
    }
  }

  //Wait for the user to release the button and debounce
  while (!digitalRead(TIMER_BUT_PIN));
  delay(100);

  return value;
}

/* Draws the default clock face screen */
void drawHome() {
  screen.clear();

  screen.setCursor(7, 1);
  DateTime now = DS3231M.now();

  int hr12 = (now.hour() % 12);
  hr12 = (hr12 == 0) ? 12 : hr12;

  sprintf(inputBuffer, "%d:%02d%c", hr12, now.minute(), now.hour() >= 12 ? 'p' : 'a');
  screen.print(inputBuffer);
  screen.setCursor(1, 2);

  //Serial.println(weekDays[0]);

  screen.print(weekDays[DS3231M.weekdayRead() % 7]);
  sprintf(inputBuffer, " %d/%d/%02d", now.month(), now.day(), now.year() % 100);
  screen.print(inputBuffer);
}

/* Draws the timer screen for when an exercise interval is in progress */
void drawTimer() {
  screen.clear();
  screen.setCursor(4, 1);
  screen.print("Elapsed Time");
  
  screen.setCursor(6, 2);

  long unixtime = (DS3231M.now()).unixtime();
  long elapsed = unixtime - start;

  int seconds = elapsed % 60;
  elapsed -= seconds;
  int minutes = (elapsed / 60) % 60;
  elapsed = (elapsed / 60) - minutes;
  int hours = elapsed / 60;

  sprintf(inputBuffer, " %d:%02d:%02d", hours, minutes, seconds);
  screen.print(inputBuffer);

}

/* Draws the the 14 day bargraph screen (for during idle mode) */
void drawTwoWeekGraph(int values[]) {
  int weekDay = DS3231M.weekdayRead();

  screen.clear();
  initGraphChars();
  for (int i = 0; i < 14; i++) {
    drawGraphBar(values[14 + i] / 225, 1, i + 3, 2);
  }

  screen.setCursor(3, 3);
  for (int i = 1; i < 15; i++) {
    screen.write(weekLetters[(i + weekDay) % 7]);
  }
}

/* Draws two horizantal graph bars, representing the total exercise time across the past two weeks */
void drawWeekCompare(int w1, int w2) {
  screen.clear();
  initBarChars();

  //See how much we've improved since last week
  int percentChange = ((w2 - w1) * 100) / w1;

  screen.setCursor(0, 0);
  screen.print("Last week");
  drawHBar(w1 / 300, 1);

  screen.setCursor(0, 2);
  screen.print("This week (");

  //Add a plus if we've gone up (negative added automatically)
  if (percentChange >= 0) {
    screen.print("+");
  }

  screen.print(percentChange);
  screen.print("%)");

  drawHBar(w2 / 300, 3);
}

//Writes each of the horizantal progress bar chars into the LCD
void initBarChars() {
  screen.clear();
  //Start with an empty glyph for the bargraph char
  byte hBar[] = {0, 0, 0, 0, 0, 0, 0, 0};

  //Loop through each bargraph level
  for (int i = 0; i < 5; i++) {
    //Loop through each row of the character
    for (int row = 0; row < 8; row++) {
      //Add in a vertical bar (via bitwise OR)
      hBar[row] = hBar[i] | (0B10000 >> i);
    }

    screen.createChar(i, hBar);
  }
}


/* Draws a horizantal graphbar x pixels wide on the given LCD row */
void drawHBar(int x, int row) {
  screen.setCursor(0, row);

  int offset = 0;
  while (x - offset > 0) {
    int blockChar = x - offset;
    blockChar = constrain(blockChar, 0, 5);

    screen.write((blockChar == 0) ? 32 : blockChar - 1);

    offset += 5;
  }
}

//Writes each of the bargraph level chars into the LCD
void initGraphChars() {
  //Start with an empty glyph for the bargraph char
  byte bar[] = {0, 0, 0, 0, 0, 0, 0, 0};

  //Loop through each bargraph level
  for (int i = 0; i < 8; i++) {
    //Set the lowest line to be all ones
    bar[7 - i] = 0B11111;
    screen.createChar(i, bar);
  }
}

/* Draws a vertical bar 'level' pixels high capped at a given height in char blocks
   at the given position (measured from the top of the bar space) */
void drawGraphBar(int level, int row, int col, int height) {

  for (int y = 0; y < height; y++) {
    int offset = y * 8;
    screen.setCursor(col, row + (height - 1) - y);

    int blockHeight = level - offset;

    //Limit the block height to 0-8
    blockHeight = constrain(blockHeight, 0, 8);

    screen.write((blockHeight == 0) ? 32 : blockHeight - 1);
  }
}

/* Take the sum of exercise time across an interval in our records */
int getTotalTime(int start, int finish) {
  int out = 0;

  for (int i = start; i < finish; i++) {
    out += pastTimes[i];
  }

  return out;
}

/* Starts and stops the exercise timer */
void timer()
{
  long unixTime = DS3231M.now().unixtime();

  if (!timerOn) {
    start = unixTime;
    playSound(happySound);
  }
  else {
    timeSeconds = unixTime - start;

    pastTimes[27] += timeSeconds;
    
    //Set the screen up to show the bargraph
    screenState = 2;
    updateTime = millis() - 3000;
  }

  timerOn = !timerOn;
}

/* Moves all recorded times over one day in memory (so day 27 is always the most recent) */
void shiftTimes()
{
  for (int j = 0; j < 27; j++)
  {
    pastTimes[j] = pastTimes[j + 1];
  }

  pastTimes[27] = 0;
}

/* Updates that need to be performed once each day */
void newDaySetup()
{
  shiftTimes();
  timeSeconds = 0;
}

/* Decide if a day has passed and we need to update things */
boolean isNewDay()
{
  DateTime now = DS3231M.now();
  if (now.hour() == 0 && now.minute() == 0 and now.second() == 0)
  {

    return true;

  }
  else
  {
    isMidnight = false;
  }
  return false;
}

/* Plays the given sound effect */
void playSound(int noteArray[])
{
  int noteLength = noteArray[0];
  for (int thisNote = 0; thisNote < noteLength; thisNote++) {
    int noteDuration = noteArray[1 + thisNote];
    int notePitch = noteArray[2 * noteLength - noteLength + 1 + thisNote];

    int noteTime = 300 / noteDuration;
    tone(SPEAKER_PIN, notePitch, noteTime);

    int pauseBetweenNotes = noteTime * 1.30;

    delay(pauseBetweenNotes);
    noTone(SPEAKER_PIN);
  }
}

/* Update the LEDs to reflect which days we have and haven't logged times */
void updateLEDs() {
  for(int i = 0; i < LED_CNT; i++) {
    digitalWrite(LED_BASE_PIN, pastTimes[27 - i] > GOAL_TIME);
  }
}

 

/*************************************************
 * pitches.h
 * Public Constants
 *************************************************/

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

 

]]>
Jeffrey’s Light: Final Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/jeffreys-light-final-documentation/ Tue, 10 Dec 2019 22:52:51 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8897 With the goal of creating a useful implement for an older person in mind, we looked into the life of our team member Jeff. As a blinds installation professional, Jeff often has to demonstrate to his clients how his products affect the quality of light passing through them. We designed a portable and adjustable light source to help him simulate different lighting conditions in relation to his window blind samples.

Our initial meeting documentation can be found here.

Our prototype documentation can be found here.

What we built

Our final product is a portable light source that replicates a range of weather and lighting conditions through a control panel on its top surface. Two knobs control color temperature and intensity, while three buttons provide sunny, cloudy, and sunrise/sunset lighting presets. These presets can also be customized by holding the button down for more than two seconds, adjusting the values, and pressing any button to save. Additionally, the light source comes with a carrier box that doubles as a stand. It can be used to transport the light source and adapter, and flipped over to act as a stand for the light source to be placed atop.

Overall Photo:

An overall image of the final product.

Basic Operation:

Demonstrating the knob and button interaction.

Details / Highlights:

Light source and adapter in carrier.

Light source (off) on stand.

Light source (on) on stand.

Close-up of diffused LED panel.

Knobs and their corresponding icons (left: color temperature, right: intensity).

Buttons and their corresponding icons (left: sunny, middle: cloudy, right: sunrise/sunset).

Usage:

Turning the knobs.

Pressing the buttons.

Reading the LCD display.

Editing the cloudy preset values.

Narrative:

Jeff has a sales pitch today at a client’s house. He places the lighting simulator and its adaptor into its carrier and packs it into his car. He commutes to his client’s house and brings the carrier inside along with his other equipment. As he is going through the window blind choices with his client, his client gets confused about some of the options. To give his client a better visual, Jeff unpacks the light and places it on top of its carrier. He plugs in the adaptor and the device turns on. He pressed the sunny button and holds the opaque blind sample in front to show that no light passes through. He then hold up the semi-opaque blind sample to show the difference in light quality. After Jeff fiddles with the light settings to give his client a realistic image of how light would pass through each of the blinds, Jeff’s client is able to make a confident decision on which blinds to purchase.

How We Got Here

In our initial planning, we split the tasks into three main stages: programming/hardware, fabrication, and assembly. Our proposed project timeline can be seen below:

Proposed project timeline.

Based on the feedback we received on our prototype, we began by researching options for a brighter LED module in order to create a light source closer to natural sunlight.

After some research, we identified several important criteria we wanted our light source to achieve.

Since we intended to simulate lighting conditions through a window, the light source would have to achieve color qualities within a large portion of those ranges, which can extend from 1000 K to 10000K, which is basically a range from a deep red sunset to a deep blue sky. We determined that such a lighting simulator would be well-balanced if it encompassed the middle range, 3000K to 6000K, which would give options from orange-ish for dawn and dusk times to a white that’s tinted slightly blue for a general daylight color.

Secondly, we aimed for a product that could reproduce the intensities of sunlight and artificial lights to some degree. Sunlight intensity at Earth’s surface has a value of about 100,000 lux, and while a window is not likely to reach such intensities often, these can be important factors in replicating the performance of the blinds had they been demoed in those lighting conditions. Also, the high intensity also offers a way to simulate bright artificial lights, such as security lights, as well. Jeff mentioned that blinds may be installed with blocking such lights in mind, so a light capable of bright white light like that of bright sunlight could also approximate an artificial light to some extent.

A third factor that we thought was worth considering was the light source’s ability to simulate the quality of sunlight, specifically its full spectrum of light. A measure of a light’s quality, or closeness to the full spectrum, is its CRI value, so if we wanted a light that simulated lighting conditions, then it would make sense to have a light to approximate the natural light source as much as possible.

Thus, we settled on a light with the following specifications:

Color Range: 2700K – 6500K

Intensity: Max intensity is 3500 lumens at a color temperature of 4100K (close to white). A quick calculation gives around 110,000 to 120,000 lux. This is of course at its peak intensity, which occurs at a color temperature of 4100 K, but this intensity is mostly just necessary for direct sunlight, which is a close temperature of around 5000K, so the light should still be able to get close to the necessary intensity.

CRI value: rated to at least 95 CRI on a scale of 100.

Overall, the LED strip we got generally satisfied all our criteria. The only catch was that they were rather expensive. A link to the store page is provided below.

BC Series High CRI LED Multirow Hybrid Color Temperature LED Flexible Strip – Pack: 1 pcs

Fabrication Details

In terms of fabrication, the first step was to make adjustments to the design of the outer casing. Jeff had requested that the form be elongated horizontally to cover more area. In addition, he asked for a stand to elevate the light in order to create extra space at the bottom for when he stretches the blind sample. The outer casing and stand were designed in tandem to fit together. With the element of the light, adaptor, and stand in mind, we decided to make the stand double as a carrying case that can transport the other two items. We thought this could be particularly useful for Jeff since he commutes to his clients’ homes by car.

Redesigning aspects through sketching. Jeff had also mentioned that the light should be stable atop the stand, so we decided to add bumpers to the bottom face of the light that perfectly fit into cutouts on the top face of the stand.

After the designs were finalized, we constructed the CAD model for the outer casing in Fusion360 and sent it for 3D printing through the Stratasys printer.

Screenshot of the outer casing CAD model in Fusion 360.

We based the dimensions of the stand on the size of both the light and its adaptor. We input these dimensions into makeabox.io which gave us the dxf file to laser cut the stand. Slots on either side were added in Adobe Illustrator for when Jeff chooses to use the stand as a carrying case. We also added the circle cutouts that would fit the bumpers. Beyond this, fabricating the stand was a fast process.

The finished stand / carrier. The laser cut pieces were then joined together using bondene.

As for the outer casing, the 3D print was placed in the parts wash and finished using bondo and spray paint. Bondo was applied and sanded down to create a smooth surface for spray painting. We chose to use matte grey spray paint because Jeff wanted a sleeker look.

The finished stand / carrier and outer casing. Icons can be seen beneath the hole for each knob / button.

We also laser cut and engraved small icons that indicate the function of each knob / button. From left to right, the icons represent the color temperature knob, the brightness / intensity knob, the sunny preset button, cloudy preset button, and sunrise / sunset preset button. The holes for the icons were designed into the CAD file.

Finally, we added the bumpers on the bottom face of the outer casing.

Bottom face of outer casing with bumpers attached.

Technical details

While the structure of the prototype code was largely retained by the final code, several revisions had to be made account for several factors.

The initial big change was switching from using a LED library to manage the LEDs to a more ‘manual’ direct control of the LED intensities via PWM on transistors that controlled the actual current flow to the LED panels, although this is greatly simplified by the analogWrite() function.

This also meant that the color temperature of the board would have to be guided through a completely different method. The research on the LEDs here offered some helpful information on how the colors blended between the two LED circuits on the board, one for warm LEDs and one for cold LEDs, to produce the color temperatures we desired. One of the graphs on the sight indicated a close to linear relationship between intensity and color for both LED circuits given the other one was fully on, so I reasoned that the intensity of either circuit would cause an additive change in the temperature given the other was fully on. Without a way to test, we couldn’t be entirely sure, but the visual results suggested that the observed LED color temperatures were fairly close to the color temperatures we mapped them to.

Another change that was included fairly late in the game was the inclusion of a save system for the button presets, which resulted in some less than optimal code since it hadn’t been initially planned for.

On the electronics side of things, there were several notable changes to account for the high voltage LED panels and their 2 circuit design. We switched to using transistors and power regulators in the design to account for the 24V supply we switched to per the voltage requirements of the LEDs while allowing us to power the 5V Arduino Pro Mini. As pushing current through a resistor wastes a lot of the power that the LED will use and creates heating problems, a transistor allowed us to control the LED intensity as well in conjunction with PWM.

Before fully committing to the new design, we tested a few subsystems like transistors and power regulators on a solderless breadboard with the LED panel before upgrading to a soldered one for a more permanent design. This soldering requirement forced us to switch to the Arduino Pro Mini as we had been using the Arduino Uno for the prototype and testing many of the subsystems.

Soldering ended up taking a fair deal of time, but once it was done, all that was left was to install the wired up parts into the frame. We did not solder the power supply barrel jack immediately to the board however as we needed to mount it first, so we soldered the rest of the board before mounting the barrel jack, then soldered the barrel jack’s wires to the board.

Testing the code and electrical components on a mini LED panel before our actual module arrived in the mail.

Integrating the LED module.

The new LED module is much brighter; closer to natural sunlight than the LED strip used in our prototype.

Wiring up the pro mini.

Moving from breadboard to protoboard.

Making progress in soldering the electrical components

Once all the connections were soldered, we began assembling everything together.

All components ready to be assembled.

We started by securing the LCD screen by hot glueing it in place, then mounting the knobs and buttons. We then glued the protoboard to the back face of the casing to prevent shifting during transport.

LCD screen, knobs and buttons mounted. Protoboard in place.

Finally, we created a cardboard backing for the LED module and glued that into place. The last step was glueing the frosted acrylic panel in front.

The LED module glued in place on cardboard backing.

In the end, we weren’t able to quite follow our timeline due to the time taken to find and confirm the purchase of the LED panel as well as planning certain milestones for classes that were during Thanksgiving break, but we were able to catch up with some work done on the Sunday (lots of soldering) and Monday (final assembly) before the final critique.

Conclusions and Lessons Learned
Findings from the final critique

A common point of critique was the stand for the device, which some mentioned could easily look dirty or show signs of wear due to its very smooth acrylic material. One of the reviewers remarked that the stand could be made of “wood or another opaque surface” and that both the device stand and our acrylic ‘diffuser’ panel that goes in front of the LED panel could be made of “a material that can take more of a beating.” While the stand had admittedly been designed with the device in mind, it certainly didn’t receive close to the attention from us that the device received, and its the thin, smooth acrylic material turned out to be a poor choice.

One reviewer remarked that we should’ve taken a “closer study of Jeff’s pitch” while another posed the question of “how will Jeff carry this into [the] customer’s home”, probably concerning the handles on the stand not being ideal. Since we hadn’t seen Jeff do a sales pitch, we recognized that this was an unfortunate oversight in our development process, as a number of the other points of criticisms can be drawn from a lack of awareness of its day to day use.

Another point of contention was our choice of placement of the controls, which could affect the sales pitch. While the controls are on the top in our design for ease of accessibility according to Jeff’s desire to put it up against a window, a reviewer said “controls might be better on back”, which would hide them from the client. Both options certainly have advantages, although Jeff seemed pleased enough with the interface as it was.

The 2 adjustable variables of temperature and intensity give the user a lot of direct control and a simpler UI to deal with, but one reviewer did point out that “lighting could be more simulation-oriented”, which is perhaps more user friendly for those less inclined to the control scheme using somewhat technical variables and prefer something they can think of, like a cloudy morning in April (weather, time, season settings vs. color temperature, light intensity settings). If we had looked for and found simple mathematical models that combine all these inputs into something like color temperature and intensity, we recognize that this may have been feasible, although this would ultimately have been a design decision we’d have had to make with Jeff after agreeing initially upon a design fairly similar to our prototype.

Despite a number criticisms, many of the reviewers also had praise for the visual aspect of the design, especially that of the main device (a bit less enthusiasm for the stand). Adjectives like “sleek”, “beautiful”, “well-designed”, “professional”, “fit together”, and “product-like” were used to describe the visual design, and what’s more, Jeff wrote that “I will use this light box daily”. What more could we ask for?

Major takeaways

One of the biggest takeaways we got from working with an older person is that everyone is unique in ways that are often overlooked by stereotypes. We went into the initial meeting with generalizations about the hobbies that an older person might enjoy, or the way that they live their life. However, we were surprised to find that many of these assumptions did not line up. This seemed to be the case for many other groups as well. In our case, Jeff is very active and had no troubles with any physical aspects of his life. He is still highly engaged in his professional life and is very technologically adept. Him and his wife are very social and spend little time in their home. This went against many of our initial assumptions of what we were designing as we expected to create something more closely related to physical needs caused by aging as well as something that would remain at his home. Just as not all young people are addicted to social media and pop culture, older people are also unique in their habits and lifestyles, making it all the more important to research the individual’s particular wants and needs.

We also got a chance to learn from Jeff how our device could play a role in his business and even the entire industry. While there are large studio setups that could do a better job than our device, they’re hardly portable. Our device is both light and compact, making it easy to transport from car to home, but the pragmatic aspect didn’t seem all that novel to us considering similar photography lights did exist, even if they generally didn’t aim for such high light intensities. So we had figured it would be simply a minor addition to the sales pitch to reinforce what Jeff was already telling the customer. But according to Jeff, the device’s role in demonstrations is part of the “sizzle” in a sales pitch that can give a salesman an edge, and, as per Jeff’s own words, “sizzle sells”.

Concluding thoughts

There were several lessons that we took away from this experience.

A variety of technical issues came up throughout the course of developing this device that will serve as helpful experience for the future to prevent mistakes.

Soldering was a challenge at times, especially on the rare occasion that one of the many pins we had to solder in for the Arduino Pro Mini we were using wasn’t connected well by the solder, which made debugging a real challenge, as determining what was a code bug vs. an electrical issue can be hard to see. Bulk soldering can also lead to forgetting about adding heat shrink until both ends of a wire is soldered on, and the potential risk isn’t worth the quicker soldering, since wrapping electrical tape around small wires isn’t fast by any means.

An unfortunate change in the final product from the prototype was switching of the encoder pins from pins 2,4 for one encoder to pins 2,3 and pins 3,5 for the other encoder to pins 4,5. While it appeared to be a seemingly innocuous and more organized change,it turns out that pins 2 and 3 are special interrupt pins on the Arduino Uno (for the prototype) and the Arduino Pro Mini that are especially good for use with encoders. As a result, an encoder output is read best if it has two or at least 1 of these interrupt pins attached, but in this case, 1 encoder got both of the interrupt pins when it would’ve been better for both to get 1. Nevertheless, the ‘faulty’ encoder still works very well if it’s turned slowly enough, so the problem was largely overlooked, as it was an uncommon issue during testing when we hardly turned it very fast.

A few design choices could’ve also potentially enhanced our device.

We hadn’t designed the housing to have a ledges for the LED panel to rest on, which lead to the use of the cardboard backing and hot glue. Additionally, the housing also had no access from the back, so it was effectively impossible to access the internal electronics once it was sealed in by the acrylic panel.

Perhaps embedding the controls in the back could’ve given it an even sleeker look, although the top access is arguably more accessible, but it would’ve been worth considering.

We really should’ve inquired more into how Jeff might use the device on a sales pitch to better customize the stand/carrier. Then we probably would’ve ended up with a sturdier and hopefully easier to carry device.

Overall, creating this device, the result of our extensive efforts, was an engaging and wonderful opportunity for improving skills, gaining experience and  enhancing Jeff’s life.

Technical details:

Code:

/*
  Final Project: Jeffrey's Light

  Description: This code is intended to serve as an interface
  between User Input (consisting of 2 encoders, 3 buttons and an LCD display)
  and configurations for approximate color and relative intensities
  for a high power, bicolor LED panel.

  NOTE: The pins chosen for the encoders are not optimal,
  as one encoder has no interrupt pins (pins 2 and 3), which makes it less effective
  While 2 is optimal, the limited number of interrupt pins makes giving
  each encoder 1 interrupt pin a better balance, therefore pins 2,4 -> Encoder 1 and
  3,5 -> Encoder 2 or something similar would work best.

  Input:
  Pins|Connection (relevant properties)

  2   |Encoder 1 (interrupt pin)
  3   |Encoder 1 (interrupt pin)
  4   |Encoder 2
  5   |Encoder 2
  7   |Button 1
  8   |Button 2
  9   |Button 3

  Output:
  Pins|Connections
  10  |LED Circuit 1 (PWM)
  11  |(PWM) LED Circuit 2 (PWM)
  A4/A5|LCD Screen (SDA/SCL)


  Resources Used:

  LCD Screen code contains snippets and references to code written by Robert Zacharias at Carnegie Mellon University, rzach@cmu.edu
   released by the author to the public domain, November 2018

  Some Button-related code snippits adapted from my Project 2 code

  Adapted code from public domain examples in Encoder Library by Paul Stoffregen
  https://www.pjrc.com/teensy/td_libs_Encoder.html

  Data on bicolor LED panel used in device from product website
  BC Series High CRI LED Multirow Hybrid Color Temperature LED Flexible Strip - Pack: 1 pcs

  Some data on the LEDs, most importantly regarding the balance of LED temperatures
  
Complexities of Bicolor LED Lights: An Extensive Color Analysis
*/ #include <Encoder.h> #include <LiquidCrystal_I2C.h> #include <EEPROM.h> //PINS assignments Encoder IntenKnob(2, 3); Encoder ColorKnob(4, 5); const int B1_PIN = 7; const int B2_PIN = 8; const int B3_PIN = 9; const int WARM_LEDS = 10; const int COLD_LEDS = 11; //Uses SDA/SCL pins, not shown LiquidCrystal_I2C screen(0x27, 16, 2); //Presets and State Constants// //State constants based on states set by buttons (effectively an enumeration) const byte CUSTOM = 0; const byte DAYLIGHT = 1; const byte CLOUDY = 2; const byte SUNSET = 3; //Temperature constants of LEDs in Kelvin const int MAX_TEMP = 6500; //Highest color temperature rating by manufacturer const int MIN_TEMP = 2700; //Lowest color temperature rating by manufacturer const int MID_TEMP = 4100; //LEDs reach peak brightness at this color temperature //Max - Min = 3800 K //LED Presets int DAY_TEMP = 6000; float DAY_INTEN = 0.86; int CLOUDY_TEMP = 6500; float CLOUD_INTEN = 0.02; int SUNSET_TEMP = 3000; float SUNSET_INTEN = 0.2; //Commented out struct below is present in device code but is not used /* struct saveData { int DAY_TEMPs; float DAY_INTENs; int CLOUDY_TEMPs; float CLOUD_INTENs; int SUNSET_TEMPs; float SUNSET_INTENs; }; */ //Variables// //I/O Constants// //Presets chosen to define the range of encoder values //50 intervals for intensity ->0.02 per encoder 'tick' //38 intervals for temperature -> 100 K per encoder 'tick' const int EncIntenRange = 50; const int EncColorRange = 38; //Constants that serve as delimeters for milliseconds it takes to recognize either //a press (50ms) for setting light to config preset or a hold (2000ms) to edit that preset const int bPressTime = 50; const int bEditTime = 2000; //Used for storing previous Intensity and Color values between loop calls int lastInten, lastColor = -1; //Keeps track of how long any of the three buttons have been held int buttonTimes[3]; //These store the output values to the PWM pins (index 0 is warm LEDs; index 1 is cold LEDs) int PWMs[2]; //Time Variables// //Used to keep track of elapsed time between loop calls unsigned long lastMillis; //A constant delay value (should be a constant variable) at the end of loop calls as it should reduce LCD flickering. Possibly unnecessary. int delayTime = 10; //State Variables// //The state of the device in non-editing mode (not relevant while editing) byte state = CUSTOM; //The state of the device during editing (not relevant when non-editing) byte EditState = CUSTOM; //Initialized to not an editable state //Determines if the device is in an editing state or not. bool isEditing = false; //A flag to determine whether to redraw the LCD screen or not bool dirtyLCD = true; //Initialization Constants// //Initialization Temperature and color (a soft white glow to indicate activity without being blinding) const int InitTemp = 5000; const float InitInt = 0.02; void setup() { //Initialize button pins pinMode(B1_PIN, INPUT_PULLUP); pinMode(B2_PIN, INPUT_PULLUP); pinMode(B3_PIN, INPUT_PULLUP); //Initialize LED (PWM) pins pinMode(WARM_LEDS, OUTPUT); pinMode(COLD_LEDS, OUTPUT); lastMillis = millis(); //Loads the 3 presets from EEPROM loadPreset(); //Initialize the screen with relevant commands screen.init(); screen.backlight(); screen.clear(); screen.home(); //Initial color and intensity is set in the relevant 'encoder objects'. IntenKnob.write(rotFromInten(InitInt)); ColorKnob.write(rotFromTemp(InitTemp)); } void loop() { //Reads the encoder values int intenvalue = IntenKnob.read(); int colorvalue = ColorKnob.read(); //Prevents the encoders from leaving the allowed range if (intenvalue > 0) { IntenKnob.write(0); intenvalue = 0; } if (colorvalue > 0) { ColorKnob.write(0); colorvalue = 0; } if (intenvalue < -EncIntenRange) { IntenKnob.write(-EncIntenRange); intenvalue = -EncIntenRange; } if (colorvalue < -EncColorRange) { ColorKnob.write(-EncColorRange); colorvalue = -EncColorRange; } //Record Encoder input (negative due to clockwise motion decreasing the encoder values) int cin = -colorvalue; int inn = -intenvalue; //This variable is largely irrelevant unless in edit mode, in which case inputs that make it //true will lead to the leaving of edit mode. bool stopEdit = false; //Response to changes between current and previous encoder positions if (cin != lastColor || inn != lastInten) { dirtyLCD = true; if (!isEditing)state = CUSTOM; //Only while editing does state changing to custom matter } //Set state or editing based on button input if (!digitalRead(B1_PIN)) { buttonTimes[0] += millis() - lastMillis; if (buttonTimes[0] > bPressTime) { if (state != DAYLIGHT)dirtyLCD = true; state = DAYLIGHT; if (buttonTimes[0] < bEditTime)stopEdit = true; } } else buttonTimes[0] = 0; if (!digitalRead(B2_PIN)) { buttonTimes[1] += millis() - lastMillis; if (buttonTimes[1] > bPressTime) { if (state != CLOUDY)dirtyLCD = true; state = CLOUDY; if (buttonTimes[1] < bEditTime)stopEdit = true; } } else buttonTimes[1] = 0; if (!digitalRead(B3_PIN)) { buttonTimes[2] += millis() - lastMillis; if (buttonTimes[2] > bPressTime) { if (state != SUNSET)dirtyLCD = true; state = SUNSET; if (buttonTimes[2] < bEditTime)stopEdit = true; } } else buttonTimes[2] = 0; //LastMillis is only used above, so we can set it again afterwards lastMillis = millis(); //If any buttons been held for long enough, then device enters Edit Mode if (buttonTimes[0] > bEditTime || buttonTimes[1] > bEditTime || buttonTimes[2] > bEditTime) { if (!isEditing)dirtyLCD = true; stopEdit = false; isEditing = true; EditState = state; } //Initializes the string so it can be used later to print to the LCD String stateStr; if (!isEditing) { switch (state) { case CUSTOM: stateStr = "CUSTOM"; break; //Daylight presets are converted to Encoder presets case DAYLIGHT: cin = (DAY_TEMP - MIN_TEMP) / ((MAX_TEMP - MIN_TEMP) / EncColorRange); inn = (int)(EncIntenRange * DAY_INTEN); stateStr = "SUNNY"; break; //Cloudy presets are converted to Encoder presets case CLOUDY: cin = (CLOUDY_TEMP - MIN_TEMP) / ((MAX_TEMP - MIN_TEMP) / EncColorRange); inn = (int)(EncIntenRange * CLOUD_INTEN); stateStr = "CLOUDY"; break; //Sunset presets are converted to Encoder presets case SUNSET: cin = (SUNSET_TEMP - MIN_TEMP) / ((MAX_TEMP - MIN_TEMP) / EncColorRange); inn = (int)(EncIntenRange * SUNSET_INTEN); stateStr = "SUNRISE/SET"; break; } //If state has been set to non-custom, then overwrite current encoder settings if (state != CUSTOM) { IntenKnob.write(-inn); ColorKnob.write(-cin); } } else { //From above, this is the case where the device is in Editing mode switch (EditState) { case DAYLIGHT: stateStr = "EDIT:SUNNY"; break; case CLOUDY: stateStr = "EDIT:CLOUDY"; break; case SUNSET: stateStr = "EDIT:SUNSET"; break; } } //Convert ending Encoder values to temperature(equivalent to color) and intensity int temperature = MIN_TEMP + (int)((long)(MAX_TEMP - MIN_TEMP) * cin / EncColorRange); float intensity = (float)inn / EncIntenRange; //Writes to the LED panel control transistors using a function of temperature and intensity setPWM(temperature, intensity); //Only redraw the LCD if dirtyLCD flag is true if (dirtyLCD) { screen.setCursor(0, 0); screen.print(" "); screen.setCursor(0, 0); screen.print(stateStr); screen.setCursor(0, 1); screen.print((String)temperature + " K"); screen.setCursor(7, 1); screen.print(" "); //Easier to clear part of screen this way than clear the entirety. screen.setCursor(7, 1); screen.print((String)((int)(intensity * 100))); screen.print("%"); dirtyLCD = false; } //In this case, a button has been pressed during editing, so editing will cancel and the preset will be saved if (isEditing && stopEdit) { savePreset(EditState, temperature, intensity); dirtyLCD = true; //Redraw LCD when canceling out of edit } //Store current values for next loop lastInten = inn; lastColor = cin; //Analog write PWM pins with values set by SetPWM() method analogWrite(WARM_LEDS, PWMs[0]); analogWrite(COLD_LEDS, PWMs[1]); //May be unnecessary. Although it may make the LCD less flickery, it may also make changes to LED values more choppy delay(delayTime); } //conversion from temperature to encoder value int rotFromTemp(int temp) { return -((temp - MIN_TEMP) / 100); } //conversion from intensity to encoder value int rotFromInten(float inten) { return -inten / 0.02; } //sets PWM values when called based on input temperature and intensity void setPWM(int temp, float inten) { //Branching cases depending on whether the temperature is on the cold or the warm side if (temp - MID_TEMP <= 0) { //Warm temperature is at maximum for temperatures above the midTemp PWMs[0] = (int)(255 * inten); //The cold temperature varies depending on how far it ranges from MAX to midTemp PWMs[1] = (int)(inten * 255 * (temp - MIN_TEMP) / (MID_TEMP - MIN_TEMP)); } else { //Cold temperature is at maximum for temperatures above the midTemp PWMs[1] = (int)(255 * inten); //The warm temperature varies depending on how far it ranges from MAX to midTemp PWMs[0] = (int)(inten * 255 * (MAX_TEMP - temp) / (MAX_TEMP - MID_TEMP)); } } //reads the EEPROM for corresponding values for the button presets void loadPreset() { int checkLoad = 0; int i = 0; EEPROM.get(i, checkLoad); if (checkLoad >= MIN_TEMP) { EEPROM.get(i, DAY_TEMP); i += sizeof(int); EEPROM.get(i, DAY_INTEN); i += sizeof(float); } i = sizeof(int) + sizeof(float); EEPROM.get(i, checkLoad); if (checkLoad >= MIN_TEMP) { EEPROM.get(i, CLOUDY_TEMP); i += sizeof(int); EEPROM.get(i, CLOUD_INTEN); i += sizeof(float); } i = 2 * (sizeof(int) + sizeof(float)); EEPROM.get(i, checkLoad); if (checkLoad >= MIN_TEMP) { EEPROM.get(i, SUNSET_TEMP); i += sizeof(int); EEPROM.get(i, SUNSET_INTEN); i += sizeof(float); } } //Method to save the presets for the buttons to EEPROM void savePreset(int preset, int temp, float inten) { int i = 0; switch (preset) { case DAYLIGHT: DAY_TEMP = temp; DAY_INTEN = inten; break; case CLOUDY: CLOUDY_TEMP = temp; CLOUD_INTEN = inten; i = sizeof(float) + sizeof(int); break; case SUNSET: SUNSET_TEMP = temp; SUNSET_INTEN = inten; i = 2 * (sizeof(float) + sizeof(int)); break; } EEPROM.put(i, temp); EEPROM.put(i + sizeof(int), inten); isEditing = false; }

 

Schematic:

Note that this schematic is the one present in the device with the aforementioned encoder pin issue: pin 2,3 ->Encoder 1 and pin 4,5 ->Encoder 2, where 1 encoder gets both interrupt pins while the other gets none. This is also noted in the device code and concluding thoughts, so anyone aiming to reproduce at least the encoder part of the design should take note of it in both their electrical and software components.

Design Files:

design-files.zip

]]>
Team Jim – Prototype Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/team-jim-prototype-documentation/ Tue, 19 Nov 2019 14:18:09 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8782

Introduction

After our initial interview with Jim (which is documented here), we decided to have a follow-up interview to more specifically nail down an idea. After a substantial and creative conversation, we came up with a our idea.

A main feature of Jim’s living room is a large Boston grand piano which both Jim and his wife use extensively for pleasure and entertaining. One hassle, however, is that the piano requires a certain humidity to maintain its condition during the winter. In addition to their love of music, Jim and his wife also enjoy the sights and sounds of indoor fountains. After some discussion, these two themes seemed to complement each other nicely. 

Our Idea: Build them a controllable fountain that provides both the tranquil sounds of moving water and also actively monitors and maintains the correct humidity for their piano.

Below we outline the process of creating our initial prototype for Jim’s new fountain.

Prototype

Our prototype has two separate parts: a fountain part (in the middle) with the pump, LED strip, humidifier and a radio receiver, and a remote part (top right) with a humidity detector and a radio sender.

Our prototype has two separate parts: a fountain module (in the middle) with the pump, LED strip, humidifier and a radio receiver, and a remote module (top right) with a humidity detector and a radio transmitter.

Since our group had a relatively late start, we focused on finishing most of the technical components instead of the aesthetics. We decided to divide our project into two physically separate parts: the first one is the main fountain module with a pump, a humidifier, and LED indicator that shows the humidity level, and the second part is a remote module that detects humidity from a distance and sends radio signal back to the main module. Right now, the remote module will send signals back to the main controller every 5 or so seconds. If the primary module detects that the humidity is too low, it will simply turn on the humidifier until it detects that the humidity is no longer too low. The LED will accordingly respond as well. Currently rainbow colors indicate a correct humidity while red or blue indicate either too low or too high respectively. The pump’s power too can be adjusted using a small dial though it wines when it gets too weak as the our current model is not intended for varying speeds. 

In the end, we intend for Jim only to have to interact with the primary fountain module. With full battery, the remote module should continue transmitting normally for ~6 months to mitigate the hassle for Jim, at which point he will simply have to replace a couple of AA batteries. 

For the prototype, we have solved most of the technical challenges:

The actual fountain with the humidifier in shallow water, an LED strip and an adjustable pump

The “actual” fountain with the humidifier in shallow water, an LED strip and an adjustable pump. The humidifier disk has to be on the surface of shallow water to make the mist (this will be an important design consideration). The LED strip currently shows red because the humidity level is below the desired threshold.

A radio receiver in the main fountain part

The radio transmitter for the main fountain module. This will be responsible for communication with the remote humidity module located near the piano.

For the main fountain part, we have:

  • An adjustable pump
  • LED strip that displays the humidity
  • A humidifier that turns on when humidity is below a settable threshold
  • A radio receiver
The remote module that's separate from the main fountain part has a humidity detector (to the left) and a radio sender (to the right).

The remote module separate from the main fountain has a humidity detector (to the left) and a radio transmitter (to the right). These will be incorporated into a more compact package which will include a battery pack.

For the remote part, we have:

  • Humidity detector
  • A radio transmitter
Humidity detector for the remote module

Combined humidity and temperature sensor for the remote module.

Radio receiver in the main fountain part (to the left) and radio sender in the remote module (to the right)

Radio receiver in the main fountain part (to the left) and radio transmitter in the remote module (to the right).

Breadboard that has a button to manually turn on the humidifier and a potentiometer that adjust the pump level

Breadboard that has a button to manually turn on the humidifier and a potentiometer that adjust the pump power.

A potentiometer that adjusts the pump level

A potentiometer on a breadboard that adjusts the pump level

Process

The process of putting it all together:

Here the separate radio modules are wire up together for the first time. At this point, either radio can act as a transmitter or receiver of data.

Here we are completing our first tests with the jerry-rigged humidifier module. We’ve attached our own wires to the pins we needed to the turn the attach pcb circuit on and off with our own button.

The updated design for the box that will hold our remote humidity sensor, transmitter, and battery is being 3D printed here. We had to increase the volume of our design in order to hold the necessary number of batteries.

Different parts of the project start to be integrate. At this point we have a humidifier attached to the primary radio module while the humidity sensor and transmitter module are still sending data (picture at right).

All of the major components of our main module are combined. Now the pump is connected along with a potentiometer to control its speed. We tested both the humidifier and pump using a simple bucket of water.

With the main module complete with an LED indicator strip, we demonstrate the basic functionality. At this point the humidifier is automatically responding to the readings from the remote humidity sensor module. Any time it senses humidity below 40%, it begin to atomize the water.

Adjustable LED strip: the LEDs turn red when the humidity level is below the threshold (40-), turn rainbow if it’s right above the threshold (40-50), and turn blue if it’s too much above the threshold (60+).

Discussion

We had a really great discussion with Jim during our hour-long conversation last Tuesday. Though we were initially a little unsure about whether we would be able to fill such a long stretch with continued conversation. To our pleasant surprise we learned a lot from Jim who seemed pleased with our progress so far, but was also very adamant and prepared to offer his own opinions on many different aspects of our product from design to hardware to the way we were implementing state-machine-like behavior in our code. One aspect that he had some great suggestions on was the remote humidifier module that we are developing. We learned that he would like to last for at least 6 months using battery power with a low-profile and a method for indicating low-battery power. All of these seemed feasible to us and were not something we had initially considered implementing. In addition, probably spawned from his love and background in physics, Jim also mentioned that he it would be great if the fountain could include a visual display showing things like humidity and estimated humidifier completion time (calculated using the diffusion equation, he added).

On the UX side, we tried to probe Jim on some of his preferences in terms of visuals or sounds. An interesting snippet from him was his mention of falling water and how much he loved the water pooled then trickled then splashed as it made its way through the property. To us, this Pittsburgh icon seemed like a great source of inspiration for us as we considered the aesthetic and design of our indoor fountain—especially since Jim has mentioned to us his love of architecture before! For the texture, we agreed that both smooth and rough landscapes had their charms, but agreed that for a fountain of this type, a rougher landscape could be more enjoyable and allow for a more dynamic flow of water into the basin. Small pebbles and shrubbery were also other elements that Jim had added to other fountains around his house and had enjoyed.

One idea of which we were a little skeptical was Jim’s suggestion that we use a pre-existing green ceramic basin that he had at his home. It seemed to us that it would limit the possibilities of the fountain’s footprint, we well as the kinds of I/O elements we might have wanted to integrate to the base (such as indicator LEDs and a small screen)—not to mention the fact that it didn’t seem big enough to fit a basin, pump, and electronics. Later on, however, Jim joined us in this sentiment with an email he sent us later on expressing that his basin was probably not ideal and he had enjoyed some of the sketches we had made up in class.

Moving Forward

Looking ahead, work will be divided into three primary areas: Fountain Design and Manufacturing, Electrical Miniaturization, and Final Assembly. In general, we are almost completely finished with most of the technical implementation of our fountain and its features. This just leaves miniaturizing all of our components to be neat and easily installable in our final fountain. The most difficult challenge facing our group from here on out will almost certainly be the design and manufacturing of the actual fountain. There will have to be a significant amount of time spent on the CAD of the fountain’s topology and figuring precisely out we will go about vacuum forming its bowl and other features. Some of the biggest features we will need will be an easily refillable reservoir, small pools in which to place the humidifiers, and a small OLED/LCD screen to display important measurements and metrics. Finally, with all of this (hopefully) finished, we will have to proceed with assembling all of our components. By now, everything should have been individually tested and then wired together and tested that way so that all the entire system requires is placing and securing components in our final package. At this point, our wireless transmitter is nearing this point, but we have been unable to reach a similar point until other components we have ordered have arrived. To ensure steady progress, we plan on having at least one of us working in Hunt every evening, especially for those nights when we have to finish especially time consuming tasks like CAD.

More specifically, we hope to keep ourselves to this timeline:

  • Wednesday, Nov. 20th – Finalize fountain design CAD, and Electronics container
  • Friday, Nov. 22 – Finish all electronic and integrate new parts
  • Saturday, Nov. 23 to Nov. 24 – Begin and Finish fountain manufacturing (vacuum forming the bowl and all other 3D printing)
  • Monday, Nov. 25 – Begin assembly and integration of all parts
  •  Sunday, Dec. 1 – Dec. 2 – Continue and Finish final integration
  • Tuesday, Dec. 3 – Final Crit
]]>
Team Enid – Prototype Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/team-enid-prototype-documentation/ Tue, 19 Nov 2019 08:04:32 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8806 Prototype

What if we all possessed enhancive devices that would turn any boring, house chore into a playful activity between us and our family? Then, wouldn’t chores become a more joyful and engaging activity of our daily routine? Imagine for example washing the dishes and at the same time interacting with your body to answer questions concerning your favorite topics like films, books, sports, cooking, etc. That kind of adrenaline rush could render dish cleaning playful, transforming forks, spoons, knifes into checkers of an interactive game.

Our prototype reconstructs a trivia game into a cards-free interaction game. Choosing the right answer becomes a bodily experience in the kitchen,  turning cutlery and utensil into participatory game pieces. Each answer of the multiple choices corresponds to: a) a different color and b) distance range, so that players choose their answer locating their hand or checker at a particular distance of the sensory box.

Game board and ultrasonic sensor

Inside of the box – organization of components

Process

Overview of the kitchen

Integrating the device in the kitchen 1

Integrating the device in the kitchen 2

I2C SD card reader – SD card loaded with Trivia questions

Close-up of the ultrasonic sensor – this is what will determine the answer picked

Planning out the different parts required a lot of testing!

Corresponding the answers to distance range

2 LCDs 20×4,  LCD1: scrolling questions, LCD2: Multiple choices

Enid choosing answers

Enid chooses the correct answer

Schematic diagram of the prototype

Discussion

Though it was difficult to converge onto an idea to execute, once we decided on the project, it was clear that an interactive trivia game was the perfect task for our team and Enid. However, it was very unclear what technologies we wanted to use to accomplish this. During our brainstorming phase, we looked into potentially using a wireless-enabled device to present questions via an online text-to-speech service. This proved to be too ambitious for numerous reasons: A.) We would need to order additional parts, delaying our design process and B.) We learned that Enid wanted to avoid having another online device that competes for bandwidth. In the meantime, we decided to load trivia questions onto an SD card, and display the texts on LCD screens.

We had some difficulty working with the SD card and LCD screens in tandem, but some refactoring of the code into helper functions allowed us to re-implement the way we displayed answers. Though we still do not know what the original problem was, this reorganization helped us move forward. The next challenge is an ongoing one. Because of the limitations of the LCD screen, we needed a way to display questions that are longer than the number of spaces on the screen. Tentatively, we decided on scrolling through the text on the top line of a screen, but Enid raised the concern that it is too difficult to keep an eye on the screen constantly while doing the dishes. This will be discussed further soon.

We are also using the built-in Arduino random library to shuffle questions and answers. The library uses a (presumably) random voltage reading of a disconnected pin as the “seed” of the generator. However, it seems that the seed is not entirely random, and on each round after the device restarts, there are only a few possible starting values. This means that we are only able to access a small subset of the questions.

The critique we had with the class and Enid was very useful to our group. The prototype we showed was meant to be placed on the countertop, with the understanding that as one is cleaning up, they can merely put an object in the right location a convenient distance away from their workspace.  Enid mentioned that we should consider resizing it. The project as it stood right now would not be practical to put on the countertop, as it would take up way too much space. In fact, she would prefer if we didn’t have it on the countertop at all, what if it were on her window instead? In this orientation, it would be in her line of sight as well, and would be easier to view questions and answers. In order to do this, we plan to have the range to pick answers lining the box the electronics are housed in, rather than coming out of it as shown in our current prototype. This is a slight modification that would greatly shorten the total space used and be more effective for Enid to use. In addition, she preferred this not to be a permanent installation. If there was a way we could easily remove our project, this would be ideal.

She also mentioned that she has trouble reading the single-line scrolling question. She brought up good points like what if she missed a part of the question? Or forgot what it was while answering? She would like to see at least the way we present the question be reformatted, say maybe filling up the screen, or repeating in case she forgets.

Overall, Enid really liked the approach we took with this project. She was super excited to play the game and answer the questions, and told us that she would definitely play this with her husband during clean-up sessions. Later, we went back to her house to take some final measurements of the kitchen and showed her husband the prototype as well, and he also seemed excited about the idea. It was a very positive critique session, and we were still able to get a clear picture of what had to be done in the coming weeks to complete the project.

Moving Forward

Our main things to focus on are the things Enid mentioned in the crit. The first focus would be to refactor the fabrication and presentation of the project with minimal changes to the software. This would include creating a smaller box of similar proportions to the one in the process pictures. It would also require shortening the ranges of the answers to match the length of the new box, but the wiring would remain largely the same. We would also have to find a way to better present the question and eliminate/improve on the scrolling text. We also plan on adding more questions of more variety based on preferences Enid had told us, and improve our current method randomization. We could also add things such as keeping a scoring system or a way to pick the categories, but these will only come after we fix those primary issues.

General Timeline for Final Project:

  • Nov 17th: Meet with Enid to get more feedback/take measurements
  • Nov 19th: Fix scrolling and randomization issues, start planning out new fabrication design
  • Nov 17th – 22nd: Create new fabrication
  • Nov 23rd – Dec 3rd: Add last-minute tweaks and improvements, change fabrication if necessary

 

]]>
Team Jan – Prototype Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/team-jan-prototype-documentation/ Tue, 19 Nov 2019 06:40:54 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8797 Introduction

The goal of this project is to create a an assistive device for an older person, in our case, this person was Jan. In our last post, we visited Jan in her home to discuss what day-to-day problems she experienced, and propose potential projects to  aide her. By the end of our visit, we had settled on a device which would help her remember to exercise, and keep track of how active she was being.

Since that post, we’ve been able to construct a prototype of our device, which implements many of the core features we had planned in our first post. On Thursday, November 14th, we met up with Jan again to show her the device, and collect her feedback on how the device had evolved.

Prototype

Our initial prototype for the workout clock.

The clock is able to display a simple bargraph of the past two week’s worth of exercise times.

We selected a large, easily pressable button to activate and stop the timer. Here, the clock is counting how long the timer has been running.

To solve the goal of reminding Jan to stay active, our group constructed a countertop clock, which keeps track of her exercise habits. When Jan leaves her house through the back door to exercise, she presses the large button to start a timer. Upon her return, she presses the button again to stop the timer, and log the time she spent exercising, which the clock can display as a graph on its screen. The clock also features a motion sensor, which is used to occasionally remind Jan if she hasn’t exercised for the day and is in the room.

Process

Sketches of ideas for how the final product might look, and how the information could be displayed. We weren’t looking to settle on a design, but wanted to get a good idea of what components to include in the prototype.

The LCD screen with the displays being tested. Early on the LCD screen and the clock were worked on separately, and were later merged together.

The prototype in the middle of development. The green LED was there to test the motion sensor, and was replaced by the speaker in the final prototype.

A test to make sure that the time spent exercising is being tracked when the button is pressed and that the graph is displaying the information correctly.

The display showing the time and date, although it isn’t the right time or date.

A timer that will be displayed while Jan is exercising, so she can see how long she has exercised for.

A graph that will display how long Jan exercised each day for the past two weeks. It currently displays the time between button presses with each pixel being one second.

George testing the motion sensor by walking in front of it. The idea is that if the motion sensor senses Jan walk into the room, it will make a noise to remind her to exercise.

Prototype of the lights we want to use to display the exercise history for the past week. They weren’t a part of the prototype since they are still being worked on, and the final version will most likely use seven LEDs that can be red or green instead of 7 red and 7 green LEDs.

Discussion

Our project features many technological features that worked relatively independently, so we were able to each work on a different problem for much of the prototyping process.  While efficient, this parallel method of working created challenges when combining the parts.  Because different aspects of the code were designed by different group members, many connecting details like variable names had to be corrected.  Furthermore, time was needed for each individual to learn how the others hardware and code functioned.

Another challenge in prototyping came from the physical limitations of the Arduino.  We planned to use 7 lights which can be either red or green to visibly represent Jan’s recent workout history.  However, using conventional wiring practices, this would require 14 Arduino pins, which there is not enough pins for.  To solve this problem we decided to use transistors to reduce the number of pins to 7.  This method is possible because each light can be either red or green at a certain time.  Eventually this method was effective, but it took a large amount of time to learn an effective wiring and was not able to be incorporated into the prototype by the critique.  Thankfully, this was more of an additional feature than a core functionality.

The critique on November 12th gave us insight into how to better personalize our final project for Jan’s own use.  We found the personal conversation with Jan to be the most useful part of the critique and were surprised how easy it was to fill an hour with meaningful conversation about our assistive device.  We were originally unsure about the timing of our reminder system, but Jan mentioned that a beep every 3-4 hours between 9am and 9pm would be sufficient.  She also raised several concerns such as her neighbors coming to feed her cat when she is away and her wanting to be able to change the reminder time if necessary.  Therefore, we think it would be useful to include an option to turn off and change the reminder system.  Furthermore, we discussed ideal room placement and size for our final project, and Jan sent us measurements when she returned home.

While there were many useful suggestions from the critique, not all criticism could be acted on.   Jan pointed out that her cat could set off the infrared sensor and asked if there was any way to prevent this.  However, our current PIR sensor returns a single binary value, and  a correctly interpret an analog signal from a different sensor would require extensive and invasive testing.  Therefore, we believe it is best to ignore this specific problem.  Also, in the full class critique someone pointed out a small break in our LCD display’s bar graph.  This problem is caused by the physical limitations of the display (not having any pixels in the area of the break), and would require a different display to be used.  We have chose to ignore this criticism, because we believe time spent incorporating a  different display could be better used elsewhere.

Moving Forward

Having gotten some useful feedback from Jan, we’re ready to proceed with this project to completion. One major addition that we plan to make to this project is the construction of an aesthetically pleasing enclosure for our electronics. Additionally, we intend to add the following features over the next few weeks:

  • (11/19/19) – Add the LED bargraph to the main circuitry
  • (11/19/19) – Implement a “power off / mute” switch
  • (11/21/19) – Implement a dial interface for setting the time
  • (11/21/19) – Begin construction of the plastic enclosure
  • (11/26/19) – Final assembly of project
  • (12/3/19) – Final project crit
  • (12/5/19) – Last minute bug squashing and tweaks
]]>
Team Jeff – Prototype Documentation https://courses.ideate.cmu.edu/60-223/f2019/work/team-jeff-prototype-documentation/ Mon, 18 Nov 2019 06:22:36 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8751 After our initial and follow-up conversations with Jeff, we decided to create an implement that would help him with his blind installation business. This post documents the process of building a prototype that demonstrates our idea.

Our initial meeting documentation can be found here.

Prototype:

Overall photo of the device in its off state.

Frontal view of the device at cool color temperature and low intensity.

Detail view of the top surface of the prototype, including the LCD display, knobs, and buttons.

Demonstrating the features of the prototype.

The device is intended to be a light source that is capable of simulating natural light based on different parameters of weather and time of day. It has two knobs that correspond to color temperature and intensity, as well three buttons that correspond to a sunny, cloudy, and sunrise/sunset preset condition. It was designed as a portable device that Jeff could bring to the homes of his clients and hold up behind different samples of blinds in order to demonstrate their unique qualities (e.g. blackout, semi-opaque, sheer).

Process:

This sketch shows the notes on the initial parameters we intended on incorporating in the prototype. The design of the prototype was also fleshed out through drawing.

We focused on getting the color temperature and intensity features working as a first step. This was done with the Arduino Uno, an LED strip, and two potentiometers.

Early on, we were considering a battery powered design for the device to be more portable. However, we decided to make a plug-in prototype in order to concentrate our efforts elsewhere.

In terms of design and fabrication, the CAD work was done in Fusion 360 and 3D printed. A progression of the design can be seen as follows.

We included holes to wall mount the encoders, buttons, and LCD screen. We also chose to add an indent on either side to provide an easier grip.

At this point, we began adding material appearances in order to visualize what the 3D printed outcome would look like.

We also tried to render the form with a emissive appearance that was intended to represent the panel of LEDs. However, it did not come out very well.

In unifying the electronic and fabricated components, we began by laser cutting a sheet of acrylic that fit inside the box, and bending the LED strip so that it covered the sheet. The LED strip had an adhesive backing so it was easy to apply. Later on, we had to remove the strip and remount it to a smaller sheet of acrylic, since this one did not fit.

This is a photo of all the components we had working at this point. After programming the encoders (which were previously potentiometers), we added the LCD display.

A close-up of the LCD display showing color temperature and intensity values.

A photo of Larry writing the code for the button presets.

A gif that shows a piece of support going flying after being chiseled off.

Discussion:

Various challenges faced the development of this prototype, from the initial design to its exterior appearance. We had struggled for days to find a suitable design that could be of use to Jeff, but we eventually came up with the idea of this light that could potentially aid in his professional business and be within the scope of our project. From there, the basic design for a prototype came fairly naturally, such as the features of tunable controls and a few convenient presets. But we faced a certain problem when trying to transition between controls and presets. The potentiometers we initially used had limitations on the extent they could rotate, making it hard for a seamless transition from a preset setting to whatever we tuned it to, as we had to jump to whatever the potentiometer position was when we tuned the color away from a preset value to ensure that the knobs wouldn’t be at a, let’s say ‘high’ value while displaying a lower value, as turning the knob higher wouldn’t allow it to go much further, despite having more range available that the LEDs could display. Encoders resolved this issue since they had no limitations on how far they rotated. We also encountered some issues with removing the support material on the casing, since the device needed to do so was out of commission. Thus, we chipped away at it by hand. The end result might’ve suffered slightly in appearance, but fortunately, it performed as desired.

After our formative critique with Jeff, we were able to gain many valuable insights into the future steps for our project. Jeff informed us that, although he had used simulate lighting demonstrations in the past, they were large setups that are hardly portable within the trunk of a car. Thus, a portable light source that could do something similar, albeit on a smaller scale, could give him an edge over competitors who wouldn’t be able to show them such a presentation. This can be especially practical in an often cloudy city like Pittsburgh or when no daylight is available, where it can be hard to show customers how some blinds might appear on sunny days, or how well they can block out intrusive artificial light from the neighbor’s yard or light from the interior to protect the customer’s privacy. Part of Jeff’s job is showing the customer what are the best blinds for their needs, and this could certainly help with that. Thus, our concept had been met with approval, and we were also able to receive significant critique on our design regarding how we could improve it to fit Jeff’s needs, making for a very productive critique session.

Critique Inputs and Moving Forward

Among the the many pieces of advice we had received, several important points stood out. Since we had been aware of this drawback in the prototype, we weren’t surprised when the subject of the lighting brightness and color was brought up. Our prototype was using an RGB LED strip, but it wasn’t close to intense enough to achieve bright enough lighting that could actually simulate how sunlight would appear, which we intended to save for the final version when we knew we had a good prototype concept. Jeff also requested that we change the dimensions from a fairly square width and height to a rectangular one. Furthermore, he was interested in a slightly elevated design so he wouldn’t have to hold it up, freeing his hands to demo his blinds. We proposed building a stand and using it as a storage device as well,  which worked for Jeff. Our prototype also didn’t diffuse the light enough, but we’ve got several solutions in mind, such as moving the light source further back from the frosted acrylic pane, since we had it fairly close in the prototype. Jeff had mentioned adding a heat feature of some sort, which we think the high intensity LEDs may make possible as an added bonus, although the intensity of this heat is uncertain.

Aside from those major goals, there were several other minor changes we also discussed. While we had initially brought up storing more presets with Jeff, which was a good idea, we eventually learned that he probably wasn’t going to need more than 3 presets like we had on the prototype, so any others could be tuned himself. Jeff had mentioned using a rocker switch as he didn’t need the fine control, but we concluded we would probably stick with the current input design as it worked anyways and didn’t suffer from bouncing. On the aesthetic side, Jeff requested that it come in black, which would be doable. While he had been fine with the tactile interface as it met all practical needs, it was not without possible improvements. We considered that slightly larger knobs might be nice, but since we had already ordered buttons previously that were similar to our current ones, we were probably still going to use them.

Overall, our priorities were going to be programming and wiring up a new light source, setting up new presets and adjusting the acrylic window to approximate real world lighting conditions, adjusting the dimensions, and building a stand. Following those will largely be aesthetic goals that we hopefully can accomplish after taking care of our priorities.

 

Timeline:

Fri. Nov. 15 – Research and submit request for brighter LED module

Sun. Nov. 17 – Finalize CAD for new design, submit to Stratasys

Tue. Nov. 19 – (in class) If printing is complete, remove support material. Otherwise, design and laser cut acrylic pieces (LED backing, diffusing cover, stand elements). Programming and hardware.

Thu. Nov. 21 – (in class) Design and laser cut acrylic pieces. Programming and hardware.

Sun. Nov. 24 – All electrical components finalized and working, stand fabrication complete.

Tue. Nov. 26 – (in class) Finish 3D print (sand and spray paint)

Thu. Nov. 28 – (in class) Finish 3D print (sand and spray paint)

Fri. Nov. 29 – Finishing and spray paint complete

Sat. Nov. 30 – Final assembly

Tue. Dec. 3 – Final project crit.

]]>
Team James – Initial Meeting https://courses.ideate.cmu.edu/60-223/f2019/work/team-james-initial-meeting/ Tue, 29 Oct 2019 13:14:31 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8665 Brief introduction

We (Nick, Leland and Jeena) as a team of students of the CMU Introduction to Physical Computing class are required to make an assistive device for an older person. We are assigned to work with James. On October 21th, 2 of our team members Nick and Jeena conducted an interview with James at his house to learn more about him.

Interview agenda

Prior to our interview, we prepared an agenda about the general flow we wanted to have for our interview as well as the types of questions we thought should be answered before we began thinking about project ideas for James. This was our agenda:

Icebreakers/Introductions:

James’ Career and background, his interests

-Each of our majors and backgrounds, some things we like to do for fun or classes we are currently taking at CMU

Logistical Questions:

-Preferred methods of communication

Best times to email James

-General expectations about how often he’d like us to update him

Questions about his daily life:

-Describe a typical day

-Some of his major hobbies

-Locations or activity he visits or performs often

-General nuisances he experiences

-The most annoying thing he’s had to do in the past couple of days

-New things he’s been trying out

-Things he does for fun with other people and who are those people?

-Things he liked to do but no longer does

Questions about James

-Some words to described himself

-His motivations for becoming an Osher student

-His hopes for the project

Interview summary and major takeaways

We arrived at our meeting with few expectations. James was waiting for us outside ready to receive us and right off the bat, he seemed to have some ideas about what kinds of things he thought would be good projects for us to tackle around the house. Before we got down to business, however, we talked for a while about his career at CMU and he in turn asked us about our interests and hobbies. At one point, the conversation turned to James and his wife’s love of frogs as we had noticed earlier a large number of amphibian statues scattered around the porch. He described to us how he had built the porch himself and would often sit outside and read.

As we went on, we learned more about James’ area of research as a physics professor and his frequent Skype calls with scientists at the CERN particle accelerator as well as his attempts to learn piano, German, and French simultaneously. One theme that seemed to come up repeatedly was James’ love for tinkering and working with his hands. He was very familiar with technology of all kinds and was planning on buying a drone later in the year.

Finally, James described to us the two problems that had come to mind as potential project ideas. He led us upstairs and showed us the first one.

James often has to straddle this staircase and lean over the fan to open his window.

Several times a year, James has a open a close a precariously positioned window behind a fan he would use for climate control. To open it, he would have to straddle a very high staircase and lift the heavy window himself (something he continues to do now).

His other major concern was a light switch that was blocked by a dresser. The only access he had to it was through a small hole cut out of the inside of the bureau which was rather awkward to reach when turning off the lights. He had thought there might be a way to create a new remote switch that was easier to reach.

This is the hole cut into the side of his bureau. On the other side is a light switch sandwiched between the furniture and the wall.

 

As we left, we spent some time playing music on the piano and talking to him about his process of learning. He said he loves Baroque, but struggled with learning how to play separate parts of a piece with separate hands.

In general, the interview felt like it went quite well. It was nice to arrive and find that James already had some ideas in mind, however, we were a little worried as we left that nothing had immediately stuck out as a project idea. Though James suggested some himself, with elaborating on the ideas ourselves, the projects initially struck us as too mechanically challenging or tending towards the trivial side.

What we learned about James, however, was invaluable. He’s a maker as well and is excited about being involved in the project. I’m sure if he could have enrolled in 223 himself, he would have and he had no shortage of ideas for his own projects in the future. So we felt like we left with an solid understanding of our customer, we were just missing the perfect project.

Post-interview wrap-up discussion

The meeting followed the agenda as James answered all the questions on the agenda. However, it was hard to come up with some definite possibilities for what to build a device for due to some miscommunication. James signed up to be an Osher student because he thought that he’d be building something, so he had a few ideas in mind . However, these ideas were quite mechanical problems that wouldn’t suit good problems for us to solve electronically.  If we were to do it again, we would make sure to be upfront with what kind of problems we’re looking for.  For example, when he is talking about a daily process of his, we should be suggestive in what-ifs to give him a better picture of what we’re looking for. I believe each member of the team felt the same way about the interview, as we all had trouble finding some good ideas of what to make for James.

]]>
Team Enid – Initial Meeting https://courses.ideate.cmu.edu/60-223/f2019/work/team-enid-initial-meeting/ Tue, 29 Oct 2019 07:31:07 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8701  A brief introduction: 

This project is about designing an assistive device for an older person. As part of the product design process, we met with our client, Enid, to learn more about her life, daily needs, habits, and routines. The interview was held at Enid’s home, where she and her husband Errol kindly offered us a tour of their house and of their daily life. Our purpose was to extract information about Enid’s life to come up with a design scenario that would render her daily activities easier and more pleasant.

General Agenda

  • Introductions
  • Overview of our task as a team
    • Goals: Demo our own project 2
    • Timeline: Prototype crit and final deadlines
    • Questions?
  • Interview
    • Probably start with daily routine, (or interesting points she brings up when we introduce ourselves)
    • Poll questions from below based on how the conversation is going, probably don’t just go in order
  • Conclusions

How we improvised based on our initial agenda:

Questionnaire:

Before the meeting, a necessary thing was to compose a questionnaire. Then, we could start a conversation with Enid guided by the questionnaire itself. Our questions covered a wide range of aspects, concerning either matters of practicality, such as 1) “Are you experiencing any health condition or  sensori-motor disability?”, 2) “Is there anything that you would like to change or do differently in your daily routine?”, or touching the field of imagination, such as 1) “Do you have a favourite superhero?”, 2) “If you could possess a non-human property, what would that be?”.

Body and mind language:

While talking with Enid, we tried to extract meaning from her words, behavior and gestures, rendering visible to each other any potential preference, affinity, dislike she had developed about her daily activities. For instance, observing the vocabulary she used to express herself, we pointed out her love for reading. We followed this strategy in order to focus on particular activities each time and “dig” deeper. 

House tour:

We also asked for a short house tour. During that we confirmed Enid’s affinity for books (big libraries around the place) and plants, and also observed details not mentioned before (traveling – various destination books).

Many of her plants are situated like so in the living room, but there are more around the house

A look at a small portion of the total books in Enid’s house

Activity performance:

Finally, in the questionnaire’s section “Daily routine”, we were asking our older friend to perform her daily activities. Even though we didn’t have the opportunity to do that in our first meeting, we focused on one particular activity and asked her to perform a video for us a few days later. 

Meeting Summary and Major Takeaways: 

While we had some amazing discussions and learned a lot about Enid’s and her husband’s life, we were not able to identify many ideas that we could do for this project. We quickly came to the conclusion that Enid doesn’t have issues that she would like to see solved by us, so the challenge became coming up with something that could enhance her life and still be practical. In the meeting itself,  we came up with one potential project idea. Enid has a lot of plants around the house, a couple are in a central location and others are scattered around the house. She said that it could be helpful to have a reminder system or something that could automatically water all the plants. We pondered this idea with Enid for a while, and tried coming up with ways that we could implement this wirelessly, since there were many plants around the house. We weren’t entirely sold on creating this for Enid, so we decided that we would send her the full list of questions that we didn’t get to in order to see if that may glean any other potential projects.

Concluding Thoughts After Meeting

Though we went off script early on during the interview, we did become acquainted with Enid and Errol through a more casual exchange. We learned a lot about their day-to-day life, but we could have driven the conversation more towards needs and issues where we could step in. Our team did not have the time to debrief immediately after the visit, but we sent our original list of questions via email for her consideration. We were pleasantly surprised to find Enid reply with an answer to all of the questions. We met after receiving these responses, and brainstormed other ideas for the assistive device.

From the visit and her email response, we gathered that Enid and Errol enjoy reading books and going to the movies. We considered building a movie/book recommendation system that is integrated into their home/furniture, but we decided to explore options that were able to leverage the “physical” aspect of physical computing.

Enid also mentioned that one of the tasks she finds monotonous is cleaning up after a meal daily. She also mentioned enjoying doing puzzles at breakfast, which led us to ask ourselves, “can we turn this activity into a sort of game?” We began exploring ways to make this obligatory task more entertaining, perhaps by integrating a game or puzzle into the activity.

]]>