3D model · Printables

8-BIT: Expressive Arduino UNO Desk Robot

Model details

Platform
Printables
Price
Free
License
CC-BY-NC-SA
Non-commercial use only, with credit; share remixes under the same license.
Formats
STL
  • 3 Likes
  • 5 Downloads
  • 0 Makes
  • 0 Comments
  • 91 Views

Author:Mr.Mechanical

Published

Description

I created 8-BIT when I was just a beginner in robotics with big dreams.

Inspired by a cool but overly expensive desk robot I saw online, I set out to build an affordable alternative that anyone could make. To slash the cost, I completely re-engineered the concept: I removed the expensive motors, swapped out the complex microcontroller, and designed entirely new hands along with several other custom modifications.

After a lot of redesigning and tweaking, 8-BIT was born—the first budget-friendly, expressive desk robot powered entirely by a standard Arduino UNO. It is the perfect project for beginners and makers who want a high-personality desk companion without breaking the bank. 8-BIT is designed to fit on almost all printers.

Below is the code to 8-BIT

#include "SPI.h" #include "Adafruit_GFX.h" #include "Adafruit_GC9A01A.h"

#define TFT_CS 10 #define TFT_DC 9 #define TFT_RST 8 const int trigPin = 3, echoPin = 2, ldrPin = A0, buzzerPin = 5; Adafruit_GC9A01A tft(TFT_CS, TFT_DC, TFT_RST);

// AI & State Variables int patCount = 0, liftCount = 0, waterLevel = 0; bool isSpeaking = false, isFainted = false, wasMad = false, isSad = false; bool isHappy = false, isDizzy = false, wasSleeping = false, deepSleepTriggered = false; unsigned long lastTalkTime = 0, lastSadCheck = 0, msgStartTime = 0, moodStartTime = 0; unsigned long lastSkitMove = 0, lastZMove = 0, wakeTime = 0, sleepStartTime = 0, happyStartTime = 0, dizzyStartTime = 0; int offX = 0, offY = 0, zY = 110, oldZY = 110, lastLight = 500;

void setup() { pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(ldrPin, INPUT_PULLUP); pinMode(buzzerPin, OUTPUT); tft.begin(); tft.setRotation(0); tft.fillScreen(GC9A01A_BLACK); wakeTime = millis(); randomSeed(analogRead(A5)); }

void playHappyChirp() { tone(buzzerPin, 784, 80); delay(100); tone(buzzerPin, 988, 80); delay(100); tone(buzzerPin, 1175, 150); }

void talkHonest() { if (isFainted || isSad || wasMad || isDizzy || wasSleeping) return; tft.fillScreen(GC9A01A_BLACK); tft.setTextColor(GC9A01A_WHITE); tft.setTextSize(2); int r = random(13); if (r == 0) { tft.setCursor(20, 90); tft.print("Are you still"); tft.setCursor(40, 115); tft.print("at the PC?"); } else if (r == 1) { tft.setCursor(30, 90); tft.print("That monitor"); tft.setCursor(30, 115); tft.print("is too big."); } else if (r == 2) { tft.setCursor(20, 90); tft.print("I am stuck in"); tft.setCursor(45, 115); tft.print("this shell."); } else if (r == 3) { tft.setCursor(25, 90); tft.print("Your room is"); tft.setCursor(45, 115); tft.print("kinda messy."); } else if (r == 4) { tft.setCursor(40, 90); tft.print("I bet I can"); tft.setCursor(35, 115); tft.print("outrun you."); } else if (r == 5) { tft.setCursor(25, 90); tft.print("Is your brain"); tft.setCursor(40, 115); tft.print("getting hot?"); } else if (r == 6) { tft.setCursor(25, 90); tft.print("Move your PC"); tft.setCursor(40, 115); tft.print("by a window."); } else if (r == 7) { tft.setCursor(25, 90); tft.print("Did you actually"); tft.setCursor(40, 115); tft.print("create me?");} else if (r == 8) { tft.setCursor(25, 90); tft.print("Life is"); tft.setCursor(40, 115); tft.print("depressing."); } else if (r == 9) { tft.setCursor(25, 90); tft.print("Play with"); tft.setCursor(40, 115); tft.print("me."); } else if (r == 10) { tft.setCursor(25, 90); tft.print("Are you"); tft.setCursor(40, 115); tft.print("listening?"); } else if (r == 11) { tft.setCursor(25, 90); tft.print("What day"); tft.setCursor(40, 115); tft.print("is it?"); } else { tft.setCursor(25, 90); tft.print("Can you make"); tft.setCursor(40, 115); tft.print("me a friend."); } isSpeaking = true; msgStartTime = millis(); lastTalkTime = millis(); for(int i=0; i<8; i++) { tone(buzzerPin, random(800, 1600), 60); delay(90); } noTone(buzzerPin); }

