βββββββββββ ββββββββββ
βββββββββββ βββββββββββ
ββββββ βββ βββββββββββ
ββββββ ββββ ββββββββββββ
ββββββββ βββββββ βββ βββ
ββββββββ βββββ βββ βββ
EVA V2 (Zen Companion) is an autonomous, emotionally expressive desktop companion robot powered by the ESP32 DevKit. Built around an EMO-style continuous internal drive engine, EVA reacts organically to human touch, distance, time of day, and environmental stimuli using animated OLED eyes, procedural body movement, RGB mood lighting, and chiptune sound effects.
- π€ Project Vision & Design Philosophy
- β¨ Core Capabilities & Personality Engine
- 𧬠Software Architecture & Control Pipeline
- π Hardware Specification & Circuit Diagram
- π± Android Companion App (APK)
- βοΈ Configuration, Customization & Build Guide
- π€ Open Source, License & Usage Guidelines
- π Credits & Acknowledgments
- β FAQ & Troubleshooting
Most DIY desktop robots operate like basic obstacle-avoiding cars: a sensor reads a distance, triggers an if condition, executes a motor spin, and repeats. They feel mechanical and lifeless.
EVA was engineered around a single strict design rule:
Sensors do not directly trigger motors or display outputs. Sensors feed information into an Interpretation Layer, which updates an internal Continuous Lifecycle Engine. The Behaviour Engine evaluates EVA's internal energy, social need, and environmental state to decide an action, while the Emotion Engine determines how EVA feels. Outputs (eyes, buzzer tone, RGB light, chassis movement) simply express that internal state.
flowchart LR
subgraph SENSORS ["1. Physical Sensors"]
ToF["VL53L0X Distance"]
Touch["Capacitive Touch Plate"]
end
subgraph INTERPRETATION ["2. Signal Processing"]
ToF_Proc["Proportional Dist / Edge"]
Touch_Proc["Tap / Double Tap / Pet"]
end
subgraph CNS ["3. Central Nervous System"]
Lifecycle["LifecycleEngine\n(Energy & Drives)"]
Behaviour["BehaviourEngine\n(Decision State Machine)"]
Emotion["EmotionEngine\n(Baseline & Decay)"]
end
subgraph OUTPUTS ["4. Physical Expressivity"]
Eyes["RoboEyes OLED Lids"]
Motors["DRV8833 Chassis Motion"]
Light["WS2812 NeoPixel Pulse"]
Sound["Passive Buzzer Tones"]
end
SENSORS --> INTERPRETATION
INTERPRETATION --> Lifecycle
Lifecycle --> Behaviour
Behaviour --> Emotion
Behaviour --> Motors
Emotion --> Eyes
Emotion --> Light
Emotion --> Sound
EVA V2 consolidates eye expressions into 8 distinct, instantly recognizable eye personalities. Each personality dynamically re-configures FluxGarage RoboEyes parameters (lids height, autoblinker frequency, idle look-around speed, curiosity asymmetry, sweat, and horizontal flicker):
| Emotion | Lids / Mood | Autoblinker Rate | Look-Around | RGB Light | Audio Feedback |
|---|---|---|---|---|---|
EVA_NEUTRAL |
DEFAULT (calm, steady) |
~4s Β± 2s | Medium (3s) | Solid Calm Blue | Silence |
EVA_HAPPY |
HAPPY (warm curved) |
~5s Β± 2s | Soft (3s) | Solid Amber | Rising Chirp Up |
EVA_EXCITED |
HAPPY + Curiosity ON |
Fast (~2s) | Rapid (1s) | Gold Fast Pulse | Excitation Chiptune |
EVA_CURIOUS |
DEFAULT + Asymmetric |
Slow (~6s) | Focused (2s) | Cyan Pulse | Curious "Hmm?" Chirp |
EVA_SCARED |
TIRED (Wide Open) + Sweat/Flicker |
Rapid (1s) | Frozen (OFF) | Sharp Red Pulse | Flinch Sequence |
EVA_BORED |
TIRED (Heavy Droopy Lids) |
Very Slow (~9s) | Lazy (6s) | Dim Blue Fade | Silent Blip |
EVA_SLEEPY |
TIRED (Half-closed drooping) |
Slowest (~12s) | Frozen (OFF) | Slow Purple Breath | Yawn Sound |
EVA_AFFECTIONATE |
HAPPY + Soft squint |
Soft (~6s) | Gentle (5s) | Soft Pink Pulse | Purring Sequence |
When EVA remains stationary or is triggered via remote command, non-blocking bitmap animations replace the eye interface:
- π¦ Dino Jump Mini-Game (
ANIM_DINO): An interactive 25 FPS side-scrolling dinosaur jump game. EVA automatically jumps cacti in idle mode, or the user can manually play via the companion app'sJUMPbutton! - ποΈ Workout Pullups (
ANIM_PULLUPS): Animated stick-figure doing gym pullups. - π΅ Music Party (
ANIM_MUSIC): Dynamic equalizer bars dancing to rhythmic music beats. - βοΈ Snowfall (
ANIM_SNOW): Procedural particle snowfall animation across the OLED display. - π Car Cruise (
ANIM_CAR): Side-scrolling retro car driving animation.
EVA operates on an energy cycle managed by LifecycleEngine.h. Rather than relying on rigid static timers, EVA's mood and desire to sleep evolve according to energy depletion and interaction boosts:
βββββββββββββ Energy > 0.85 βββββββββββββ
β WAKING β ββββββββββββββββββββββββ> β ACTIVE β
β (Groggy) β β(Energetic)β
βββββββββββββ βββββββ¬ββββββ
β² β Energy < 0.60
β βΌ
βββββββββββββ βββββββββββββ
β SLEEPING β β CONTENT β
β (Resting) β β (Calm) β
βββββββ²ββββββ βββββββ¬ββββββ
β Energy < 0.15 β Energy < 0.35
β (Confirmed) βΌ
βββββββββββββ βββββββββββββ
β DROWSY β <ββββββββββββββββββββββββ β BORED β
β(Heavy Eye)β Energy < 0.25 β(Lazy Glum)β
βββββββββββββ βββββββββββββ
- Energy Decay: Energy drains continuously while awake (
ENERGY_DECAY_RATE_PER_S = 0.00150f). - Interaction Boost: Tapping grants
+0.06energy; sustained petting grants+0.13energy. - Sleep Threshold: When energy drops below
0.15f, EVA begins winding down and transitions toMODE_SLEEP.
In EVA V2, movement is driven by the VL53L0X Time-of-Flight distance sensor providing continuous raw millimeter distance (rawDistanceMm):
Distance > 500mm β Open Space β Energetic Wander (Full Speed)
300mm β 500mm β Approach Zone β Slow Curious Crawl (Curious Eyes)
150mm β 300mm β Curve Zone β Gentle Steering Curve
< 120mm β Obstacle Zone β Proportional Flinch & Turn
< 600mm Drop-Off β Edge Hazard β Immediate Backward Flinch + 180Β° Spin
- Memory tracking
consecutiveObstacles. - Alternating turn directions deterministically on each retry.
- Increasing turn duration by
+120msper consecutive retry. - Triggering a Trapped Escape Maneuver (600ms firm reverse + 180Β° spin) after 5 consecutive failed turn attempts.
MODE_EVA(Autonomous Companion Life): Full autonomous exploration, environmental awareness, emotional state transitions, and ToF proportional movement.MODE_PET(Resting / Touch-Only State): Motors are safely locked. EVA stays resting on your desk, responding only to touch and petting with sweet eyes and purring tones.MODE_CLOCK(Desktop Clock & Weather): OLED displays digital time, date, alarm status, and real-time weather fetched over Wi-Fi from Open-Meteo.MODE_SLEEP(Low-Power Sleep): Display turns off, motors lock, and energy recharges. Periodic clock peeks occur every 5 minutes.MODE_RC(Bluetooth Remote Control): Autonomous engine pauses; direct chassis manual driving and custom emotion/animation triggering are activated via Bluetooth.
| Component | Quantity | Model / Description | Notes |
|---|---|---|---|
| Microcontroller | 1 | ESP32 DevKit V1 / ESP32-WROOM-32 | 240MHz Dual-Core, Wi-Fi & Bluetooth SPP |
| Display | 1 | 0.96" I2C SSD1306 OLED (128Γ64) | Address 0x3C, I2C Bus |
| Distance Sensor | 1 | VL53L0X Time-of-Flight (ToF) Sensor | Address 0x29, Angled downward |
| Motor Driver | 1 | DRV8833 Dual H-Bridge Driver | 4 PWM Input Channels |
| Motors | 2 | N20 DC Geared Motors (6V 300RPM) | Open-loop speed control |
| Touch Sensor | 1 | Capacitive Copper Plate / Foil | ESP32 touchRead() on GPIO 4 |
| Mood Light | 1 | WS2812B NeoPixel RGB LED | Single/Short Strip on GPIO 27 |
| Audio Output | 1 | 5V Passive Piezo Buzzer | LEDC PWM driven on GPIO 14 (Channel 4) |
| Power Supply | 1 | 18650 Li-Ion Battery + 5V Boost Module | Dual power rail (3.3V Logic / 5V Motors) |
Centralized strictly inside src/Config.h:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AUTHORITATIVE ESP32 PINOUT MAP β
βββββββββββββββββββββ¬ββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ€
β Peripheral β GPIO Pin β Hardware Function / Channel β
βββββββββββββββββββββΌββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β I2C SDA β GPIO 21 β Shared Bus (OLED + VL53L0X ToF) β
β I2C SCL β GPIO 22 β Shared Bus (OLED + VL53L0X ToF) β
β Motor Left Fwd β GPIO 25 β DRV8833 IN1 (LEDC PWM Channel 0) β
β Motor Left Rev β GPIO 26 β DRV8833 IN2 (LEDC PWM Channel 1) β
β Motor Right Rev β GPIO 32 β DRV8833 IN3 (LEDC PWM Channel 2) β
β Motor Right Fwd β GPIO 33 β DRV8833 IN4 (LEDC PWM Channel 3) β
β Touch Plate β GPIO 4 β Touch0 (`touchRead()` Capacitive Input)β
β WS2812 NeoPixel β GPIO 27 β FastLED / NeoPixel Data Line DIN β
β Passive Buzzer β GPIO 14 β LEDC PWM Tone (LEDC Channel 4) β
β Expansion Servo β GPIO 13 β Optional SG90 Servo (Disabled) β
βββββββββββββββββββββ΄ββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ
- Pre-Compiled APK: Ready-to-install binary is available at
/apk/EVA-Companion.apk. - Source Code: Android Studio project files are located in
/android_app_src.
During early testing, remote control via a standard website was evaluated. However, we completely abandoned the web controller and moved to a native Android APK due to browser Bluetooth limitations:
- Protocol Mismatch (Classic BT SPP vs. Web Bluetooth BLE):
- ESP32's
BluetoothSerial.hlibrary runs Classic Bluetooth SPP (Serial Port Profile / RFCOMM00001101-0000-1000-8000-00805F9B34FB). - Mobile web browsers (Chrome, Safari, Edge) ONLY support Bluetooth Low Energy (BLE / GATT). Web browsers actively block raw Classic Bluetooth SPP socket connections.
- ESP32's
- The Native APK Solution:
- The Android app invokes Android's native
BluetoothAdapterandBluetoothSocketAPIs directly, guaranteeing zero-latency RFCOMM streaming and instant pairing.
- The Android app invokes Android's native
- Download APK: Download
EVA-Companion.apkfrom the/apkdirectory onto your Android device. - Pair Bluetooth: Power on EVA. Go to Android Settings β Bluetooth, scan for nearby devices, and pair with
EVA. - Allow Unknown Sources: Enable "Install Unknown Apps" in Android Security settings for your File Manager if prompted.
- Install APK: Tap
EVA-Companion.apkand select Install. - Launch & Connect: Open EVA Robot, grant Bluetooth permissions, and tap Connect.
All commands sent to CommsHub are string-based packets or single drive characters:
'F': Drive Forward |'B': Drive Backward |'L': Pivot Left |'R': Pivot Right'G': Curve Left |'I': Curve Right |'H': Slow Curve Reverse |'J': Slow Curve Forward'S': Stop Motors Immediately |'0'β'9': Set Motor PWM Speed (0=120, 9=255)
| Command String | Description | Example |
|---|---|---|
MODE <MODE> |
Switch operating mode | MODE EVA, MODE PET, MODE CLOCK, MODE SLEEP, MODE RC |
EMOTION <NAME> |
Trigger emotion profile | EMOTION HAPPY, EMOTION EXCITED, EMOTION SCARED |
TIME HH:MM |
Set manual clock time | TIME 14:30 |
DATE DD/MM/YYYY |
Set manual date | DATE 25/12/2026 |
ALARM HH:MM <ON/OFF> |
Set or disable daily alarm | ALARM 07:00 ON, ALARM OFF |
WIFI <SSID> <PASS> |
Save Wi-Fi configuration | WIFI MyHomeNetwork SecretPass123 |
V <0-255> |
Set buzzer volume | V 200 |
T <0-255> |
Set OLED display contrast/brightness | T 250 |
DANCE / TRICK |
Start procedural dance routine / wiggle trick | DANCE |
ANIM <DINO/WORKOUT/PARTY/SNOW/CAR> |
Trigger OLED takeover animation | ANIM DINO |
GAME <DINO/JUMP> |
Start Dino game / Impulse jump action | GAME DINO, GAME JUMP |
- IDE: Arduino IDE 2.x or VS Code with PlatformIO.
- Board Package: ESP32 Arduino Board Manager (
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json). - Target Board:
ESP32 Dev Module.
- Clone the repository:
git clone https://github.com/abhijithk-ak/EVA.git cd EVA - Create your local config file:
cp src/Config.example.h src/Config.h
- Open
src/EVA.inoin Arduino IDE. - Edit
src/Config.hto set your Wi-Fi credentials:#define WIFI_SSID "Your_WiFi_SSID" #define WIFI_PASSWORD "Your_WiFi_Password" #define WEATHER_LATITUDE "10.93" #define WEATHER_LONGITUDE "76.62" #define GMT_OFFSET_SEC 19800 // GMT+5:30 (India)
- Connect your ESP32 via USB and click Upload.
All robot behavior, energy decay rates, sensor sensitivities, motor speeds, and display/audio parameters are configured in src/Config.h:
ENERGY_DECAY_RATE_PER_S: Rate at which EVA's energy depletes per second (0.00150f). Increase (e.g.0.0050f) for faster sleep cycles, or decrease (e.g.0.0008f) for all-day active operation.ENERGY_SLEEP_THRESHOLD: Below this energy level (0.15f), EVA enters drowsy mode and prepares for sleep.ENERGY_WAKE_BOOST: Energy restored immediately upon waking from sleep (0.85f).CURIOSITY_RISE_RATE_PER_S: Rate at which EVA's desire to look around rises when standing still (0.008f).SOCIAL_RISE_RATE_PER_S: Rate at which EVA's desire for touch builds when alone (0.002f).
TOF_OBSTACLE_MM: Distance in mm (95) below which EVA detects an obstacle and triggers a startled flinch turn.TOF_EDGE_MM: Distance in mm (150) above which EVA detects a table edge drop-off and backs away.TOF_EDGE_CONFIRM_SAMPLES: Number of consecutive samples (3) required before confirming an edge event to prevent false drops.
PIN_TOUCH: ESP32 Touch pin (GPIO 4/ Touch0).TOUCH_TRIGGER_RATIO: Dynamic multiplier against baseline (0.78f). Lower (e.g.0.70f) reduces sensitivity; higher (e.g.0.85f) increases sensitivity.TOUCH_TRIGGER_DELTA: Threshold delta (200) required for tap classification.TOUCH_PET_MIN_MS/TOUCH_LONG_HOLD_MS: Petting duration (1100msβ5000ms) and sleep hold threshold (5000ms).
MOVE_DEFAULT_SPEED: Default cruising duty cycle (200out of 255).MOVE_TURN_SPEED: Pivot turn duty cycle (190out of 255).MOVE_FORWARD_MS/MOVE_TURN_MS: Timed move duration (700ms) and turn duration (450ms).
DISPLAY_BRIGHTNESS: SSD1306 OLED hardware contrast register (250out of 255).BUZZER_VOLUME: Passive buzzer LEDC PWM duty cycle cap (250out of 255).
Because sensor mounting angles and chassis dimensions vary, calibrate these values in src/Config.h:
- VL53L0X ToF Distance Calibration:
#define TOF_OBSTACLE_MM 95 // Reading < 95mm = obstacle ahead #define TOF_EDGE_MM 150 // Reading > 150mm (when angled down) = edge drop-off
- Capacitive Touch Sensitivity:
#define TOUCH_TRIGGER_RATIO 0.78f // Sensitivity multiplier against dynamic baseline #define TOUCH_TRIGGER_DELTA 200 // Raw threshold delta
EVA is shared under the MIT License with Non-Commercial Condition (see LICENSE):
- π’ Allowed: Free for personal, educational, research, and non-commercial maker projects. You are free to view, modify, build, and adapt the code and hardware for your own personal use.
- π€ Contributions: Community contributions (pull requests, bug fixes, custom eye animations, and 3D chassis designs) are warmly welcomed!
- π΄ Commercial Restriction: The software, hardware schematics, and derived works MAY NOT be sold, resold, leased, or incorporated into commercial products intended for sale without prior explicit written authorization from the copyright holder (Abhijith K).
- FluxGarage RoboEyes Library: Created by Dennis Lee (FluxGarage). The core eye rendering, autoblinking, and lid position algorithms are powered by the official FluxGarage RoboEyes library. Website: https://www.fluxgarage.com Β· GitHub: https://github.com/FluxGarage/RoboEyes.
- Open-Meteo API: Provides free, keyless weather forecast data for Clock Mode. Website: https://open-meteo.com.
- Adafruit Industries: For the
Adafruit_GFX,Adafruit_SSD1306, andAdafruit_VL53L0Xopen-source drivers. - Expressif Systems: For the ESP32 microcontroller architecture and
BluetoothSeriallibrary.
- Verify I2C wiring: SDA β GPIO 21, SCL β GPIO 22.
- Check I2C address in
src/Config.h(#define EVA_OLED_I2C_ADDR 0x3C). Run an I2C scanner sketch to verify if your panel uses0x3D.
- Ensure the VL53L0X is powered with 3.3V and shares the same SDA/SCL lines as the OLED.
- Check for solder bridges on the VIN/GND pins.
- DC motors draw high inrush currents. Power the DRV8833 driver directly from the 18650 battery / 5V rail, not from the ESP32 3.3V pin. Add a 100Β΅F electrolytic capacitor across the motor power rails.
- Pair the device "EVA" in your phone's Android System Settings under Bluetooth before launching the companion app APK.
Crafted with β€οΈ by Abhijith K and the EVA Open-Source Community.













