A box that can display a user’s moods
Video
Overall Photo
Detail Photos
Demonstration Images
Process Images and Review
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.
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.
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; } }