A box that can display a user’s moods

Video

Overall demonstration of mood box.

Overall Photo

Detail Photos

This is an inside view of the mood box. On the bottom is a bread board with LEDs, resistors, and buttons soldered onto it. Each LED corresponds to a button. This was mostly used as a debugging tool.

 

The LED matrix is mounted on a mini bread board. This made wiring it in the box a lot easier.

Demonstration Images

You operate buttons to display different moods. There are five different moods (Anger, Sad, Neutral, Happy, Bored).

The angry mood is triggered when left most button is pressed.

 

Process Images and Review

Initial Ideation Sketches. I originally wanted to make more abstract animations, but it was difficult to convey emotion. As a result, I chose to use eyes.

Around the time of ideation and creating the first prototype, I realized that I had to limit how ambitious I wanted to be with animations. I originally wanted multicolor matrix animations that were pretty visually complex, but it did not make sense in the context of expressing emotion. I chose to animate eyes because emotion expressed through eyes is more recognizable and the work load was more reasonable.

Laser cut box with push buttons screwed in. This was the first time that I got to see and do laser cutting and it was super cool!

This was when all the buttons, LEDs, and their resistors were properly soldered and working. I originally thought a bread board would be fine, but with so many buttons and loose connections, I ended up soldering everything. The LEDs were originally a debugging tool that helped me see if input from the buttons was working, but I ended up incorporating different color LEDs into the project.

A big moment where I had to pivot was when I realized I had soldered my 16×8 LED matrix incorrectly. I called a couple of hardware stores, but apparently desoldering tools are rarely in stock. Luckily I still had one working 8×8 LED matrix and since all my animations were already 8×8 bit maps, it wasn’t difficult to finish animating all the different moods. The current version of the project still has a gaping square for where the other eye should go, but that can be fixed in future version of the mood box.

Finished version of the mood box (pirate eye edition). I soldered the 16×8 LED matrix incorrectly, so I ended up only being able to implement the box with one eye.

Discussion

I received a lot of positive reactions from the animations. “The animation is super cool!! I love that you were able to convey emotion with just two frames for each emotion”. While most of the moods were just two frames, the “sad” mood was around 6 frames because I wanted to animate a tear. I really appreciate all the love the animations got I hope I can improve them in future versions of the box. I also received quite a bit feedback regarding user interaction. “The buttons could have labels or colors to differentiate them”. Currently, I’d say the weakest part of the project is the user interface. The buttons are all one color so it’s difficult to tell which mood is which, but I’d like to solve this issue with color coded buttons.

There was mix of things that I loved and hated about the final product. Laser cutting the box and screwing in the buttons was a lot of fun and I like how compact the box is. I enjoyed soldering LEDs, resistors, and buttons and I believe that was one of my smarter decisions. While I do like the current animations, I know I could improve the way that I implemented the code and allow for more variation. Overall, I’m not happy with the current version, but I still love the idea of a mood box and I want to build off of what I have now.

One of my biggest take aways is hardware is hard (pun intended). The majority of my issues were hardware issues and most of the time I did not even know that it was a hardware issue. When I was first prototyping with an 8×8 LED matrix, I spent hours debugging example code when it was just the LED matrix that was broken. Near the end of this project, I ended up soldering my 16×8 matrix wrong and when I realized it was a hardware issue, it was difficult to move past it. On a more positive note, I enjoyed laser cutting and I would love to have more opportunities to do it.

In a new iteration of the box, I’d fix the 16×8 matrix so there would be two eyes. I’d also want to color code the buttons to indicate different moods. I’d also want to add some mechanism that can turn the box on and off.

Technical Information

 

