the midterm - fortune teller!
I worked with Diba to create a project that, with embedded switches, can determine one’s fortune. The idea was to create a fortune teller that could randomly generate a fortune for the user. What unfolded throughout our process made it become much more than that!
We decided to tackle this project by beginning with the basic wiring and coding of the project. This actually turned out to be very challenging and did not feel basic at all. But once we got this down, we were able to make changes based on the affordances of the fortune teller and the way we wanted it to go. We pseudocoded first but ended up having to take it step by step. We added the potentiometer and the button to start, which would help so that the code isn’t endlessly running through the phases. We encountered issues with our serial, but it ended up being very trivial and we solved them quickly with Scott’s help! We also wanted to add neopixels to our project. We learned that we had to have a 5V output, so we used Diba’s board, which is a nano. Once we fixed that, they worked! We realized our wires were incredibly awkward and made the fortune teller able to literally walk, so we wanted to use threaded wires. Then, we created our pretty final product, dropped our 3D printed globe thing too much, and finalized the p5.js code, which is just text on the canvas.
We’re really happy with this final product! It felt like the perfect level of challenge that taught us more about physical computing and Arduino. We were able to overcome the things that stood in our way and we are proud of what we’ve made.
Process photos:




this is our fortune teller literally being able to stand and walk… NOT ideal for our setup


