Spark - An AI Emotional Companion Robot on Arduino UNO Q

Sep 25, 2026 • 12 min read

Meet Spark, a desk-sized AI emotional companion robot on Arduino UNO Q that sees, hears, feels touch, and expresses emotions with OLED eyes and servo ears.

Project Spark — AI companion robot built with Arduino UNO Q

Meet Spark — a small desk robot that acts like a pet. Pet its head and its ears droop. Pick it up and it notices. Say “Hey Spark” and it listens, thinks, and talks back — with blinking OLED eyes, a little mouth that moves when it speaks, and a camera so it can see who is in the room.

In short: Spark is not a chatbot in a box. It has a body (sensors, eyes, ears) and a brain (AI that controls that body and even your smart home). Fast touch-and-feel reactions run locally with no internet, while smart conversation runs through an LLM.

Original project links:

What is Spark?

Think of Spark as a pet for your desk:

  • Ears that move — two small servos perk the ears up or let them droop, just like a cat or dog.
  • Eyes that show feelings — two OLED screens animate happy, sad, angry, surprised, sleepy, and awake. They blink, glance around, and follow you a little.
  • A mouth that “speaks” — a tiny OLED shows a waveform when Spark is talking, so you can see it speaking.
  • A head you can pet — six touch sensors under the shell detect where you petted and how — a single stroke, repeated pets, or a long hold.
  • A sense of being handled — a motion sensor inside knows if Spark is picked up, tilted, bumped, shaken, or dropped.
  • Ears that listen — listens for “Hey Spark” and then listens to your question.
  • Eyes that see — a phone camera over Wi-Fi lets Spark spot faces and look toward you.
  • A brain that thinks — an AI assistant that can change Spark’s emotion, control smart-home devices, or take a photo to answer “what do you see?”

Instead of voice > AI > voice, Spark does:

human > sensors > AI > decision > physical reaction

That loop — Sense → Understand → Decide → Express — is what makes it feel alive.

Spark robot 4 views on desk - OLED eyes and SPARK body

Note: because of a technical issue, the mouth OLED was not working at demo time. The eyes, touch, IMU, ears, and AI gateway were working.

What can Spark do?

CapabilityHow it worksStatus
Express emotionAnimated OLED eyes + ear positions + mouth animation. Emotions: neutral, happy, sad, angry, surprised, sleepy, wake/sleepWorking
Feel touch6-zone capacitive grid (TTP223) — single, repeated, long-hold pet patternsWorking
Sense handlingIMU (MPU-6500) detects pickup, put-down, tilt, bump, shake, drop, startleWorking
Hear “Hey Spark”Wake-word brick → POST /wake → native audio/wake_listener.pyExperimental — bring-up validated, mic not fully tested
See peopleFace-detection brick fed by phone camera over Wi-Fi (CCTV Cam App)Experimental — bring-up validated
Think and actLLM orchestrator with tools: set_emotion, Home Assistant, camera snapshot, multi-key failoverWorking
Talk backSpeech-to-text + text-to-speech (scripts/audio/: Groq / whisper.cpp STT + Piper TTS)Built — end-to-end wake → reply wiring is next

Why I built Spark

I use AI assistants every day, but almost always through a screen, speaker, or cloud website. That made me ask:

What would an AI assistant feel like if it had a physical body? And who should own it?

Cloud AI is powerful because you don’t need expensive hardware. But it also creates dependence on one provider’s models, pricing, and servers.

So I set a rule for Spark early:

The robot should belong to the user, not to a particular AI service.

That means the owner can swap the AI model, speech system, and tools without rebuilding the robot. Use a local LLM via Ollama / LM Studio for privacy, or a cloud model via OpenRouter when you need more smarts. Same for STT/TTS.

Spark is my way to explore Physical AI — where AI senses the physical world, makes decisions, and expresses them through a body.

How Spark works: brain and body

The most important design choice was splitting the system into two layers. The Arduino UNO Q is perfect for this because it has two processors on one board:

1. The Linux side — Spark’s “brain” (MPU)