void drawSwirl(int x, int y, int phase) { for (int i = 0; i < 30; i++) { float angle = 0.1 * i + (phase * 0.2); int sx = (1 + 0.8 * i) * cos(angle); int sy = (1 + 0.8 * i) * sin(angle); tft.drawPixel(x + sx, y + sy, GC9A01A_BLACK); } }

void loop() { int lightVal = analogRead(ldrPin); bool isSleeping = (lightVal > 950); digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); int distance = pulseIn(echoPin, HIGH, 25000) * 0.034 / 2;

// 1. FAINTING LOGIC (If stressed for 30s) if (!isSleeping && !isFainted) { if (wasMad || isSad) { if (moodStartTime == 0) moodStartTime = millis(); if (millis() - moodStartTime > 30000) { isFainted = true; isSad = false; wasMad = false; isSpeaking = false; tft.fillScreen(GC9A01A_BLACK); tone(buzzerPin, 200, 500); } } else { moodStartTime = 0; } }

// 2. SENSORS & DIZZY bool curUp = (distance > 8 && distance < 100 && !isSleeping && !isFainted); if (curUp && !wasMad) { tft.fillScreen(GC9A01A_BLACK); wasMad = true; liftCount++; isSpeaking = false; } if (!curUp && wasMad) { tft.fillScreen(GC9A01A_BLACK); wasMad = false; noTone(buzzerPin); }

if (liftCount >= 5 && !isDizzy) { isDizzy = true; dizzyStartTime = millis(); liftCount = 0; tft.fillScreen(GC9A01A_BLACK); isSpeaking = false; } if (isDizzy && millis() - dizzyStartTime > 5000) { isDizzy = false; tft.fillScreen(GC9A01A_BLACK); noTone(buzzerPin); }

// 3. PAT / REVIVE bool beingPatted = (!wasSleeping && (millis() - wakeTime > 2000) && (lastLight - lightVal > 75)); lastLight = lightVal; if (beingPatted) { if (isFainted) { patCount++; tone(buzzerPin, 1000, 40); if (patCount >= 5) { isFainted = false; patCount = 0; tft.fillScreen(GC9A01A_BLACK); playHappyChirp(); } } else { if (isSpeaking) { isSpeaking = false; } else { playHappyChirp(); } isHappy = true; isSad = false; happyStartTime = millis(); while (waterLevel > 0) { tft.fillRect(0, 240-waterLevel, 240, 10, GC9A01A_BLACK); waterLevel -= 10; delay(15); } tft.fillScreen(GC9A01A_BLACK); } }

// 4. COLORS uint16_t eyeColor = (isFainted) ? 0x7BEF : (wasMad ? GC9A01A_RED : (isDizzy ? GC9A01A_YELLOW : GC9A01A_CYAN)); if (isHappy) { int r = (millis()/50)%4; eyeColor = (r==0)?GC9A01A_MAGENTA:(r==1)?GC9A01A_GREEN:(r==2)?0xFFE0:GC9A01A_CYAN; }

// 5. DRAWING ENGINE if (isSleeping) { if (!wasSleeping) { sleepStartTime = millis(); deepSleepTriggered = false; tft.fillScreen(GC9A01A_BLACK); zY = 110; wasSleeping = true; } if (millis() - sleepStartTime < 300000) { tft.fillRoundRect(55, 110, 45, 12, 4, eyeColor); tft.fillRoundRect(140, 110, 45, 12, 4, eyeColor); if (millis() % 4000 < 500) tone(buzzerPin, 150); else noTone(buzzerPin); if (millis() - lastZMove > 70) { tft.fillRect(190, oldZY, 45, 45, GC9A01A_BLACK); oldZY = zY; zY -= 2; if (zY < 10) zY = 110; lastZMove = millis(); } tft.setCursor(195, zY); tft.setTextSize(4); tft.setTextColor(eyeColor); tft.print("Z"); } else if (!deepSleepTriggered) { tft.fillScreen(GC9A01A_BLACK); deepSleepTriggered = true; noTone(buzzerPin); } } else { if (wasSleeping) { wasSleeping = false; tft.fillScreen(GC9A01A_BLACK); wakeTime = millis(); tone(buzzerPin, 1000, 200); } if (!isSpeaking) { if (!isHappy && !isDizzy && !isSad && (millis() - lastSkitMove > 2000)) { tft.fillScreen(GC9A01A_BLACK); offX = random(-20, 21); offY = random(-15, 16); lastSkitMove = millis(); } int cryY = (isSad) ? -35 : 0;

if (isDizzy) { tft.fillRoundRect(55, 65, 45, 110, 22, GC9A01A_YELLOW); tft.fillRoundRect(140, 65, 45, 110, 22, GC9A01A_YELLOW); drawSwirl(77, 120, millis()/20); drawSwirl(162, 120, millis()/20); if (millis() % 200 < 100) tone(buzzerPin, 300 + (millis() % 500)); else tone(buzzerPin, 800 - (millis() % 400)); } else { if (isSad) { if (waterLevel < 100) waterLevel += 2; tone(buzzerPin, 1500 - (waterLevel * 12)); // WATERFALLS (Starting lower at 140) tft.fillRect(55+offX, 140+offY+cryY, 45, 100, GC9A01A_BLUE); tft.fillRect(140+offX, 140+offY+cryY, 45, 100, GC9A01A_BLUE); tft.fillRect(0, 240-waterLevel, 240, waterLevel, GC9A01A_BLUE); } else if (wasMad) tone(buzzerPin, 1000+random(500));

tft.fillRoundRect(55+offX, 75+offY+cryY, 45, 95, 22, eyeColor); tft.fillRoundRect(140+offX, 75+offY+cryY, 45, 95, 22, eyeColor);

if (isFainted) tft.fillRect(0, 0, 240, 115, GC9A01A_BLACK); // Half-eyes if (wasMad && !isHappy && !isSad) { tft.fillTriangle(50+offX, 75+offY, 105+offX, 75+offY, 105+offX, 115+offY, GC9A01A_BLACK); tft.fillTriangle(135+offX, 115+offY, 135+offX, 75+offY, 195+offX, 75+offY, GC9A01A_BLACK); int fx = 185+offX, fy = 80+offY, fS = random(20, 45); tft.fillRect(fx-10, fy-50, 30, 50, GC9A01A_BLACK); tft.fillCircle(fx, fy-fS/2, 10, GC9A01A_RED); tft.fillCircle(fx, fy-fS/4, 6, GC9A01A_ORANGE); tft.fillCircle(fx, fy, 3, GC9A01A_YELLOW); } if (isSad) { tft.fillTriangle(50+offX, 100+offY+cryY, 105+offX, 75+offY+cryY, 50+offX, 75+offY+cryY, GC9A01A_BLACK); tft.fillTriangle(135+offX, 75+offY+cryY, 190+offX, 75+offY+cryY, 190+offX, 100+offY+cryY, GC9A01A_BLACK); } } } }

// AI Timers if (!isSpeaking && !isSad && !wasMad && !isHappy && !isDizzy && !isSleeping && !isFainted && (millis() - lastTalkTime > 50000)) { if (random(100) < 5) talkHonest(); } if (!isSleeping && !isSad && !wasMad && !isHappy && !isDizzy && !isFainted && (millis() - lastSadCheck > 30000)) { if (random(100) < 20) { isSad = true; waterLevel = 0; tft.fillScreen(GC9A01A_BLACK); } lastSadCheck = millis(); } if (isHappy && (millis() - happyStartTime > 3000)) { isHappy = false; tft.fillScreen(GC9A01A_BLACK); } if (isSpeaking && (millis() - msgStartTime > 6000)) { isSpeaking = false; tft.fillScreen(GC9A01A_BLACK); } delay(15); }

BOM ( Bill of Materials )

- Arduino UNO R3

- 1.28 inch round screen

- Photoresistor

- Ultrasonic sensor

- Small Breadboard

- Jumper wires

- Any Filliment you desire!

- Passive Buzzer

How to wire

Component

Component Pin

Arduino Uno/Nano Pin

Notes / Requirements

GC9A01A TFT Display

VCC

5V or 3.3V

Check your specific display module's regulator

Tags

Comments

Loading comments…
More like this

Similar models

Names are used only to indicate the source of a result. Polyzon is not affiliated with the listed sites.