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