A Qualcomm QCM2290 running Linux + Python. It handles everything that likes a full OS:

  • Wake-word detection (“Hey Spark”)
  • Speech-to-text (STT)
  • LLM reasoning + tool calling
  • Text-to-speech (TTS)
  • Computer vision + face presence
  • High-level robot behavior
  • Home Assistant and other integrations

The AI layer is modular. The LLM gateway can route to different providers, automatically fails over to another API key on error, and exposes tools like set_emotion, home_assistant, camera snapshot, and an opt-in http_request tool.

2. The STM32 side — Spark’s “body” (MCU)

An STM32U585 microcontroller for predictable, real-time control:

  • 2x 1.3" OLED eyes (SSD1106/SH1106, I2C, U8g2, addresses 0x3C & 0x3D)
  • 0.91" OLED mouth waveform
  • 6x TTP223 touch sensors + pet-pattern detection
  • 2x SG92R ear servos (direct-drive)
  • MPU-6500 IMU for pickup/tilt/bump/shake/drop
  • LDR on A0 for auto OLED brightness (mcu/ambient/)
  • PAM8403 audio amp + MAX9814 mic via USB sound card

The two sides talk over MessagePack RPC (Bridge RPC). The Linux side decides what Spark wants to do, the MCU makes the body do it reliably. The MCU also sends events up like TOUCH_EVENT or IMU_EVENT using the @EVT1| format.

Simple mental model:

"Hey Spark" → Brain (main.py) → RPC → MCU (eyes/ears/touch/IMU)
              Brain → STT/TTS
              Brain → LLM Gateway (tools)
              Brain → Vision loop (camera)

I also used Arduino App Lab for the camera + perception layer, and trained a custom Edge Impulse keyword-spotting model for “Hey Spark” so it feels natural — no button needed.

Spark software architecture - MPU Linux Python to MCU STM32 Bridge RPC

Making Spark expressive

A big part of the work was making Spark feel less like a box of electronics.

Spark demo animation - expressive OLED eyes and ear movement

The emotion system has a central state. An AI reply, a touch, or an IMU event can request happy, sad, angry, etc., and that one state drives eyes + ears + mouth together consistently.

For example:

  • Pet head gently → eyes happy + ears perk
  • Long hold → eyes sleepy + ears droop
  • Pick up suddenly → startle → eyes surprised + ears up
  • AI says something friendly → set_emotion(happy) tool call

The eyes blink, glance, and do a small gaze-follow. The ears add the physical “pet-like” cue that a screen alone can’t give.

Hardware at a glance (BOM)

PartWhat it isNotes
BoardArduino UNO Q 2GB — Qualcomm MPU + STM32 MCUTwo brains on one board
Eyes1.3" OLED x2, 128x64, I2CU8g2 driver, 0x3C & 0x3D
Mouth0.91" OLED 128x32Waveform visualizer
Touch6x TTP223 capacitiveHead-top PCB carrier
MotionMPU-6500 IMUPickup, tilt, bump, shake, drop
Ears2x TowerPro SG92R 180° servosDirect-drive rotation
CameraOld Android phone as IP camera (CCTV Cam App) over Wi-FiFace detection + AI snapshots
AudioElectret mic (MAX9814) + 50mm woofer + PAM8403 amp via USB sound cardWake + speech
LightLDR on A0Auto-adjusts OLED brightness
PowerCustom dual-charger + boost power board + discrete MT3608 boost4x custom PCBs total

Custom PCBs in the repo (PCB/ — KiCad + Gerbers in GitLab, schematics in resources/schematic/):

  • heade-pcb/ — head electronics carrier (eyes, mouth, LDR)
  • head-top-pcb/ — 6x TTP223 touch grid carrier
  • amp_imu_pcb/ — audio amp + MAX9814 mic + IMU carrier
  • spark_power_board/ + mt3608_boost_converter/ — power

Don’t want to fab PCBs? You can build the same circuit on perfboard — the circuit is simple. See the schematic PDFs in the repo.