/*
   60-223: Mood Box
   Shuyu Zhang (shuyuzha)
   
   Description: This device reads 5 buttons as inputs, and
   drives 5 and a LED Matrix as outputs. When the Red LED Button
   is pressed, the Angry animation is triggered. The Blue LED Button
   triggers the Sad Animation, the Whote LED Button triggers the Neutral
   Animation, the Yellow LED Button triggers the Happy Animation,
   and the Green LED Button triggers the Bored Animation. 

   Collaboration and sources:
   1) I referenced the Adafruit LED Matrix code to make bitmaps and 
   load them onto the LED Matrix.
   
   https://github.com/adafruit/Adafruit_LED_Backpack/blob/master/examples/matrix8x8/matrix8x8.ino


   Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
       4         Output    Red LED
       5         Input     Red LED Button
       6         Input     Blue LED Button
       7         Output    Blue LED
       8         Input     White LED Button
       9         Output    White LED
       10        Input     Yellow LED Button
       11        Output    Yellow LED
       12        Output    Green LED 
       13        Input     Green LED Button
       SDA       Output    LED Matrix I2C backpack
       SCL       Output    LED Matrix I2C backpack
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

const int DELAYONE = 1000;
const int REDLED = 4;
const int REDBUTTON = 5;
const int BLUELED = 7;
const int BLUEBUTTON = 6;
const int WHITELED = 9;
const int WHITEBUTTON = 8;
const int YELLOWLED = 11;
const int YELLOWBUTTON = 10;
const int GREENLED = 12;
const int GREENBUTTON = 13;

const int NUMLED = 5;

Adafruit_8x16matrix matrix = Adafruit_8x16matrix();

static const uint8_t PROGMEM
smile_bmp[] =
{ B00111100,
  B01000010,
  B10100101,
  B10000001,
  B10100101,
  B10011001,
  B01000010,
  B00111100
},
neutral_bmp[] =
{ B00111100,
  B01000010,
  B10100101,
  B10000001,
  B10111101,
  B10000001,
  B01000010,
  B00111100
},
frown_bmp[] =
{ B00111100,
  B01000010,
  B10100101,
  B10000001,
  B10011001,
  B10100101,
  B01000010,
  B00111100
},
neutral_eye[] =
{ B00000000,
  B00111100,
  B01111110,
  B01110110,
  B01100110,
  B01111110,
  B00111100,
  B00000000
},
neutral_blink[] =
{ B00000000,
  B00000000,
  B00000000,
  B01000000,
  B01100000,
  B01111110,
  B00111100,
  B00000000
},
sad_eye1[] =
{ B00000000,
  B00000000,
  B01000010,
  B00100100,
  B00011000,
  B00000000,
  B00000000,
  B00000000
},
sad_eye2[] =
{ B00000000,
  B00000000,
  B01000010,
  B00100110,
  B00011000,
  B00000000,
  B00000000,
  B00000000
},
sad_eye3[] =
{ B00000000,
  B00000000,
  B01000010,
  B00100100,
  B00011010,
  B00000000,
  B00000000,
  B00000000
},
sad_eye4[] =
{ B00000000,
  B00000000,
  B01000010,
  B00100100,
  B00011000,
  B00000010,
  B00000000,
  B00000000
},
sad_eye5[] =
{ B00000000,
  B00000000,
  B01000010,
  B00100100,
  B00011000,
  B00000000,
  B00000010,
  B00000000
},
sad_eye6[] =
{ B00000000,
  B00000000,
  B01000010,
  B00100100,
  B00011000,
  B00000000,
  B00000000,
  B00000010
},
bored_eye[] =
{ B00000000,
  B00000000,
  B00000000,
  B01111110,
  B01011010,
  B00100100,
  B00011000,
  B00000000
},
bored_blink[] =
{ B00000000,
  B00000000,
  B00000000,
  B00000000,
  B01111110,
  B00111100,
  B00000000,
  B00000000
},
happy_eye[] =
{ B00000000,
  B00000000,
  B00011000,
  B00100100,
  B01000010,
  B00000000,
  B00000000,
  B00000000
},
happy_blink[] =
{ B00000000,
  B00111100,
  B01111110,
  B01100110,
  B01111110,
  B00111100,
  B00000000,
  B00000000
},
angry_eye[] =
{ B01110000,
  B10001100,
  B10000010,
  B10010110,
  B10011010,
  B01000100,
  B00111000,
  B00000000
},
angry_blink[] =
{ B00000000,
  B10000000,
  B11000000,
  B11110010,
  B11111110,
  B00111100,
  B00000000,
  B00000000
};

int reading;
int LEDs[] = {REDLED, BLUELED, WHITELED, YELLOWLED, GREENLED};
int Buttons[] = {REDBUTTON, BLUEBUTTON, WHITEBUTTON, YELLOWBUTTON, GREENBUTTON};
int lastState[] = {1, 1, 1, 1, 1};
int butState[] = {1, 1, 1, 1, 1};
int LEDState[] = {0, 0, 0, 0, 0};
int faceState[] = {0, 0, 0, 0, 0};
unsigned long lastDebounceTimes[] = {0, 0, 0, 0, 0};

unsigned debounceDelay = 10;
bool RedOn = false;
bool BlueOn = false;
bool AngryOn = false;
bool NeutralOn = false;
bool BoredOn = false;
bool HappyOn = false;

unsigned long neutralTimer = 0;
unsigned long neutralTimer2 = 0;

unsigned long sadTimer1 = 0;
unsigned long sadTimer2 = 0;
unsigned long sadTimer3 = 0;
unsigned long sadTimer4 = 0;
unsigned long sadTimer5 = 0;
unsigned long sadTimer6 = 0;
unsigned long sadTimer7 = 0;

unsigned long angryTimer1 = 0;
unsigned long angryTimer2 = 0;

unsigned long happyTimer1 = 0;
unsigned long happyTimer2 = 0;

unsigned long boredTimer1 = 0;
unsigned long boredTimer2 = 0;

void neutralEye() {
  if (millis() - neutralTimer >= DELAYONE) {
    neutralTimer = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, neutral_eye, 8, 8, LED_ON);
    matrix.writeDisplay();
  } else if (millis() - neutralTimer2 >= (DELAYONE * 3.5)) {
    neutralTimer2 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, neutral_blink, 8, 8, LED_ON);
    matrix.writeDisplay();
  }
}


void sadEye() {

  if (millis() - sadTimer1 >= DELAYONE) {
    sadTimer1 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, sad_eye1, 8, 8, LED_ON);
    matrix.writeDisplay();

  } else if (millis() - sadTimer2 >= DELAYONE) {
    sadTimer2 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, sad_eye2, 8, 8, LED_ON);
    matrix.writeDisplay();

  } else if (millis() - sadTimer3 >= DELAYONE) {
    sadTimer3 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, sad_eye3, 8, 8, LED_ON);
    matrix.writeDisplay();

  } else if (millis() - sadTimer4 >= DELAYONE) {
    sadTimer4 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, sad_eye4, 8, 8, LED_ON);
    matrix.writeDisplay();

  } else if (millis() - sadTimer5 >= DELAYONE ) {
    sadTimer5 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, sad_eye5, 8, 8, LED_ON);
    matrix.writeDisplay();

  } else if (millis() - sadTimer6 >= DELAYONE) {
    sadTimer6 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, sad_eye5, 8, 8, LED_ON);
    matrix.writeDisplay();

  }

}

void boredEye() {
  if (millis() - boredTimer1 >= DELAYONE) {
    boredTimer1 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, bored_eye, 8, 8, LED_ON);
    matrix.writeDisplay();
  } else if (millis() - boredTimer2 >= (DELAYONE * 2)) {
    boredTimer2 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, bored_blink, 8, 8, LED_ON);
    matrix.writeDisplay();
  }

}

void happyEye() {
  if (millis() - happyTimer1 >= DELAYONE) {
    happyTimer1 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, happy_eye, 8, 8, LED_ON);
    matrix.writeDisplay();
  }
  if (millis() - happyTimer2 >= (DELAYONE * 2)) {
    happyTimer2 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, happy_blink, 8, 8, LED_ON);
    matrix.writeDisplay();
  }

}

void angryEye() {

  if (millis() - angryTimer1 >= DELAYONE) {
    angryTimer1 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, angry_eye, 8, 8, LED_ON);
    matrix.writeDisplay();
  }
  angryTimer2 = angryTimer1;
  if (millis() - angryTimer2 >= (DELAYONE / 2)) {
    angryTimer2 = millis();
    matrix.clear();
    matrix.drawBitmap(0, 0, angry_blink, 8, 8, LED_ON);
    matrix.writeDisplay();
  }

}


void setup() {
  Serial.begin(9600);
  Serial.println("8x16 LED Matrix Test");

  pinMode(REDBUTTON, INPUT_PULLUP);
  pinMode(REDLED, OUTPUT);

  pinMode(BLUEBUTTON, INPUT_PULLUP);
  pinMode(BLUELED, OUTPUT);


  pinMode(WHITEBUTTON, INPUT_PULLUP);
  pinMode(WHITELED, OUTPUT);


  pinMode(YELLOWBUTTON, INPUT_PULLUP);
  pinMode(YELLOWLED, OUTPUT);


  pinMode(GREENBUTTON, INPUT_PULLUP);
  pinMode(GREENLED, OUTPUT);

  matrix.begin(0x70);  // pass in the address

}


void loop() {


  Serial.println(butState[0]);

  for (int i = 0; i < NUMLED; i++) {
    reading = digitalRead(Buttons[i]);

    if (reading != lastState[i]) {
      lastDebounceTimes[i] = millis();
    }

    if ((millis() - lastDebounceTimes[i] > debounceDelay)) {
      if (reading != butState[i]) {
        butState[i] = reading;

        if (butState[i] == LOW) {

          if (i == 0) {
            RedOn = true;
            BlueOn = false;
            NeutralOn  = false;
            BoredOn = false;
            HappyOn = false;
          } else if (i == 1) {
            BlueOn = true;
            RedOn = false;
            NeutralOn = false;
            BoredOn = false;
            HappyOn = false;
          } else if (i == 2) {
            NeutralOn = true;
            BlueOn = false;
            RedOn = false;
            BoredOn = false;
            HappyOn = false;
          } else if (i == 3) {
            HappyOn = true;
            RedOn = false;
            BlueOn = false;
            NeutralOn = false;
            BoredOn = false;
          } else if (i == 4) {
            BoredOn = true;
            RedOn = false;
            BlueOn = false;
            NeutralOn = false;
            HappyOn = false;

          }


          LEDState[i] = HIGH;
          faceState[i] = 1;
          for (int j = 0; j < NUMLED; j++) {
            if (j != i) {
              LEDState[j] = LOW;
              faceState[j] = 0;
            }
          }
        }
      }
    }

    for (int k = 0; k < NUMLED; k ++) {
      digitalWrite(LEDs[k], LEDState[k]);
    }


    if (RedOn) {
      angryEye();
    } else if (BlueOn) {
      sadEye();
    } else if (NeutralOn) {
      neutralEye();
    } else if (BoredOn) {
      boredEye();
    } else if (HappyOn) {
      happyEye();
    } else {
      neutralEye();
    }

    lastState[i] = reading;

  }


}