Evie LaComb
Evie LaComb
The Cube is an artifact that leaves much for the human imagination. Its simplicity in use and complexity in presentation work together to bring people in and wonder about its origins.
When one approaches the object they might say it looks both technological and magical. It has four switches and a speaker visible on it's sides. When turned on the cube lights up with a pulse and an intriguing sound. It then awaits an input, inviting the user to flip it's switches and explore it's meaning. When the switches are flipped in a "correct pattern" a set of lights will light up on the perimeter of the cube and the cube gives a positive jingle. The user will then continue to flip switches at random in order to achieve more lights.
As each set of lights are activated, reaching the next set is slightly harder and takes a little bit longer to stumble upon. The solutions to this cube are not random, but completely arbitrary, as they have no real discernable meaning or pattern between themselves. When The Cube is lit around all sides it plays a new tune and lights up in all different colors around its perimeter, signaling it has completed its function.
The meaning behind the cube and what it does is up to the imagination of the user. Someone with a completely practical mind might see this box as a useless toy, but a child or more imaginative user might see a different world in which this cube originates; perhaps the cube is completing a magical or highly technological function that is simply not apparent to our eyes.
The Cube brings people in with its physicality, but also exists in the space of imagination in the world building of its user. Presentation wise I would love to see this cube displayed in a museum as if it was being studied or displayed. The lack of explanation for this cube, and the mystery behind it, the exploration of what it does, and the invitation to do so is what makes this artifact special.
These triangles where glued to every corner, and how I suspended the LED strip inside the cube.
In order to make construction easier, I left a few of the side panels of while I threaded the LED strip inside. The letters helped me orient the cube in where the strip needed to be, A being the first 8 LEDs. The the skeleton is 3D printed and the panels are lazer cut.
Make Shift Wiring Plan for Protoboard. A simply means it will contect to the Arduino.
Here you can see everything connected so I could trouble shoot and make sure everything worked before mounting the electronics semi-permanently in the cube.
Above is my cardboard model in comparison with my printed skeleton. I added a quarter inch to each face of the cube, and the skelton itself added to the overall dimentions. This added space was decided upon to fit electronics with room to acess the insides.
It was at this point I realized the back of the LED strips were ugly tape, so I had to go through and cover the backs of each strip with black electrical tape. I am not sure if this ended up mattering though, because you can barely see it.
Protoboard half way through contruction. There are more wires then needed due to some wiring planning mistakes, and I should have made a better plan then what is seen on the left. The fourth switch is connected to male and female jumpers so it can be removed completely as it will be mounted on the lid panel of the box.
The electronics are mounted on two platsic platforms that clipped into either side of the cube. On one side is the protoboard and the battery and then across is the Arduino with easy acess to its ports.
This is the logic behind what is a possible solution in the stages. You can see how the original plan changed a little bit and how I explored different combinations so solutions would not overlap with the previous. The final order is shown in the circled numbers and the stared rows on the first page. the 3rd case became the 5th case and the fifth became the 6th.
Coding the startup Animation
Light animation for successful combination and reset to clear
Same animations, tested in the box - some edits to speed and color
User Testing: As my first Guinee pig, I wanted to test how long it would take to solve the cube as I was afraid people might give up if it took too long. In this first test I found that it is best to have the fist case very easy to solve so the user feels the immediate incentive that this is what they are supposed to do and to keep doing it. I also found that my current code takes about an average time of a minute to a minute and a half to solve. I feel like there are cases where a longer solving time might be more exciting, but for the sake of testing I left it at this time as I myself was getting frustrated if it took longer.
At the time of this being submitted there is still one bug that I have not been able to figure out. The cube was working at some point of the process, but something changed either in my code or the wiring that caused it to fail latter on. If I set my code to just the final mode (mode 7) the cube lights up as planned with the multicolor, but when you get to the end of mode 6 when it is supposed to change to mode 7 it just starts clicking and fizzling out.
The current clicking problem at the end of mode 6.
The cube coded to mode 7.
I am happy with the outcome of this project even if the process was at times painful. My main area of pride and pain is in the physical construction of the piece. I told myself that after I had finished the code and had a working prototype on the breadboard that I was basically done and it would only take a day to solder and construct the final. That one day quickly become 3 days and one night. When all the parts came together in the end it turned into chaos, and the cube I designed was not built for so much trouble shooting. The worst casualty of construction came when I threaded the 48 LED strips into the box. Once I did this, It would be very difficult to take them out and repair them if per se one of the bulbs fried and ruined the entire strip. Of course my worst fear came to pass and I had to pop out one of the sides of the box in order to cut out and re-solder the wires while the strip was still in the box. If you have noticed, this is why there are only three lights on one side of the cube. If I could go back in time or do this project again, I would make the interior structure so that the LED strip clipped into the corners instead of threaded through so it would have been easier to place them inside as well as take them out.
Secondly, I would have loved to spend a little more time on the detail of my code and the sounds. If I had more time on this project I would love to go back and make the sounds line up with the light animations. I am no sound designer, but I feel like this aspect of the cube gave it a lot of personality and if I spent a little more time creating a more complete sound story or personality it could have resonated with the user more then it did. Unfortunately, I had a lot of trouble with the speaker as some of the sounds, especially those that were lower or high pitched didn't work at all on the speaker. The speaker was also quieter when running on the battery then when the Arduino was plugged into the board. Some sounds that worked when plugged into the Arduino didn't work when the speaker was running off the battery, and I think that as the battery died this problem got worse. On my final cube the sounds were inconsistent in volume and I wish they were louder for the final presentation. Furthermore, the cube kept shutting down at its end case where it was coded to light up and play a longer sound. I think the combination of the sound and all the lights changing might have required too much power. This could also have been because of some wires being crossed inside around the power connections, as at times during the prototyping stage the cube would glitch, make a fizzle sound and then power off, which was concerning.
Overall, time management could have used some work on this project. I needed to give myself more time for the final construction and I could have spent less time on the physical aspects to work on the more technical aspects such as the code and sounds. I also wish I had finished the cube earlier in order to give myself more time to practice the presentation of the project.
// Project: The Cube
// Electronic Logics and Creative Practice 2023
// Evette LaComb
// Pin Map:
// 5 - switch one
// 4 - switch two
// 3 - switch three
// 2 - switch four
// 6 - neopixel LEDs
// 10 - speaker
// 11 - speaker
// This code reads switches and then lights LEDs and plays Sounds based on a mode number
// I used a neopixel and a speaker library in this code I did not write.
int TOGone = 5;
int TOGtwo = 4;
int TOGthree = 3;
int TOGfour = 2;
int gReen = 10;
int bLue = 10;
int mode = 0;
int resetLED = false;
int colorT = false;
int modeSix = false;
int pix = 48;
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define PIN 6 // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS 48 // Popular NeoPixel ring size
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 200 // Time (in milliseconds) to pause between pixels
//////////
//SPEAKER stuff
#include "Arduino.h"
#include "DFRobotDFPlayerMini.h"
#if (defined(ARDUINO_AVR_UNO) || defined(ESP8266)) // Using a soft serial port
#include <SoftwareSerial.h>
SoftwareSerial softSerial(/*rx =*/10, /*tx =*/11);
#define FPSerial softSerial
#else
#define FPSerial Serial10p...
#endif
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);
////////////////////////////////////////////////////
void setup() {
Serial.begin(9600);
pinMode(TOGone, INPUT);
pinMode(TOGtwo, INPUT);
pinMode(TOGthree, INPUT);
pinMode(TOGfour, INPUT);
// light stuff
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
pixels.begin();
/////////////////////////////////////
//Speaker Stuff
#if (defined ESP32)
FPSerial.begin(9600, SERIAL_8N1, /*rx =*/D3, /*tx =*/D2);
#else
FPSerial.begin(9600);
#endif
Serial.begin(115200);
if (!myDFPlayer.begin(FPSerial, /*isACK = */true, /*doReset = */true)) { //Use serial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while(true){
delay(0); // Code to compatible with ESP8266 watch dog.
}
}
myDFPlayer.volume(20); //Set volume value. From 0 to 30
}
void loop() {
/////////////////////////////////////////////
int TOGR1 = digitalRead(TOGone);
int TOGR2 = digitalRead(TOGtwo);
int TOGR3 = digitalRead(TOGthree);
int TOGR4 = digitalRead(TOGfour);
////////////////////////////////
///RESET THE LEDS WHEN TURING ON
if(resetLED == false){
for(int i=0; i<48; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
pixels.show();
}
resetLED = true;
Serial.println("reset");
}
////////////////////////////////
// START UP LIGHT SHOW
if (mode == 0){
myDFPlayer.play(3);
for(int i=0; i<=20; i++){
for(int i=0; i<48; i++) {
pixels.setPixelColor(i, pixels.Color(0, gReen, bLue));
pixels.show();
delay(1);
}
if (colorT == false){
gReen += 10;
bLue += 10;
if (gReen > 100){
colorT = true;
}
}
if (colorT == true){
gReen -= 10;
bLue -= 10;
}
}
mode += 1;
}
//////////////////
//CASE ONE
if (mode == 1){
if (((TOGR1 == HIGH) | (TOGR2 == HIGH) | (TOGR3 == LOW)) && (TOGR4 == HIGH)){
myDFPlayer.play(2);
for(int i=0; i<7; i++) {
pixels.setPixelColor(i, pixels.Color(0, 200, 200));
pixels.show();
delay(DELAYVAL);
}
Serial.println("mode 1 complete");
mode += 1;
}
}
////////////////////////
//CASE TWO
if (mode == 2){
if(((TOGR1 == LOW) | (TOGR2 == LOW) | (TOGR3 == LOW)) && (TOGR4 == LOW)){
myDFPlayer.play(2);
for(int i=7; i<15; i++) {
pixels.setPixelColor(i, pixels.Color(0, 200, 200));
pixels.show();
delay(DELAYVAL);
}
Serial.println("mode 2 complete");
mode += 1;
}
}
if (mode == 3){
if(((TOGR1 == LOW) | (TOGR2 == LOW)) && ((TOGR3 == LOW) && (TOGR4 == HIGH))){
myDFPlayer.play(2);
for(int i=15; i<23; i++) {
pixels.setPixelColor(i, pixels.Color(0, 200, 200));
pixels.show();
delay(DELAYVAL);
}
Serial.println("mode 3 complete");
mode += 1;
}
}
if (mode == 4){
if(((TOGR1 == HIGH) | (TOGR2 == LOW)) && ((TOGR3 == HIGH) && (TOGR4 == HIGH))){
myDFPlayer.play(2);
for(int i=23; i<31; i++) {
pixels.setPixelColor(i, pixels.Color(0, 200, 200));
pixels.show();
delay(DELAYVAL);
}
Serial.println("mode 4 complete");
mode += 1;
}
}
if (mode == 5){
if(((TOGR1 == LOW) && (TOGR2 == LOW)) && ((TOGR3 == LOW) | (TOGR4 == LOW))){
myDFPlayer.play(2);
for(int i=31; i<39; i++) {
pixels.setPixelColor(i, pixels.Color(0, 200, 200));
pixels.show();
delay(DELAYVAL);
}
Serial.println("mode 5 complete");
mode += 1;
}
}
if (mode == 6){
if((TOGR1 == HIGH) && (TOGR2 == HIGH) && (TOGR3 == HIGH) && (TOGR4 == HIGH)){
myDFPlayer.play(2);
for(int i=39; i<47; i++) {
pixels.setPixelColor(i, pixels.Color(0, 200, 200));
pixels.show();
delay(DELAYVAL);
}
for(int i =0; i < 47; i++){
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
mode += 1;
delay(500);
}
}
if (mode == 7){
for (int i =0; i <3; i ++){
myDFPlayer.volume(25);
myDFPlayer.play(1);
for(int i=0; i<47; i++) {
pixels.setPixelColor(i, pixels.Color(random(0,250), random(0,250), random(0,250) ));
pixels.show();
delay(150);
}
for(int i =0; i < 47; i++){
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
}
}
}