You can watch a video of our final product here!
Arduino code:
const int startBtnPin = 10;
const int ledPin1 = 2;
const int switchPin1 = 6;
const int ledPin2 = 3;
const int switchPin2 = 7;
const int ledPin3 = 4;
const int switchPin3 = 8;
const int switchPin4 = 9;
const int potPin = A7;
int startBtnState;
int switch1State;
int switch2State;
int switch3State;
int switch4State;
int potPinVal;
int prevPotVal;
int phase = 0;
int switchCount;
String nounArray[] = {"She", "He", "You", "We", "Your mom", "Your cat", "Your dad", "Your friend", "I"};
String verbArray[] = {" jump over", " run from", " kill", " carry", " eat", " read", " play with", " talk to", " look at"};
String objectArray[] = {" a sandwich", " a robber", " a cat", " your computer", " a snack", " a subway rat", " a pigeon", " a car", " the president"};
String timeArray[] = {" tomorrow", " today", " in a year", " yesterday", " right now", " in the near future", " next week", " this afternoon", " tonight"};
String fortune = "";
String col = String("color");
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required nfor 16 MHz Adafruit Trinket
#endif
#define PIXEL_PIN 12 // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 30
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
strip.show();
pinMode(ledPin1, OUTPUT);
pinMode(switchPin1, INPUT);
pinMode(ledPin2, OUTPUT);
pinMode(switchPin2, INPUT);
pinMode(ledPin3, OUTPUT);
pinMode(switchPin3, INPUT);
pinMode(switchPin4, INPUT);
pinMode(potPin, INPUT);
pinMode(startBtnPin, INPUT);
fortune = nounArray[random(0,8)] + " will" + verbArray[random(0,8)] + objectArray[random(0,8)] + timeArray[random(0,8)];
Serial.begin(9600);
while(!Serial){
;;
}
//phase = 1;
prevPotVal = analogRead(potPin);
}
void loop() {
//Serial.println(phase);
if (phase == 0) {
Serial.println(phase);
delay(20);
startBtnState = digitalRead(startBtnPin);
if (startBtnState == HIGH) {
phase = 1;
}
}
if (phase == 1) {
colorWipe(strip.Color(255, 0, 0), 50); // Red
digitalWrite(ledPin1, HIGH);
digitalWrite(ledPin2, LOW);
//phase one is evaluating the potentiometer for the color
Serial.println(phase);
delay(6000);
potPinVal = analogRead(potPin);
if (potPinVal < 500) {
col = "pink";
} else if (potPinVal < 1000) {
col = "orange";
} else if (potPinVal < 3000) {
col = "red";
} else if (potPinVal < 4095) {
col = "purple";
} else {
col = "green";
}
phase = 2;
//need to re-evaluate the numbers here, not sure why but it's being measured to 4000????
}
if (phase == 2) {
colorWipe(strip.Color( 0, 255, 0), 50); // Green
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, HIGH);
//Serial.print("phase 2 color "); Serial.println(col);
//Serial.print(col.length()); Serial.println(col);
Serial.println(col);
delay(20);
if (switchCount != col.length()) {
switch1State = digitalRead(switchPin1);
switch2State = digitalRead(switchPin2);
if (switch1State == HIGH) {
//digitalWrite(ledPin1, HIGH);
switchCount += 1;
delay(2000);
} else {
//digitalWrite(ledPin1, LOW);
}
if (switch2State == HIGH) {
//digitalWrite(ledPin2, HIGH);
switchCount += 1;
delay(2000);
} else {
//digitalWrite(ledPin2, LOW);
}
}
if (switchCount >= col.length()) {
digitalWrite(ledPin2, LOW);
phase = 3;
}
}
if (phase == 3) {
colorWipe(strip.Color( 0, 0, 255), 50); // Blue
Serial.println(phase);
delay(20);
digitalWrite(ledPin3, HIGH);
switch3State = digitalRead(switchPin3);
switch4State = digitalRead(switchPin4);
if(switch3State == HIGH) {
phase = 4;
}
if (switch4State == HIGH) {
phase = 4;
}
}
if (phase == 4){
theaterChaseRainbow(50);
Serial.println(fortune);
delay(10000);
digitalWrite(ledPin3, LOW);
fortune = nounArray[random(0,8)] + " will" + verbArray[random(0,8)] + objectArray[random(0,8)] + timeArray[random(0,8)];
phase = 0;
switchCount = 0;
}
}
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in increments of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
p5 code:
//code to connect to serial:https://wp.nyu.edu/electronics/serial-communication/
let port;
let connectBtn;
let phase;
// let nounArray = [];
// let verbArray = [];
// let objectArray = [];
// let timeArray = [];
let fortune;
function setup() {
createCanvas(windowWidth, windowHeight);
port = createSerial();
connectBtn = createButton("connect");
connectBtn.position(10, 10);
connectBtn.mousePressed(connectBtnClicked);
textAlign(CENTER);
textSize(windowWidth / 20);
fill("white");
}
function draw() {
phase = port.readUntil("\n");
phase.trim();
//phase = "Here's my text";
print(phase);
if (phase.length > 0 ) {
if (phase == 0) {
background("pink");
text("press the button to start!", windowWidth/2, windowHeight/2);
} else if (phase == 1) {
background("pink");
text("twist the knob!", windowWidth/2, windowHeight/2);
} else if (phase == 3) {
background("pink");
text("open and close the flap!", windowWidth/2, windowHeight/2);
} else if (phase.length > 10) {
background("pink");
text(phase, windowWidth/2, windowHeight/2);
}
else if (phase.length>2) {
background("pink");
text("your color is " + phase, windowWidth/2, windowHeight/2);
}
}
// if (phase.length > 0)
// {
// if (phase == 0 || phase == "1" || phase == "3") {
// if (phase == "0") {
// background(220);
// text("Press the button to start", windowWidth / 2, windowHeight / 2);
// }
// if (phase == "1") {
// background(220);
// text("Twist the knob.", windowWidth / 2, windowHeight / 2);
// }
// } else if (phase.length > 10) {
// //this is when the serial output is the final fortune stage - a long string
// background(220);
// text(phase, windowWidth / 2, windowHeight / 2);
// } else if (phase == "3") {
// text("Open and close the flap to get your fortune!", windowWidth/2, windowHeight/2);
// }else if (phase.length > 2) {
// // this is when the serial output is the color - not any of the numbers
// background(220);
// if (phase == "red") {
// background(rgb(240, 155, 155));
// } else if (phase == "pink") {
// background("pink");
// } else if (phase == "orange") {
// background("orange");
// } else if (phase == "purple") {
// background("rgb(207,158,207)");
// } else if (phase == "green") {
// background("rgb(130,196,130)");
// }
// text("Your color is " + phase, windowWidth / 2, windowHeight / 2);
// }
// }
}
function connectBtnClicked() {
if (!port.opened()) {
port.open(9600);
} else {
port.close();
}
}

