
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
Components needed
| Component | Type | Qty | Buy |
|---|---|---|---|
| SSD1306 OLED Face | display | 1 | €4.30 |
| Feed Button | other | 1 | €8.30 |
| Play Button | other | 1 | €8.30 |
| Sleep Button | other | 1 | €8.30 |
| Piezo Buzzer | actuator | 1 | €4.75 |
| Status LED | actuator | 1 |
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
Wire the OLED face display
Connect OLED VCC to 3.3V, GND to ground, SDA to GPIO21, and SCL to GPIO22.
- Confirm the I2C address — most modules use 0x3C.
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.
- Color-code the buttons (green=feed, blue=play, purple=sleep) for easier identification.
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.
- The LED blinks fast when cranky, slow when sleepy, and stays solid when happy.
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.
- Adjust the idle thresholds in code to make ClawdBot needier or more independent.
Pin assignments
| Pin | Connection | Type |
|---|---|---|
| 3V3 | clawdbot-oled-1 VCC | POWER |
| GND | clawdbot-oled-1 GND | GROUND |
| GPIO 21 | clawdbot-oled-1 SDA | I2C |
| GPIO 22 | clawdbot-oled-1 SCL | I2C |
| GND | feed-button-1 GND | GROUND |
| GPIO 32 | feed-button-1 SIG | DIGITAL |
| GND | play-button-1 GND | GROUND |
| GPIO 33 | play-button-1 SIG | DIGITAL |
| GND | sleep-button-1 GND | GROUND |
| GPIO 25 | sleep-button-1 SIG | DIGITAL |
| GND | clawdbot-buzzer-1 GND | GROUND |
| GPIO 26 | clawdbot-buzzer-1 SIG | PWM |
| GND | clawdbot-led-1 GND | GROUND |
| GPIO 27 | clawdbot-led-1 SIG | DIGITAL |
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.ioReady to build this?
Open this project in Schematik to get the full wiring diagram, pin assignments, and deployable code for the ClawdBot Tamagotchi.
Open in Schematik →Related guides
How to Build a Cosmic Critter Pet with Raspberry Pi Pico
Raspberry Pi Pico · Beginner
How to Build a Gesture-Controlled Mood Lamp with ESP32
ESP32 · Beginner
How to Build an Arcade Reaction Tower with ESP32
ESP32 · Beginner
How to Build a Self-Balancing Rover with ESP32
ESP32 · Intermediate