Spark head parts - 1.3 inch OLED eyes and 0.91 inch mouth OLED with head PCB

3D models are in Blender/ — body, ears, assembly, plus module models for the OLEDs and SG92R servos.

Software structure (from GitLab)

ProjectSpark/
├── Blender/               # 3D models (body, ears, assembly)
├── ki-cad-library/        # KiCad OLED symbols + footprints
├── PCB/                   # 5 KiCad boards (see above)
├── mcu/                   # STM32 firmware
│   ├── eyes/              # OLED eyes (eyes.ino + src/ + README)
│   ├── touch/             # TTP223 grid + pet patterns
│   ├── mouth/             # 0.91" mouth waveform
│   ├── ears/              # 2x SG92R servos
│   ├── imu/               # MPU-6500 events
│   └── robot/             # Main firmware: all modules + Bridge RPC
├── app-lab/projectspark/  # Experimental wake-word + face bricks
├── resources/images/ + schematic/
└── scripts/
    ├── main.py            # Brain/gateway orchestration
    ├── audio/             # wake_listener, VAD recorder, STT, TTS
    ├── vision/camera.py   # CCTVCam gateway
    ├── mcu_client.py      # Bridge RPC client + @EVT1| parser
    └── llm-gateway/       # Multi-provider LLM orchestrator
        ├── orchestrator.py, client.py, conversation.py
        └── tools/: emotion.py, home_assistant.py, curl.py, registry.py

Key ideas:

  • Multi-key failover — add 3+ API keys, it switches automatically on timeout.
  • Plugin tools — each tool is one file. Easy to add your own.
  • Per-tool switches in .env (TOOL_*_ENABLED).
  • Test mode + REPL — run the brain with fake hardware: python main.py --test "hi" or python main.py for interactive chat.

See scripts/README.md, scripts/audio/README.md, scripts/vision/README.md, and mcu/<module>/README.md in GitLab for full docs.

Building Spark on a ₹10,000 budget

I limited myself to about ₹10,000. I couldn’t buy a fancy 3D-printed body.

The quote for a 3D printed body was too high, so I reused what I had and built the current body from a reshaped old PVC pipe. Not perfect-looking, but it let me spend money where it mattered for the demo: UNO Q, sensors, displays, audio, and servos.

The result is deliberately a maker prototype, not a commercial product — and that’s the point. Spark shows what Physical AI can do with limited resources.

Spark home-etched PCBs - KiCad Project Spark boards etched to save budget

Challenges and lessons learned

  1. Hardware integration is harder than modules. Each part worked alone. Together, displays + touch + audio + IMU + servos + USB sound + Wi-Fi camera needed a lot of debugging, especially USB/audio on Linux.

  2. Two computers = one boundary to design carefully. MPU + MCU is powerful, but every interface is a possible failure point. I learned: modularity is good, but keep the RPC simple. Beginner traps I hit on UNO Q: never use while(!Serial) in SBC mode (hangs with no USB host), App code can’t use Serial1 (router owns it — use Monitor.println() on TCP 7500), and $/serial/open notifications don’t forward — use --tcp mode for tests.

  3. Budget forces choices. I couldn’t buy my way out of problems. Enclosure, cable management, and extra sensors had to be balanced. Several ideas were postponed to get the core loop working: See / Hear > Understand > Respond > Express.

  4. Scope management. The biggest lesson was learning when not to build. Each extra subsystem adds dev time and demo risk. I prioritized the core interaction loop first.

How to reproduce / try it yourself

Full code, Gerbers, and Blender files: GitLab repo .

Path A — Try Spark’s brain with no hardware (~5 min)

git clone https://gitlab.com/mayur-454/project-spark.git
cd ProjectSpark/scripts/llm-gateway
cp .env.example .env
# edit .env: set LLM_API_KEYS / LLM_BASE_URL / LLM_MODEL
pip install -r requirements.txt
python main.py --test "hi"

You should see a reply + simulated set_emotion(...) call. Then try python main.py for REPL (/reset, /raw).

Path B — Try the robot body (needs Arduino UNO Q)

# Test eyes first — most visual
arduino-cli compile -b arduino:zephyr:unoq mcu/eyes/
arduino-cli upload -b arduino:zephyr:unoq mcu/eyes/

# Full robot once modules work
arduino-cli compile -b arduino:zephyr:unoq mcu/robot/
arduino-cli upload -b arduino:zephyr:unoq mcu/robot/

Then on the board over SSH:

cd scripts/tests/mcu
pip install msgpack
python test_emotion.py happy
python test_emotion.py gaze left
python test_emotion.py demo
python test_imu.py --tcp

After flashing mcu/robot/, eyes + mouth start even without Python — that’s normal.

Path C — Voice + camera

cd scripts/audio
cp .env.example .env
pip install -r requirements.txt
python -m audio.wake_listener  # :8123, POST /wake to trigger
python -m audio.stt --check
python -m audio.tts --check

Camera is in scripts/vision/ (CCTVCam phone app on same Wi-Fi). See scripts/vision/README.md.

Path D — App Lab wake + face (experimental)

app-lab/projectspark/ runs keyword-spotting + face detection together. Change the phone IP and model path in .env, import into Arduino App Lab. You can use the default “Hey Arduino!” model if my custom “Hey Spark” Edge Impulse model isn’t public yet. Skip unless you need hands-free wake.

PCB + assembly

Spark head internal wiring - SG92R ear servos and TTP223 touch PCB assembly

  1. Fab the 4 PCBs from Gerbers in GitLab, or etch at home (I did print-and-etch) or use perfboard.
  2. Assemble head PCBs, amp/IMU/mic PCB, and power board.
  3. Flash STM32, start App Lab app, then run python3 main.py (or create a service to auto-start it).
  4. Build the enclosure — 3D print from Blender/ files or hand-make like my PVC-pipe body. Use an old phone for the camera or add a camera module — your choice.

What I accomplished

The final prototype is a complete Physical AI architecture, not just one AI trick:

Arduino UNO Q + Linux AI + speech + vision + LLM tools + TTS + eyes + ears + touch + motion + audio.

Because it’s modular:

  • New AI model ≠ rebuild robot
  • New tool ≠ rewrite personality
  • New sensor = add to physical layer

That extensibility is the most important outcome. Spark can already do Home Assistant. The same tool pattern could add smart-home control, personal automations, local info access, other robots/IoT, more sensors — as tools for the AI, not hard-coded behaviors.

Future improvements

  • Cleaner, more durable enclosure + better cable management
  • More expressive eye/ear animations + reliable touch behaviors
  • Bigger tool ecosystem (more Home Assistant + local tools)
  • More local AI, less cloud dependence where practical
  • Web-UI for history and analytics

All incremental — the modular base already exists.

FAQ

Is Spark a finished product? No. It’s an actively developed prototype. Software/hardware may change. Use the GitLab main commit referenced in the Hackster guide as the reproduction version.

How much did it cost? About ₹10,000 in parts, reusing materials and a PVC-pipe body to stay in budget.

Can I build it without custom PCBs? Yes. Use perfboard and the schematic PDFs. Custom PCBs just make it neater.

Do I need internet? Touch, eyes, ears, and IMU reactions run locally on the MCU with no internet. Conversation needs an LLM — local (Ollama/LM Studio) or cloud (OpenRouter etc.).

What board do I need? Arduino UNO Q (I used the 2GB version). The split MPU (Qualcomm Linux) + MCU (STM32) is core to the design.

Final thoughts

Spark started with a simple question: What would an AI assistant feel like if it had a physical body, and could its owner actually control it?

The answer is a budget-conscious, modular prototype that proves AI doesn’t have to live behind a screen or be locked to one cloud. It senses, reacts, expresses itself physically, and stays open enough to keep evolving.

If you build it, remix it, or improve the eyes/ears/touch — I’d love to hear about it. Start from the GitLab repo and the full Hackster.io build log .