CONTEXT AND SIGNIFICANCE
Our project draws inspiration from platforms like Wangyiyun Music, where playful and interactive personality quizzes encourage self-reflection. These quizzes use carefully chosen visuals and background music to create a multi-sensory experience, engaging users through sight and sound. They invite people to reflect on their choices and inclinations, fostering an awareness of personal preferences. Inspired by this approach, we sought to transform the typical digital quiz into a three-dimensional, physical interaction.
Guided by our research on physical mechanisms for immersive experiences, we designed a tangible testing machine that brings the concept of a digital quiz into a real, sensory environment. In our project, participants engage with a flipbook that prompts them to answer questions and reflect on their preferences. Based on their responses, the machine releases a mist of a recommended fragrance, allowing participants to experience the scent firsthand rather than just reading its name or description. This shift from digital interaction to direct sensory experience makes the concept come alive, addressing the common curiosity: what if we could actually smell the scents we see in videos or images on our screens?
Our design was further inspired by observing people in fragrance shops, where many seek scents that resonate with their personality and lifestyle. Each fragrance, with its unique combination of top, middle, and base notes, evokes particular scenes and moods. This inspired us to explore how these combinations could convey distinct imagery, allowing participants to discover scents that align with their identity. By integrating visual and olfactory senses, we aim to guide participants on a journey of self-discovery, helping them identify their scent preferences and perhaps introducing them to a fragrance that feels uniquely suited to them.
Our hope is that through this project, people will be encouraged to reflect on the small, healing moments in their daily lives—whether it’s a walk by the beach, a moment resting in a meadow, or a brief break for reading. This reflection can foster self-awareness and self-care, encouraging us to observe and nurture ourselves with the same attentiveness we’d give to a friend’s joy. Inspired by my previous work, the *wearable kinetic: self-care butterfly*, we believe that self-observation is essential to understanding our true sources of comfort.
Scents, in particular, can powerfully enhance happiness and bring a sense of ease, transforming secondhand descriptions into an immediate, soothing experience. Incorporating preferred aromas into daily self-care—like using a favorite diffuser at work—can create a comforting environment and reduce stress. This is why we believe that combining a self-reflection quiz with a personalized fragrance recommendation offers a meaningful, supportive experience, allowing participants to explore self-care in a refreshing way.
CONCEPTION AND DESIGN
Giving participants a cohesive and engaging experience is our goal. Our original plan was to show the participants various scents by using a servo to open a door. Once the correct door was opened, the participants could sniff the perfumes for themselves. Even while opening the door can appear quite elegant, we decided that this aromatherapy presentation was still too indirect, thus we abandoned the design in the original sketch.
We hope the audience will have an amazing experience and be able to respond to all of the questions without interruption. As a result, we must design a mechanism that allows the question cards to be shown smoothly. We considered the display, but we decided against it as we still don't know how to set up a sequence of questions that are connected to button presses. In order to ensure stable question switching by hand flips, we also considered adding a small amount of manual labor. However, this significantly diminished the project's independence and the immersion of participants' autonomous experience, so we also abandoned this alternative.
Later, we found inspiration from a manual page-turning book on Youtube. We hoped to use the stepper instead of manual work to make a self-rotating mechanism controlled by buttons.
Next, we chose two types of cardboard as materials for the question cards.The ability of the question card material to work effectively with the page-turning mechanism is our criterion for choosing it. It can turn pages well under the stepper's strength, and the shielding plate may simply block the hardness. We switched to a harder kraft paper card because the color paper we had been using was too soft and prone to bending downward when the pages were not turned.
As for the page-turning mechanism, we chose to fix the question papers using metal rods that are rotated and straightened by a machine. We originally planned to use materials such as bamboo sticks or chopsticks, but their load-bearing capacity is not as good as metal, and the length is difficult to match with other parts of our mechanism.
FABRICATION AND PRODUCTION
1x Breadboard
1x Arduino Uno
1x USB Cable
1x USB Protector
3x 10 kOhm Resistors
3x small buttons
3x medium buttons
3x Ultrasonic Atomizer
A handful of M/M jumper cables
Matte paper
1 x Ruler
1 x Hot glue gun
1 x Scissors
1 x Wire cutters
1 x Cutting board
Cardboard
1 x Marker
1 x Tape
8 x Craftpaper
3 x Test Tube
3 x Aromatherapy
Soldering set
Step 1: Designing the circuit (Yitong and Ivy)
Following careful discussion, we first verified the fundamental idea of using atomizers as the output and buttons as the input. We later added a stepper to the circuit at the output end after considering the question presentation and deciding to use it to regulate the question board's flipping. Our circuit is rather straightforward after we identify the motor that the input and output depend on. To create the circuit as seen in the above image, we use an Arduino as a bridge.
Review: At first, we planned to use two Arduino, one controlling the buttons and Atomize, one controlling the stepper. The reason we planned as this was separating them to two Arduino can be easier for us to hide the wires since the he distance between the stepper and other originals is relatively far. However, we gave up this idea because:
1)Coding will be extremely challenging if we wish to synchronize two Arduinos and inform them of each other's actions.
2) We discovered that an Arduino has enough pins and can accommodate all of the original components we currently require.
3)After making changes to the layout, we discovered that the stepper wires are sufficiently long to conceal all of the cables inside a sizable box without detracting from the design.
Step 2: Testing the buttons
We have always thought that using larger embedded buttons is necessary to improve the interactive experience. Thus, I attached the wires to a medium size button and put it aside. To improve the clarity and precision of the circuit connection, I first used a standard small button to be placed directly on the breadboard in accordance with the circuit design, verified the location of the button's four pins, and then replaced it with the medium-sized button's positive and negative electrodes for soldered ones.
Additionally, I tested the standard small button using the Arduino example code before swapping it out for the medium button to make sure the procedure worked. After replacing the buttons, I checked with the example code again. To check in real time if the computer recognized that the button was pressed, I added Serial.println to the original code to print out the state of the button.
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
Serial.println("pressed");
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
Serial.println("released");
}
}
Step 3: Testing the Ultrasonic Atomizer
After connecting the ultrasonic atomizer with our circuits, I found they weren't working. I saw that the inside LED was illuminated, indicating that the component itself—rather than the circuits—is the issue. Every time I came across a similar circumstance, I would push the water-absorbing rod closer to the atomizer piece because I discovered that the inadequate contact between it and the piece was the reason it didn't operate. I also used the Blink without delay example code to test whether they are working after implementing.
const int ledPin = 8; // the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change:
const long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(8, OUTPUT);
}
void loop() {
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the difference
// between the current time and last time you blinked the LED is bigger than
// the interval at which you want to blink the LED.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(8, ledState);
}
}
Step 1: Determine the main logic(Yitong and Ivy)
Following discussion, we agreed to incorporate the counting we had studied in class into our code. We would count the number of times each button was hit before comparing the three numbers. Choose the button that has received the most presses, then spray the scent that goes with it.
Step 2: Code in Arduino
Since this is my first time coding, I reached out to my instructor and IMA fellow a lot. After breaking down my coding into three primary sections—counting, comparing, and motivating—I used our instructor Andy's guide to organize the entire process. I included the idea of state into our code in order to improve organization. This makes it easier for us to move from one section to the next without interfering with the sequence of other sections.
Obstacles and Solutions:
1) Finding the largest number out of three is something I haven't learned how to do.I discovered that the method Max() can be used to determine which of two is larger, but this cannot be used in our case. I then came up with the idea to combine "and" with "comparing" after reviewing what I've learnt. This way, we may determine that A is the largest if it is larger than B and larger than C. I resolve the comparing part in this way. Given that there are five questions and three options, it is possible for two options to be selected twice and one option to be selected just once. In this instance, there isn't a greatest number. We decided to motivate a random one from the two largest to deal with this, so I introduced a random function to specially handle this situation.
2) I encountered a problem, that is, after countdown completes counting, I need to use the button corresponding to the largest number to start the next step (atomization). But the count variable itself cannot target the corresponding button. After discussing with fellow, I introduced a new variable mostchosen to represent the button that has been pressed the most, and used the numbers one, two and three to represent the red, yellow and blue buttons respectively.(line14)
3) Another problem I encountered was the atomization time. I wanted to use a 4-second delay to make it spray aromatherapy for only four seconds. However, when the atomizer was activated, it continued to spray aromatherapy.(The original code is shown below.)
After reaching out to my instructor, I realized the problem is the "if statement" checking the mostchosen variable is always true and checked for many times very quickly by the arduino. In this case, the first 4 seconds is followed by the next 4 seconds over and over again, which means the motor is activated for many times. In order to make this motivation happen only once, I introduced bool into my code.
With this revised code, as long as the motor is activated for the fist time, the state of the bool becomes false and will not trigger the motor once again.
4) When I first started coding, I found through the information printed out by the computer that although I only pressed the down button once, it was counted many times. Later, I learned in class that this is because the button is triggered repeatedly, and preval=val must be updated at the end of each state. Otherwise, preval and val will always be different, and it will be regarded as the button being pressed repeatedly.
Review:
1) We originally planned to let Ivy be responsible for the coding of the flip book and the stepper related to the flip book, but in actual operation, we found that this division of labor was unreasonable. Because it would be more difficult to let her to complete stepper's code alone and then integrate it with my code, so in the end I was responsible for completing stepper's code. Ivy was responsible for consulting the instructor and confirming the coding details of stepper's code. Because I had to handle all the issues and difficulties by myself during the programming process, this irrational division of labor really made me feel a little worn out and lonely. My workload will be lessened if the coding is distributed more equitably. For instance, in the counting section, we are in charge of counting and comparing a single button separately before combining them.
Some important learning outcomes:
Timely test for code
Use example code to rule out the possibility that the original itself is damaged
Update preval = val to track the buttons
Using state
Using bool variable
Reasonable use and coordination of variables
(Code structure tutored by Andy)
(Comparing code tutored by Kevin)
(My notes recording the problems during coding)
Full Code
#include <AccelStepper.h>
int state = 0;
int question = 0;
int valA; //Red
int prevalA;
int countA = 0;
int valB; //Yellow
int prevalB;
int countB = 0;
int valC; //Blue
int prevalC;
int countC = 0;
int mostchosen; //represent the most chosen choice; 1 is A; 2 is B; 3 is C
int step;
int DIR_PIN = 7;
int STEP_PIN = 6;
int EN_PIN = 5;
bool mist = false;
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
void steppernewposition(int step) {
stepper.moveTo(step); // Use stepper.moveTo() to set a new target position
stepper.runToPosition(); // Move the stepper motor to the target position
}
void setup() {
Serial.begin(9600);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(8, OUTPUT); //A
pinMode(9, OUTPUT); //B
pinMode(10, OUTPUT); //C
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, LOW);
// Set initial speed & acceleration
stepper.setMaxSpeed(1000);
stepper.setAcceleration(500);
prevalA = LOW;
prevalB = LOW;
prevalC = LOW;
}
void loop() {
valA = digitalRead(2);
valB = digitalRead(3);
valC = digitalRead(4); // Main code, runs repeatedly
if (state == 0) { //Intro
Serial.println("Press any button to start the Fragrance Journey!");
if (prevalA == LOW && valA == HIGH || prevalB == LOW && valB == HIGH || prevalC == LOW && valC == HIGH) { //press any button and start the journey!
state = 1;
step = step - 35;
steppernewposition(step); //flipping to question 1
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
if (state == 1) {
Serial.println("State 1");
if (prevalA == LOW && valA == HIGH) { //question 1, choose A
countA = countA + 1; //Increase count for A
step = step - 25;
steppernewposition(step); //flipping to question 2
Serial.println("motor moved 1");
state = state + 1;
}
if (prevalB == LOW && valB == HIGH) { //question 1, choose B
countB = countB + 1;
step = step - 25;
steppernewposition(step); //flipping to question 2
state = state + 1;
}
if (prevalC == LOW && valC == HIGH) { //question 1, choose C
countC = countC + 1;
step = step - 25;
steppernewposition(step); //flipping to question 2
state = state + 1;
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
if (state == 2) {
Serial.println("State 2");
if (prevalA == LOW && valA == HIGH) { //question 2, choose A
countA = countA + 1;
step = step - 25;
steppernewposition(step); //flipping to question 3
state = state + 1;
}
if (prevalB == LOW && valB == HIGH) { //question 2, choose B
countB = countB + 1;
step = step - 25;
steppernewposition(step); //flipping to question 3
state = state + 1;
}
if (prevalC == LOW && valC == HIGH) { //question 2, choose C
countC = countC + 1;
step = step - 25;
steppernewposition(step); //flipping to question 3
state = state + 1;
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
if (state == 3) {
Serial.println("State 3");
if (prevalA == LOW && valA == HIGH) { //question 3, choose A
countA = countA + 1;
step = step - 25;
steppernewposition(step); //flipping to question 4
state = state + 1;
}
if (prevalB == LOW && valB == HIGH) { //question 3, choose B
countB = countB + 1;
step = step - 25;
steppernewposition(step); //flipping to question 4
state = state + 1;
}
if (prevalC == LOW && valC == HIGH) { //question 3, choose C
countC = countC + 1;
step = step - 25;
steppernewposition(step); //flipping to question 4
state = state + 1;
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
if (state == 4) {
Serial.println("State 4");
if (prevalA == LOW && valA == HIGH) { //question 4, choose A
countA = countA + 1;
step = step - 25;
steppernewposition(step); //flipping to question 5
state = state + 1;
}
if (prevalB == LOW && valB == HIGH) { //question 4, choose B
countB = countB + 1;
step = step - 25;
steppernewposition(step); //flipping to question 5
state = state + 1;
}
if (prevalC == LOW && valC == HIGH) { //question 4, choose C
countC = countC + 1;
step = step - 25;
steppernewposition(step); //flipping to question 5
state = state + 1;
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
if (state == 5) {
Serial.println("State 5");
if (prevalA == LOW && valA == HIGH) { //question 5, choose A
countA = countA + 1;
step = step - 25;
steppernewposition(step); //flipping to waiting page
state = state + 1;
}
if (prevalB == LOW && valB == HIGH) { //question 5, choose B
countB = countB + 1;
step = step - 25;
steppernewposition(step); //flipping to waiting page
state = state + 1;
}
if (prevalC == LOW && valC == HIGH) { //question 5, choose C
countC = countC + 1;
step = step - 25;
steppernewposition(step); //flipping to waiting page
state = state + 1;
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
if (state == 6) { // Compare choices; display result
Serial.println("State 6");
if (countA > countB && countA > countC) {
mostchosen = 1;
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
if (countB > countA && countB > countC) {
mostchosen = 2;
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
if (countC > countA && countC > countB) {
mostchosen = 3;
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
if (countA == countB && countA > countC) {
mostchosen = random(1, 3);
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
if (countB == countC && countB > countA) {
mostchosen = random(2, 4);
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
if (countA == countC && countA > countB) {
mostchosen = random(1, 4);
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
if (countA == countB && countA == countC) {
mostchosen = random(1, 4);
delay(3000);
step = step - 25;
steppernewposition(step); //flipping to final thank you page
state = state + 1;
}
}
if (state == 7) { //activate the differing thing (I don't know the name...)
Serial.println("State 7");
if (mostchosen == 1 && mist == false) { //if A is the most chosen
mist = true;
digitalWrite(8, HIGH);
digitalWrite(9, LOW); //Is this necessary?
digitalWrite(10, LOW);
delay(4000);
digitalWrite(8, LOW);
}
if (mostchosen == 2 && mist == false) {
mist = true;
digitalWrite(9, HIGH);
digitalWrite(8, LOW);
digitalWrite(10, LOW);
delay(4000);
digitalWrite(9, LOW);
}
if (mostchosen == 3 && mist == false) {
mist = true;
digitalWrite(8, LOW);
digitalWrite(9, LOW);
delay(4000);
digitalWrite(10, LOW);
}
if (prevalA == LOW && valA == HIGH || prevalB == LOW && valB == HIGH || prevalC == LOW && valC == HIGH) {
step = step - 25;
steppernewposition(step);
state = 0;
mist = false;
}
prevalA = valA;
prevalB = valB;
prevalC = valC;
}
}
In this part, Ivy was in charge of making the main machine box and the flipping mechanism while I designed the original question-answering box and the question cards. At the last stage, I also helped to implement and fix the stepper.
The Original Answering Box
According to the original sketch, the answering box with buttons implemented is an independent box. Although I made it out successfully, we did not use it finally because:
1) We needed a more holistic installation, rather than separate parts. This will make the operation clearer and more visually beautiful.
2)Later, we considered that the question cards and flip books required more space, which was inconsistent with the size we originally calculated, so we needed a new, wider answer box.
Though we didn't use it at last, I also gained precious experience when making this box. The first step was to solder the wires onto the buttons. In contrast to the previously welded flat cardboard, the process of affixing the button is more challenging due to the reduced dimensions of the mating surfaces. To enhance precision and expedite the welding procedure, I have positioned the welding torch at a calculated distance from the extremity of the metal strip. This strategic placement allows for the localized melting of the metal, thereby facilitating the direct attachment of the wire head to the button's positive and negative terminals. This method ensures a secure and efficient connection, optimizing the welding outcome.
The Question Cards
Step 1: Designing the questions
I listed the names of all the scent elements in the top, middle and bottom notes of the three fragrances we selected. In order to make our problem perspectives more diverse and less homogeneous. I designed the questions regarding to different part of our daily life, for instance, nature preference, music taste. And in order to build a direct connection between questions and the fragrance, I added a question in terms of fruits preference.
After I designed the questions, I reviewed them with Ivy and we both agreed with these questions.
Step 2: Making the question cards
As Ivy was in charge of making the flipping mechanism, she told me the exact size for the cards after careful calculation. We agreed on using a font looks like in magical fairy tales, which is in line with our title "adventure".
In order to make the three options look clearer, we replace ABC with a circle of the same color as the buttons.
We left a small space on top of each question, and finally folded and glued it to the stick of the flipping mechanism.
Step 3: Preparing Aromatherapy
We diluted three different aromas with water and put them into three test tubes. The sizes of the test tubes and atomizers matched exactly. The test tube is installed and fixed in three small holes on the surface of the machine.
Ivy's part
This time ivy made a huge contribution to the prototype, mainly responsible for the mechanism design and production of the flipping book and the revision, design and production of the overall box.
(Ivy,2024)
(Ivy,2024)
(Ivy,2024)
(Ivy,2024)
(Ivy,2024)
(Ivy,2024)
Our users give us really helpful tips. Initially, we designed a fully sealed box, however this would change the lighting and make the question board's light dimmer. According to users, it was quite challenging to see the questions clearly. In order to increase the brightness and let in more natural light, we redesigned our equipment. Additionally, we installed a support beneath the question card so that the questions appear at an angle rather than straight down, making the queries easier to read. In addition, based on suggestions and our observations, we also set a slope on the surface of the machine to be more in line with people's visual habits.
Arora Adventure aims to bring the casual quizzes online into reality and create a multi-sensory and three dimensional experience, where participants reflect on their preferences in daily life and their inner-self, as well as being recommended with a special fragrance according to their preferences.Our project is interactive in that the answers to five questions with various topics form the basis of our final output. To a certain degree, each participant's outcomes are unique and customized. However, our interaction is more centered on differentiation based on amount, but there is no longer any shift in the input and output methods, which is what makes it insufficiently interactive. Buttons are used for input, and fragrance is released as the output. Our design is based on the idea of an interactive question-answering and perfume-recommendation machine, hence the interactive form is extremely straightforward: buttons are used to select the answer. Participants knew what to do next thanks to a very basic written instruction that said, "Press any button to start the journey." This was not a significant departure from our expectations.
Improvements we can make if we have more time:
To enhance the participants' sensory experience, I hope we could match each smell with a comparable musical genre if we had more time. In addition, I want to incorporate noises into upcoming projects. Additionally, certain lights can intensify the feedback and visual impression. One way to make the process of spraying out the mist more noticeable is to turn on the lights while the scent is being sprayed.
I believe that during this project, we still had a lot of cooperation obstacles. At first, we didn't realize that combining coding and prototyping would require us to dedicate at least half a day to solving the issue. Because Ivy's portion was still unfinished, I was unable to perform the final testing right away after finishing the circuit and programming portion. Additionally, a one-day delay could result in additional circuit issues and necessitate further research.We also have diverse work habits. She is accustomed to solving a lot of work at once using explosive power at the end, while I prefer to break the job up into individual days. Cooperation is really hampered by this since I have to wait for her work to be finished before I can proceed to the next phase. We might be able to resolve issues if we can improve our communication beforehand regarding when to merge work at each step. Additionally, because of unique circumstances, there were other instances where we did not begin work in accordance with our original plan, which is quite disappointing for me. I think clearer agreements on the start and end time of the cooperation part should be made. I hope both sides can be serious about the available time we promised to each other.I feel that I have taken on a lot of pressure in this collaboration.But more importantly, Ivy's accurate calculations and prototype manufacture also enabled my efforts. She taught me a lot of prototyping techniques, and I was astounded by both my own and her ability.
The successful portion taught me that it's critical to test the finished part on time, particularly for the circuit and programming, to make sure the subsequent components are constructed correctly. This can make further troubleshooting more effective. Furthermore, I believe that using a separate note to document the issues discovered is really essential. In this method, we can identify the issue in a systematic fashion and document the solution. This serves as a useful guide for future issues of a similar nature. Simultaneously, both parties share ideas and brainstorm, which is highly advantageous for project execution. The process of deciding on the project's structure and specifics goes extremely smoothly because the two individuals' thoughts compliment one another. The correct use of preval=val for detecting button presses is consolidated in the programming process. Mechanism plays an extremely critical part in realizing the problem presented. Simultaneously, we draw inspiration from everyday experiences and frequently apply user thinking to rethink our project during both user and our own testing, making it easier for participants to comprehend and engage with it. This can make the work more approachable by reminding us to consider the relationship with people and everyday life throughout the project process.