The Uncertain 7-Cube
Magic Isn't Real
It’s sad but true. We can’t levitate, we can’t teleport and we definitely can’t see the future. That last bit makes the so-called “Magic 8-Ball” especially sinister. There’s nothing magical about randomly answering a yes or no question. Knowing that, the only responsible thing to do is to build a better, more honest, fortune telling device for the enlightened age. I present to you: The Uncertain 7-Cube.
The Uncertain 7-Cube is a non-committal, less-than-helpful, but also entirely honest fortune teller. Simply ask it a yes or no question, give it a nudge, and the 7-Cube will dutifully inform you that it doesn’t have all the facts and doesn’t feel comfortable making a guess. That’s right, in a variety of voices and a multitude of responses, the Uncertain 7-Cube will preserve your sense of responsibility for the future by refusing to make your decisions for you!
To make this happen we’ll need a few things:
- Parallax Emic2 Text-to-Speech Module
- Arduino Pro Mini 5V
- 2” Square ProtoBoard
- Mono Audio Amp Breakout
- Thin Speaker
- Power Cell LiPo Charger/Booster
- 1000mAh Polymer Lithium Ion Battery
- Wake-on-Shake Board
- FTDI Basic Breakout 5V
- Some Male Right Angle and Female Headers
- Some Kind of Enclosure (I used acrylic)
- A Soldering Iron and Some Solder
Behind the Uncertainty
Since magic isn’t making this thing tick, what is? Well, it’s a bit of a jumble:
The ability of the Uncertain 7-Cube to remain in ‘stasis’ while waiting to be picked up or bumped is a function of the Wake-on-Shake board. The Wake-on-Shake uses an ultra low power accelerometer to detect motion. When motion is detected, the on-board microcontroller wakes up and turns on power to the rest of the cube.
The ability to speak (magical as it may seem) is actually provided by the emic2 Text-to-Speech module from Parallax. This module simply takes character strings over a serial connection, parses them into pronounceable words, and uses a built-in voice synthesizer to speak them out loud. Our Mono Amp breakout turns the volume to 11 so you can clearly hear the cube’s non-advice.
All of the different non-committal answers are stored on an Arduino Pro Mini, which is programmed to randomly choose an answer from the list and transmit it over the serial port. When it gets a signal back from the emic2 module that it’s done talking, the Pro Mini shuts everything down and the cube goes back into stasis.
The emic2 module has an input voltage of 5V, so the supply voltage for the cube needed to be able to provide that. A lithium polymer battery and a Powercell board provide 5V to the system. The Powercell also provides an easy way to charge the battery without having to remove it.
The Build
The Uncertain 7-Cube was supposed to be about the size of a Magic 8-Ball except, you know, cube shaped. The way this was accomplished is that almost all of the component boards were mounted vertically on a 2” square ProtoBoard using right-angle headers. This kept everything mounted firmly to the cube and left room in the center for a battery.
As you can see, there’s a ribbon cable attached to the FTDI header on the Arduino Pro Mini. That’s just there to allow the Arduino to be programmed after the whole thing is enclosed. The headphone jack on the Text-to-Speech module, the charging jack on the Powercell and the FTDI ribbon are all accessible from one side of the assembly; That way, I could avoid taking the whole enclosure apart if I needed to get to something.
The only part that isn’t mounted vertically is the Wake-on-Shake board. Since it uses an accelerometer to detect when it changes position, it needs to be firmly connected to the board so it can’t wiggle around and decrease the reliability of the sensor. You’ll also notice the speaker is just hanging off of the board. When everything is mounted in the enclosure, the standoffs keep the speaker from moving.
The Enclosure
Cubes are a nice shape. They’re made up of regular planes and are therefore really easy to fabricate out of almost anything. I decided that laser cut acrylic was the fastest way to make a really good looking enclosure. To make the basic box shape, I used an awesome online tool called BoxMaker which takes the dimensions of your box and the thickness of your material and generates a vector file with the pattern. I imported the pattern into InkScape (a free vector drawing tool) and added a little flair of my own.
After I had the file drawn out, I sent it to the laser cutter. The thin lines were cut and the thick features and shapes were raster etched. When the pieces came out of the laser cutter I cleaned them with a plastic polish and painted inside of the etched features using a white paint pen.
When everything was clean and dry, it was puzzle time. I started by screwing the electronics to the bottom plate of the cube. There were three holes cut in the piece that would match the position of the standoffs. I used a handheld drill to add a chamfer to the holes which would hide the head of the machine screws.
Once the core was in place, I started assembling the cube one panel at a time using hot glue. I left one panel loose so that I could still access the board to change/charge the battery or connect to the emic2 module’s headphone jack.
The Code
Since the Wake-on-Shake board handles all of the hibernation and motion detecting functions, all that the Arduino has to do is pick a phrase, send it to the voice synth, and then tell the Wake-on-Shake to turn everything off again. The code is based heavily on the Emic2 example code provided by Parallax.
language:C
#include <SoftwareSerial.h>
#include <TrueRandom.h>
#define rxPin 2 // Serial input (connects to Emic 2 SOUT)
#define txPin 3 // Serial output (connects to Emic 2 SIN)
#define ledPin 13 // Most Arduino boards have an on-board LED on this pin
#define wakePin 9 // Wake on Shake "Keep Awake" Pin
// set up a new serial port
SoftwareSerial emicSerial = SoftwareSerial(rxPin, txPin);
void setup() // Set up code called once on start-up
{
// define pin modes
pinMode(ledPin, OUTPUT);
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
pinMode(wakePin, OUTPUT);
// set the data rate for the SoftwareSerial port
emicSerial.begin(9600);
/*
When the Emic 2 powers on, it takes about 3 seconds for it to successfully
intialize. It then sends a ":" character to indicate it's ready to accept
commands. If the Emic 2 is already initialized, a CR will also cause it
to send a ":"
*/
emicSerial.print('\n'); // Send a CR in case the system is already up
while (emicSerial.read() != ':'); // When the Emic 2 has initialized and is ready, it will
//send a single ':' character, so wait here until we receive it
delay(10); // Short delay
emicSerial.flush(); // Flush the receive buffer
digitalWrite(wakePin, HIGH); // Tell the Wake-on-Shake that we're still awake
}
void loop()
{
int freeWill = TrueRandom.random(16); // Choose a response. This is the magic part.
// int summonVoice = TrueRandom.random(9); // Summon a voice from Beyond
// summonVoice = char(summonVoice); // Convert the will of the universe
//to a character so the emic module will accept it
// emicSerial.print('N'); // Select voice
// emicSerial.print(summonVoice); // Our voice from Beyond
// emicSerial.print('\n'); // Terminate the voice command
emicSerial.print('S'); // Speak some text command
switch (freeWill) {
case 0:
emicSerial.print("I mean, anything is possible. Right?");
break;
case 1:
emicSerial.print("I don't feel comfortable saying either way.");
break;
case 2:
emicSerial.print("Yes. . Oor No. . I won't speculate.");
break;
case 3:
emicSerial.print("I say: go with what you know.");
break;
case 4:
emicSerial.print("How important is it to know that right now?");
break;
case 5:
emicSerial.print("If it happens, it happens.");
break;
case 6:
emicSerial.print("Hoo could possibly know that?");
break;
case 7:
emicSerial.print("I won't pretend to be an expert on the subject.");
break;
case 8:
emicSerial.print("It's not obviously a yes. It's not a particularly strong no either.");
break;
case 9:
emicSerial.print("Bro... You need to live in the now. The future will be here soon enough.");
break;
case 10:
emicSerial.print("Ummmm. . . Sure? I mean, I don't know. but maybe?");
break;
case 11:
emicSerial.print("You're not giving me a lot to work with here.");
break;
case 12:
emicSerial.print("I'll need to form a subcommittee and get back to you.");
break;
case 13:
emicSerial.print("Market research in that segment shows a trend torward attitudes that strongly favor neither answer in particular.");
break;
case 14:
emicSerial.print("I suggest you shop the idea with a focus group.");
break;
case 15:
emicSerial.print("You should leverage web 2 point oh social leadership to crowdsource the answer.");
break;
default:
emicSerial.print("The default case occurred. This shouldn't have happened.");
}
emicSerial.print('\n'); // Terminate the speech command
while (emicSerial.read() != ':'); // Wait here until the Emic 2 responds with a ":" indicating it's done talking
digitalWrite(wakePin, LOW); // Let the Wake-On-Shake module know it's okay to turn off
while(1){}; // Hang out here until the WOS module shuts us down
}
So there it is, I simply used a random number generator library called “TrueRandom” to pick a number. Then I used that number to select a phrase from a list. That phrase was sent to the serial port, and then the sleep pin was allowed to fall to 0V, signalling the Wake-on-Shake to shut down. Pick up the cube and the whole process starts over again!
All Together Now
There you have it. A fortune telling device that doesn’t make any supernatural claims. Does it take all the fun out it? Maybe. Was it an entertaining build? Totally. Will I win the lottery? I don’t feel comfortable saying either way, but anything could happen... right?
If you wanna take a crack at this yourself, here are some resources you might find useful: