Community project

Lobster Companion Pet Bot

ESP32
Photo of Lobster Companion Pet Bot
Generated with AI

Anita Kirkovska

Published September 8, 2026

Build a digital lobster companion that lives on an ESP32-powered OLED display and responds to care interactions. This tiny pet cycles through moods—happy, hungry, sleepy, bored, and cranky—based on how well it's fed, played with, and rested. The guide includes a complete wiring diagram, parts list, Arduino firmware with mood logic, and step-by-step assembly instructions to get the lobster bot up and interacting within minutes.

Press the Feed button to keep your lobster happy and boost its care score, trigger Play for entertainment and mood boosts, or hit Sleep to let it rest. The piezo buzzer chirps cheerfully with each interaction, the status LED provides visual feedback, and the SSD1306 face displays your pet's current mood with ASCII expressions. Perfect for learning ESP32 programming, I2C communication, and simple state-machine logic in a fun, tactile project.

Wiring diagram

Wiring diagram for Lobster Companion Pet Bot

Gather all the parts

QtyComponent
1

SSD1306 OLED Face

Displays moods, care score, and idle timer.

1

Feed Button

Feeds the ClawdBot and resets hunger.

1

Play Button

Triggers play interaction and happy state.

1

Sleep Button

Puts the bot into sleepy calm mode.

1

Piezo Buzzer

Chirps and emotional feedback tones.

1

Status LED

Blink pattern reflects mood intensity.

1

220 Ω resistor

Current limiting or transistor-base resistor required by the wiring.

Assemble it in 4 steps

1. 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.

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.

  • Color-code the buttons (green=feed, blue=play, purple=sleep) for easier identification.

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.

  • The LED blinks fast when cranky, slow when sleepy, and stays solid when happy.

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.

  • Adjust the idle thresholds in code to make ClawdBot needier or more independent.

Review all connections

1. Connections between "clawdbot-oled-1" and "ESP32"

Functionclawdbot-oled-1ESP32
powerVCC3V3
groundGNDGND
i2cSDAGPIO 21
i2cSCLGPIO 22

2. Connections between "feed-button-1" and "ESP32"

Functionfeed-button-1ESP32
groundGNDGND
digitalSIGGPIO 32

3. Connections between "play-button-1" and "ESP32"

Functionplay-button-1ESP32
groundGNDGND
digitalSIGGPIO 33

4. Connections between "sleep-button-1" and "ESP32"

Functionsleep-button-1ESP32
groundGNDGND
digitalSIGGPIO 25

5. Connections between "clawdbot-buzzer-1" and "ESP32"

Functionclawdbot-buzzer-1ESP32
groundGNDGND
pwmSIGGPIO 26

6. Connections between "clawdbot-led-1" and "ESP32"

Functionclawdbot-led-1ESP32
groundGNDGND
digitalSIG220-ohm-resistor:BGPIO 27

7. Connections between "clawdbot-tamagotchi-220-ohm-resistor-1" and "ESP32"

Functionclawdbot-tamagotchi-220-ohm-resistor-1ESP32
current-limitGPIO 27
current-limitstatus-led:SIGEXT

Deploy the firmware

schematik_esp32.inoOpen in Schematik
#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;
unsigned long lastDecayMs = 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;
    if (now - lastDecayMs >= 1000) {
      careScore = max(0, careScore - 1);
      lastDecayMs = now;
    }
  }
  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);
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik