Tippi Li
Front view of the smoothie recipe generator
This machine generate random smoothie recipe including six ingredients in four categories: vegetable, fruit, protein and liquid. The user is able to regenerate ingredients in individual categories of the recipe if they are out of that ingredient or not satisfied with the combination. The user can also print out the recipe and keep the physical copy for later use.
Side view
The dimension of the box are 20cm*15cm*7cm
Back view
Hole on the back for the wire to connect to the computer and functional to let the machine hang on the wall.
The machine is designed like a person holding a cup.
Detailed shoot of the machine's head. The eyes are buttons where the function is indicated by the labels on the eyelashes. The mouth is a rectangular hole allowing the receipt to spit out.
Inside view
I used six buttons with six 10om resisters, four 19*2LCDs, a thermal printer and an Arduino for this piece.
In this video, I showcased the generate function, regenerate function as well as the print function of the machine.
1. Initial ideation sketch of the project including the physical, electronic components as well as schematic diagram.
2. I tinkered with the thermal printer first since I am new with this component. I tried to print text with different alignment which is helpful for the formatting of the receipt.
3. A major challenge I face is controlling multiple LCD screens with the Arduino. After browsing through different tutorials and websites, I modified the address of the LCDs by soldering the pins at the back of the screens.
4. After that I am able to control multiple screens to display different contents! I also wired the buttons and tested out the "generate" and "print" function which worked out fine.
5. This are the sketches for the design of the formatting of the receipt as well as the shape of the machine.
7. After the physical box is printed, I put the wired and soldered components into it. I also used two breadboards to stay organized and prevent wires from falling out of the socket easily.
6. Then I modeled the physical component with Fusion 360 and printed them with 3mm thick wood.
8. After the components are put together I tested the program again and finally glued the box together
I am proud that I am able to make a useful device for myself. I really pushed with the physical appearance of the machine despite the limited time and unfamiliarity with Fusion 360. I am happy with my adaptable design which can be hang on wall and placed on counter as well as the function to regenerate ingredients. I also figured out how to control multiple LCD screens with Arduino which I though was impossible at first. I tried to compromise by using LCDs of different sizes at one point but I still went back to my initial idea of using four same sized LCDs in the sketch. The most dfficult part of the project for me is modeling the physical component in Fusion 360. I often found myself unable to proceed because my previous steps are done improperly such as not constrained to be perpendicular, etc. Therefore, I spend a lot of time fixing previous problems and ended up making my model twice. From this experience I learned to always constrain my shapes and make multiple sketches with good name.
The final product is functional and a pretty good realization of my initial ideation. However, I wish I could complete the project in a more timely manner so that I have more time to try out the machine and refine the details or make additional features. There are so many things I can push further with this project. For example, I could add a buzzer that imitates the sound of the juicer when it is generating the ingredients. I could also make the formatting of the receipt more appealing by adding custom graphics and using different text size and fonts. I could also experiment more with the material of the box such as colored or transparent acrylics and see which one looks better comparing with wood. I also got a lot of thoughtful comments from the final critique. They suggested I could make my physical components more compact since it is a rather large box with relative simple feature and add external power source so it doesn't have to connect to a computer every time. Two future considerations printed out in the critique that I find inspiring are "How can we add or remove ingredients from the list?" and "Amount of each ingredient can be another value (quantity) added". If I have more time I would love to add these features to my machine so that it is more informative as a recipe(include amount of each ingredient) and more flexible to address user needs. I am excited to take this project as a starting point and keep pushing and building from that.
/*
SMOOTHIE RECIPE GENERATOR
Author: Tippi Li
The code randomly fetch ingredients from the four arrays of ingredients and display them on the LCD screen and printed receipt.
pin mapping:
Arduino pin | role | description
___________________________________________________________________
2 input Button pin to generate recipe
3 input Button pin to print recipe
4 input Button pin to regenerate fruit
5 input Button pin to regenerate liquid
6 input Button pin to regenerate protein
7 input Button pin to regenerate veggie
10 output TX_PIN for thermal printer
11 output RX_PIN for thermal printer
Some code referenced from:
- Multiple LCD display with Arduino: https://bestengineeringprojects.com/how-to-interface-multiple-i2c-lcd-to-arduino/
- Example sketch for Adafruit Thermal Printer library for Arduino
- ChatGPT
*/
#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
int smoothieCount = 1; // To keep track of the number of smoothies generated
#define TX_PIN 10 // Arduino transmit YELLOW WIRE labeled RX on printer
#define RX_PIN 11 // Arduino receive GREEN WIRE labeled TX on printer
SoftwareSerial mySerial(RX_PIN, TX_PIN);
#define BUTTON1 4
#define BUTTON2 5
#define BUTTON3 6
#define BUTTON4 7
#define GENERATEBUTTON 2
#define PRINTBUTTON 3
Adafruit_Thermal printer(&mySerial);
LiquidCrystal_I2C lcd1(0x27, 16, 2);
LiquidCrystal_I2C lcd2(0x26, 16, 2);
LiquidCrystal_I2C lcd3(0x25, 16, 2);
LiquidCrystal_I2C lcd4(0x23, 16, 2);
const char* veggie[] = {"spinach", "kale", "celery", "cucumber", "carrot", "beetroot", "zucchini", "romaine lettuce", "parsley", "broccoli"};
const char* fruits[] = {"apple", "avocado", "banana", "blueberries", "mango", "pineapple", "strawberries", "peach", "pear", "raspberries"};
const char* protein[] = {"oats", "nuts", "chia seeds", "hemp seeds", "Greek yogurt", "sunflower seeds", "pumpkin seeds"};
const char* liquid[] = {"coconut water", "milk", "almond milk", "oat milk", "water"};
String selectedVeggie1, selectedVeggie2;
String selectedFruit1, selectedFruit2;
String selectedProtein;
String selectedLiquid;
// Function to regenerate veggies
void generateVeggies() {
int veggieIndex1 = random(0, sizeof(veggie) / sizeof(veggie[0]));
selectedVeggie1 = veggie[veggieIndex1];
int veggieIndex2;
do {
veggieIndex2 = random(0, sizeof(veggie) / sizeof(veggie[0]));
} while (veggieIndex2 == veggieIndex1);
selectedVeggie2 = veggie[veggieIndex2];
}
// Function to regenerate fruits
void generateFruits() {
int fruitIndex1 = random(0, sizeof(fruits) / sizeof(fruits[0]));
selectedFruit1 = fruits[fruitIndex1];
int fruitIndex2;
do {
fruitIndex2 = random(0, sizeof(fruits) / sizeof(fruits[0]));
} while (fruitIndex2 == fruitIndex1);
selectedFruit2 = fruits[fruitIndex2];
}
// Function to regenerate protein
void generateProtein() {
int proteinIndex = random(0, sizeof(protein) / sizeof(protein[0]));
selectedProtein = protein[proteinIndex];
}
// Function to regenerate liquid
void generateLiquid() {
int liquidIndex = random(0, sizeof(liquid) / sizeof(liquid[0]));
selectedLiquid = liquid[liquidIndex];
}
// Function to update all LCDs
void updateLCDs() {
// Update LCD1 (Veggies)
lcd1.clear();
lcd1.home();
lcd1.setCursor(0, 0);
lcd1.print(selectedVeggie1);
lcd1.setCursor(0, 1);
lcd1.print(selectedVeggie2);
// Update LCD2 (Fruits)
lcd2.clear();
lcd2.home();
lcd2.setCursor(0, 0);
lcd2.print(selectedFruit1);
lcd2.setCursor(0, 1);
lcd2.print(selectedFruit2);
// Update LCD3 (Protein)
lcd3.clear();
lcd3.home();
lcd3.setCursor(0, 0);
lcd3.print(selectedProtein);
// Update LCD4 (Liquid)
lcd4.clear();
lcd4.home();
lcd4.setCursor(0, 0);
lcd4.print(selectedLiquid);
}
// Function to print the ingredients
void printIngredients() {
// Print date and time
DateTime now = rtc.now(); // Get current time from RTC
printer.justify('C');
printer.println("Smoothie #" + String(smoothieCount));
printer.println("============================");
printer.feed(1);
// Print stored veggies
printer.justify('C');
printer.inverseOn();
printer.println("Veggies:");
printer.inverseOff();
printer.justify('L');
printer.println(selectedVeggie1);
printer.println(selectedVeggie2);
// Print stored protein
printer.justify('C');
printer.inverseOn();
printer.println("\nProtein:");
printer.inverseOff();
printer.justify('L');
printer.println(selectedProtein);
// Print stored liquid
printer.justify('C');
printer.inverseOn();
printer.println("\nLiquid/Base:");
printer.inverseOff();
printer.justify('L');
printer.println(selectedLiquid);
// Print stored fruits
printer.justify('C');
printer.inverseOn();
printer.println("\nFruits:");
printer.inverseOff();
printer.justify('L');
printer.println(selectedFruit1);
printer.println(selectedFruit2);
printer.println("============================");
printer.feed(1); // Leave some space before rating section
// Print rating and review section
printer.justify('C');
printer.println("Rate this smoothie: (1-5)");
printer.println("[ ]1 [ ]2 [ ]3 [ ]4 [ ]5");
printer.feed(1);
printer.println("Your Review:");
printer.println("..............................");
printer.println("..............................");
// Feed lines after printing && Restore printer to defaults
printer.feed(5);
printer.setDefault();
smoothieCount++; // Increment smoothie count for next receipt
}
//----------------------------------
void setup() {
Serial.begin(4800);
// Initialize LCD Screens
lcd1.init();
lcd1.backlight();
lcd2.init();
lcd2.backlight();
lcd3.init();
lcd3.backlight();
lcd4.init();
lcd4.backlight();
// Print welcome message:
lcd1.setCursor(0, 0);
lcd1.print("It's smoothie");
lcd1.setCursor(0, 1);
lcd1.print("time~~~");
lcd2.setCursor(0, 0);
lcd2.print(" Enjoy:)))");
lcd3.setCursor(0, 0);
lcd3.print("Press generate");
lcd3.setCursor(0, 1);
lcd3.print("button below");
lcd4.setCursor(0, 0);
lcd4.print("to start!");
// Initialize SoftwareSerial and Printer
mySerial.begin(19200);
printer.begin();
randomSeed(analogRead(0));
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
pinMode(BUTTON3, INPUT);
pinMode(BUTTON4, INPUT);
pinMode(GENERATEBUTTON, INPUT);
pinMode(PRINTBUTTON, INPUT);
}
//----------------------------------
void loop() {
int button1Val = digitalRead(BUTTON1);
int button2Val = digitalRead(BUTTON2);
int button3Val = digitalRead(BUTTON3);
int button4Val = digitalRead(BUTTON4);
int buttonGVal = digitalRead(GENERATEBUTTON);
int buttonPVal = digitalRead(PRINTBUTTON);
if (button4Val == HIGH) {
generateVeggies();
updateLCDs();
}
if (button1Val == HIGH) {
generateFruits();
updateLCDs();
}
if (button3Val == HIGH) {
generateProtein();
updateLCDs();
}
if (button2Val == HIGH) {
generateLiquid();
updateLCDs();
}
if (buttonGVal == HIGH) {
Serial.println("enter");
generateVeggies();
generateFruits();
generateProtein();
generateLiquid();
updateLCDs();
}
if (buttonPVal == HIGH) {
printIngredients();
}
}