DESKTOP PET COMPANION

A reactive autonomous desktop companion running dynamic state machines and presence tracking feedback loops.

Zzz...
* Note: Digital representation only

System Architecture Overview

The Prototype Pivot

Initial blueprints intended for a 30-pin ESP32 processing architecture to utilize its built-in touch controllers and wireless expansion lines. However, to eliminate hardware debugging variables during initial development, operations were moved to an Arduino Uno.


This strategy allows the core behavioral loops, timing controls, and display frame buffering structures to be locked down completely before shifting to the high-performance dual-core ecosystem.

Hardware Inventory

Arduino Uno R3 Core Processing Unit

Manages the main application timeline, triggers ultrasonic pulses, calculates echo windows, and schedules display updates via the I2C pipeline.

0.96" SSD1306 OLED Screen Display Subsystem

A low-power monochrome screen driven via the 2-wire I2C communication protocol to print changing graphic arrays instantly.

HC-SR04 Module Proximity Sensor Array

Measures exact physical distance by evaluating supersonic echo travel intervals to track user presence.

Passive Audio Buzzer Chirp Synthesis

Generates distinct variable-frequency square waves to create audible emotional chirps during state changes.

1kΩ & 2kΩ Resistors Signal Conditioning

Arranged as a structural inline voltage divider configuration. It scales down the 5V Echo output of the sensor down to a safe 3.3V logic line level, preparing the hardware mapping for the future ESP32 controller migration.

Logic Configuration & Wiring

Module Component Microcontroller Pin Voltage Bus
OLED SDA PinHardware SDA (A4)3.3V Power Rail
OLED SCL PinHardware SCL (A5)3.3V Power Rail
HC-SR04 TRIG PinDigital Pin D95.0V Power Rail
HC-SR04 ECHO PinDigital Pin D10 (via Divider)5.0V Power Rail
Passive Buzzer LineDigital Pin D85.0V Power Rail

Behavior Architecture


Normal State: Runs clean round eyes with nested white specular spots, triggering automatic blinks natively inside the CSS timeline loop.


Excited State: Occurs when the HC-SR04 sensor registers an object under 20cm. Displays maximized eye scales with a vibrating jitter animation, simulating rapid hardware recognition events.


Happy & Sleepy States: Progressive idle states calculated after 7 seconds and 10 seconds of sensor inactivity. Screen shifts to curved eyes or small sleepy frames while emitting calm multi-tone frequency feedback.

Firmware Subsystem

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define TRIG_PIN 9
#define ECHO_PIN 10
#define BUZZER_PIN 8

unsigned long lastBlink   = 0;
unsigned long lastIdle    = 0;
unsigned long blinkInterval = 3000;
bool isExcited = false;
bool isBlinked = false;

// ─────────────────────────────────────────
// DISTANCE
// ─────────────────────────────────────────
long getDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  long duration = pulseIn(ECHO_PIN, HIGH, 20000);
  return duration * 0.034 / 2;
}

// ─────────────────────────────────────────
// BLINK HANDLER
// runs independently, call after every face draw
// ─────────────────────────────────────────
void handleBlink(void (*faceFn)()) {
  unsigned long now = millis();
  if (!isBlinked && now - lastBlink > blinkInterval) {
    // draw closed eyes with same mouth style
    display.clearDisplay();
    // cute closed eyes — curved lines
    display.drawLine(18, 28, 28, 24, SSD1306_WHITE);
    display.drawLine(28, 24, 38, 28, SSD1306_WHITE);
    display.drawLine(82, 28, 92, 24, SSD1306_WHITE);
    display.drawLine(92, 24, 102, 28, SSD1306_WHITE);
    // keep mouth
    display.drawFastHLine(44, 54, 40, SSD1306_WHITE);
    display.display();
    delay(120);
    isBlinked = true;
    lastBlink = now;
    blinkInterval = random(2000, 5000);
    faceFn(); // redraw face after blink
  } else {
    isBlinked = false;
  }
}

// ─────────────────────────────────────────
// MOUTH HELPERS
// ─────────────────────────────────────────
void drawNeutralMouth() {
  // cute small curved mouth
  display.drawPixel(54, 55, SSD1306_WHITE);
  display.drawPixel(55, 56, SSD1306_WHITE);
  display.drawFastHLine(56, 57, 16, SSD1306_WHITE);
  display.drawPixel(72, 56, SSD1306_WHITE);
  display.drawPixel(73, 55, SSD1306_WHITE);
}

void drawSmile() {
  // big cute smile
  display.drawPixel(44, 52, SSD1306_WHITE);
  display.drawPixel(45, 54, SSD1306_WHITE);
  display.drawPixel(46, 55, SSD1306_WHITE);
  display.drawFastHLine(47, 56, 34, SSD1306_WHITE);
  display.drawPixel(81, 55, SSD1306_WHITE);
  display.drawPixel(82, 54, SSD1306_WHITE);
  display.drawPixel(83, 52, SSD1306_WHITE);
}

void drawOpenMouth() {
  // cute open O mouth
  display.drawRoundRect(50, 50, 28, 13, 6, SSD1306_WHITE);
  display.fillRoundRect(51, 51, 26, 11, 5, SSD1306_BLACK);
  // cute tongue
  display.fillRoundRect(57, 57, 14, 5, 3, SSD1306_WHITE);
}

void drawFrown() {
  display.drawPixel(44, 57, SSD1306_WHITE);
  display.drawPixel(45, 56, SSD1306_WHITE);
  display.drawPixel(46, 55, SSD1306_WHITE);
  display.drawFastHLine(47, 54, 34, SSD1306_WHITE);
  display.drawPixel(81, 55, SSD1306_WHITE);
  display.drawPixel(82, 56, SSD1306_WHITE);
  display.drawPixel(83, 57, SSD1306_WHITE);
}

void drawSleepyMouth() {
  // tiny mouth slightly open
  display.drawFastHLine(52, 55, 24, SSD1306_WHITE);
  display.drawFastHLine(52, 57, 24, SSD1306_WHITE);
  display.drawFastVLine(52, 55, 2, SSD1306_WHITE);
  display.drawFastVLine(75, 55, 2, SSD1306_WHITE);
  // ZZZ bubbles
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(100, 18);
  display.print("z");
  display.setCursor(107, 11);
  display.print("z");
  display.setCursor(113, 5);
  display.print("z");
}

// ─────────────────────────────────────────
// FACES
// ─────────────────────────────────────────
void drawNormalFace() {
  display.clearDisplay();
  // cute round eyes with shine
  display.fillCircle(32, 28, 14, SSD1306_WHITE);
  display.fillCircle(35, 26, 6, SSD1306_BLACK);
  display.fillCircle(30, 22, 3, SSD1306_WHITE); // shine
  display.fillCircle(96, 28, 14, SSD1306_WHITE);
  display.fillCircle(99, 26, 6, SSD1306_BLACK);
  display.fillCircle(94, 22, 3, SSD1306_WHITE); // shine
  drawNeutralMouth();
  display.display();
}

void drawExcitedFace() {
  display.clearDisplay();
  // big sparkly eyes
  display.fillCircle(32, 26, 18, SSD1306_WHITE);
  display.fillCircle(36, 23, 7, SSD1306_BLACK);
  display.fillCircle(28, 19, 4, SSD1306_WHITE); // big shine
  display.fillCircle(38, 30, 2, SSD1306_WHITE); // small shine
  display.fillCircle(96, 26, 18, SSD1306_WHITE);
  display.fillCircle(100, 23, 7, SSD1306_BLACK);
  display.fillCircle(92, 19, 4, SSD1306_WHITE);
  display.fillCircle(102, 30, 2, SSD1306_WHITE);
  // rosy cheeks
  display.drawCircle(14, 38, 5, SSD1306_WHITE);
  display.drawCircle(15, 38, 5, SSD1306_WHITE);
  display.drawCircle(113, 38, 5, SSD1306_WHITE);
  display.drawCircle(114, 38, 5, SSD1306_WHITE);
  drawOpenMouth();
  display.display();
}

void drawHappyFace() {
  display.clearDisplay();
  // happy squint eyes
  display.fillRoundRect(16, 22, 32, 14, 7, SSD1306_WHITE);
  display.fillRect(16, 22, 32, 7, SSD1306_BLACK);
  display.fillRoundRect(80, 22, 32, 14, 7, SSD1306_WHITE);
  display.fillRect(80, 22, 32, 7, SSD1306_BLACK);
  // rosy cheeks
  display.drawCircle(14, 40, 5, SSD1306_WHITE);
  display.drawCircle(15, 40, 5, SSD1306_WHITE);
  display.drawCircle(113, 40, 5, SSD1306_WHITE);
  display.drawCircle(114, 40, 5, SSD1306_WHITE);
  // sparkles
  display.drawPixel(6, 20, SSD1306_WHITE);

System Scaling Roadmap

[01]
ESP32 Architecture Migration

Transition tracking operations to a high-speed dual-core controller to implement integrated multi-threaded scheduling loops and hardware processing capabilities.

[02]
Dual-Axis Pan & Tilt Hardware Linkages

Incorporate small PWM micro servo brackets to map physical face tracking movements matching external distance data coordinates.

[03]
Full-Color SPI TFT Panel Integration

Upgrade from 1-bit monochrome constraints to a vibrant modern display window, opening up complex alpha channels and rich digital animations.

[04]
Wireless Web Panel Control Deck

Initialize localized async network servers on the chip to construct immediate wireless control dashboard interfaces accessible via desktop IP paths.