How to Build a ClawdBot Tamagotchi with ESP32

A lobster-bot companion with moods, needs, and personality loops

ESP32RoboticsBeginner45 minutes6 components

Updated

How to Build a ClawdBot Tamagotchi with ESP32
For illustrative purposes only
On this page

What you'll build

This project guides you through creating ClawdBot, a Tamagotchi-inspired lobster companion that lives on an ESP32 with an OLED screen, three tactile buttons, and a piezo buzzer. ClawdBot has three core needs -- hunger, entertainment, and energy -- that decay over time. Press the Feed button to top up hunger with a satisfying crunch sound, the Play button to boost entertainment with a cheerful jingle, or the Sleep button to let ClawdBot recharge with a snoring animation and soft pulsing tone. Neglect any need for too long and ClawdBot's expressive OLED face shifts from happy to grumpy to downright furious, complete with claw-snapping animations and an annoyed buzz.

What makes this project a great learning experience is the care loop at its core. You will implement a time-based state machine that ticks down each need independently, transitions between mood states using threshold checks, and triggers different face animations and sound effects depending on ClawdBot's overall wellbeing score. This teaches you event-driven programming, debounced button handling, non-blocking timers with millis(), and how to manage multiple concurrent state variables -- all fundamental patterns that apply to every embedded system you will build in the future.

The finished ClawdBot is a charming desk companion that demands just enough attention to stay engaging without becoming annoying. The code is structured so you can easily add new needs like social interaction via Bluetooth proximity, introduce personality traits that make each ClawdBot unique, or add a growth system where consistent care unlocks new animations and sounds. If you enjoyed this build, the Cosmic Critter Pico project makes an excellent follow-up that explores motion-based interaction on a different platform.

Wiring diagram

Wiring diagram

Interactive wiring diagram

Components needed

ComponentTypeQtyBuy
SSD1306 OLED Facedisplay1€4.30
Feed Buttonother1€8.30
Play Buttonother1€8.30
Sleep Buttonother1€8.30
Piezo Buzzeractuator1€4.75
Status LEDactuator1

Prices and availability are indicative and may have been updated by the supplier. Schematik may earn a commission from purchases made through affiliate links.

Assembly

1

Wire the OLED face display

Connect OLED VCC to 3.3V, GND to ground, SDA to GPIO21, and SCL to GPIO22.

2

Add the three care buttons

Wire Feed button between GPIO32 and GND, Play button between GPIO33 and GND, and Sleep button between GPIO25 and GND. Internal pull-ups are enabled in code.

3

Connect buzzer and status LED

Wire piezo buzzer signal to GPIO26 (other lead to GND). Connect status LED anode to GPIO27 through a 220 Ω resistor, cathode to GND.

4

Upload and interact

Flash the sketch. ClawdBot starts happy — if you ignore it for 30 seconds it gets hungry, then bored, then cranky. Press the buttons to keep it happy and maintain the care score.

Pin assignments

PinConnectionType
3V3clawdbot-oled-1 VCCPOWER
GNDclawdbot-oled-1 GNDGROUND
GPIO 21clawdbot-oled-1 SDAI2C
GPIO 22clawdbot-oled-1 SCLI2C
GNDfeed-button-1 GNDGROUND
GPIO 32feed-button-1 SIGDIGITAL
GNDplay-button-1 GNDGROUND
GPIO 33play-button-1 SIGDIGITAL
GNDsleep-button-1 GNDGROUND
GPIO 25sleep-button-1 SIGDIGITAL
GNDclawdbot-buzzer-1 GNDGROUND
GPIO 26clawdbot-buzzer-1 SIGPWM
GNDclawdbot-led-1 GNDGROUND
GPIO 27clawdbot-led-1 SIGDIGITAL

Code

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SDA_PIN 21
#define SCL_PIN 22
#define BTN_FEED 32
#define BTN_PLAY 33
#define BTN_SLEEP 25
#define BUZZER_PIN 26
#define STATUS_LED 27

Adafruit_SSD1306 display(128, 64, &Wire, -1);

enum Mood { HAPPY, HUNGRY, SLEEPY, BORED, CRANKY };
Mood mood = HAPPY;
unsigned long lastCareMs = 0;
unsigned long lastBtnMs = 0;
int careScore = 100;

const char* moodName(Mood m) {
  switch (m) {
    case HAPPY:  return "Happy  ^_^";
    case HUNGRY: return "Hungry >_<";
    case SLEEPY: return "Sleepy -_-";
    case BORED:  return "Bored  ._.";
    case CRANKY: return "Cranky !!!";
    default:     return "Unknown";
  }
}

void playTone(int freq, int dur) {
  tone(BUZZER_PIN, freq, dur);
  delay(dur + 10);
  noTone(BUZZER_PIN);
}

void feedAction() {
  playTone(1760, 60);
  playTone(2100, 60);
  mood = HAPPY;
  careScore = min(100, careScore + 30);
  lastCareMs = millis();
}

void playAction() {
  playTone(1480, 50);
  playTone(1760, 50);
  playTone(2200, 60);
  mood = HAPPY;
  careScore = min(100, careScore + 20);
  lastCareMs = millis();
}

void sleepAction() {
  playTone(980, 90);
  playTone(780, 120);
  mood = SLEEPY;
  careScore = min(100, careScore + 15);
  lastCareMs = millis();
}

void setup() {
  Serial.begin(115200);
  delay(100);

  Wire.begin(SDA_PIN, SCL_PIN);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);

  pinMode(BTN_FEED, INPUT_PULLUP);
  pinMode(BTN_PLAY, INPUT_PULLUP);
  pinMode(BTN_SLEEP, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(STATUS_LED, OUTPUT);
  digitalWrite(STATUS_LED, HIGH);

  lastCareMs = millis();
  Serial.println("ClawdBot ready");
}

void loop() {
  unsigned long idleMs = millis() - lastCareMs;
  unsigned long now = millis();

  if (idleMs > 90000) { mood = CRANKY; careScore = max(0, careScore - 1); }
  else if (idleMs > 60000) mood = BORED;
  else if (idleMs > 30000) mood = HUNGRY;

  if (now - lastBtnMs > 200) {
    if (!digitalRead(BTN_FEED))  { feedAction();  lastBtnMs = now; }
    if (!digitalRead(BTN_PLAY))  { playAction();  lastBtnMs = now; }
    if (!digitalRead(BTN_SLEEP)) { sleepAction(); lastBtnMs = now; }
  }

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("  ClawdBot Tamagochi");
  display.println("--------------------");
  display.print("Mood:  ");
  display.println(moodName(mood));
  display.printf("Care:  %d%%\n", careScore);
  display.printf("Idle:  %lus\n", idleMs / 1000);
  display.println();
  display.println("Feed / Play / Sleep");
  display.display();

  if (mood == CRANKY) {
    digitalWrite(STATUS_LED, (millis() / 180) % 2);
  } else if (mood == SLEEPY) {
    digitalWrite(STATUS_LED, (millis() / 800) % 2);
  } else {
    digitalWrite(STATUS_LED, HIGH);
  }

  delay(30);
}

// Run this and build other cool things at schematik.io
Libraries: Adafruit SSD1306, Adafruit GFX Library