# Eye Mechanism Control (Arduino Mega + Voice Conversation)

This project is a simplified port of Will Cogley's animatronic eye mechanism control code for **Arduino Mega**. It focuses purely on realistic eye animations, including looking around and eyelids that automatically track the pupil's vertical movement.

## Features
- **Auto Animation**: Eyes look around randomly with smooth movements.
- **Eyelid Tracking**: Eyelids automatically track the vertical position of the eye.
- **Random Blinking**: Realistic blinking behavior.
- **Synchronized Jaw Animation**: Jaw opens and closes randomly (like breathing or mumbling) while maintaining perfect sync between left/right servos.
- **Expressive Eyebrows**: Four independent servos control the eyebrows to create expressions like surprise, suspicion, and neutral states.
- **Serial Jaw Control**: Host app can switch to talk mode and drive jaw openness in real time.
- **Push-To-Talk Desktop UI**: Hold the space bar to record, release to transcribe/respond/speak.
- **Simplified Hardware**: No external switches, potentiometers, or buttons required. Just power and servos.

## Hardware Requirements
- 1x Arduino Mega 2560
- 12x Micro Servos (SG90 or similar)
  - 6 for Eyes
  - 2 for Jaw
  - 4 for Eyebrows
- External 5V Power Supply (REQUIRED for 12 servos)

## Hardware & Wiring

### Pin Mapping Table

| Component | Function | Pin | Range | Notes |
|-----------|----------|-----|-------|-------|
| **Servo 1** | Left/Right (LR) | **D22** | 60-120° | Eyes |
| **Servo 2** | Up/Down (UD) | **D23** | 60-120° | Eyes |
| **Servo 3** | Top Left Lid (TL) | **D24** | 110-40° | Eyelids |
| **Servo 4** | Bottom Left Lid (BL)| **D25** | 70-130° | Eyelids |
| **Servo 5** | Top Right Lid (TR) | **D26** | 50-140° | Eyelids |
| **Servo 6** | Bottom Right Lid (BR)| **D27** | 120-70° | Eyelids |
| **Servo 7** | Jaw Left | **D28** | 0-15° | Jaw |
| **Servo 8** | Jaw Right | **D29** | 180-165° | Jaw |
| **Servo 9** | Brow Left-Left (LL) | **D30** | 42-7° | Outer Left |
| **Servo 10**| Brow Left-Right (LR) | **D31** | 35-70° | Inner Left |
| **Servo 11**| Brow Right-Right (RR)| **D32** | 137-172°| Outer Right |
| **Servo 12**| Brow Right-Left (RL) | **D33** | 36-1° | Inner Right |

### Wiring Diagram (ASCII)

```text
       Arduino Mega 2560
      +------------+
      |            |
      |        D22 |----> [Servo LR Signal]
      |        D23 |----> [Servo UD Signal]
      |        D24 |----> [Servo TL Signal]
      |        D25 |----> [Servo BL Signal]
      |        D26 |----> [Servo TR Signal]
      |        D27 |----> [Servo BR Signal]
      |        D28 |----> [Servo Jaw L Signal]
      |        D29 |----> [Servo Jaw R Signal]
      |        D30 |----> [Servo Brow LL Signal]
      |        D31 |----> [Servo Brow LR Signal]
      |        D32 |----> [Servo Brow RR Signal]
      |        D33 |----> [Servo Brow RL Signal]
      |            |
      |        5V  |----> To ALL Servos (VCC) - FROM EXTERNAL PSU
      |        GND |----> To ALL Servos (GND) & External PSU GND
      |            |
      +------------+

POWER NOTE: 
Connect all Servo VCC pins to an external 5V power supply.
Connect all Servo GND pins to the external power supply AND the Arduino Mega's GND.
DO NOT power 12 servos directly from the Arduino 5V pin!
```

### Servo Limits (Safety Guardrails)
Defined ranges to ensure structural integrity:
- **LR (Left/Right)**: 60° to 120°
- **UD (Up/Down)**: 60° to 120°
- **TL (Top Left Lid)**: 110° (Closed) to 40° (Open)
- **BL (Bottom Left Lid)**: 70° (Closed) to 130° (Open)
- **TR (Top Right Lid)**: 50° (Closed) to 140° (Open)
- **BR (Bottom Right Lid)**: 120° (Closed) to 70° (Open)
- **Jaw Left**: 0° (Closed) to 15° (Open)
- **Jaw Right**: 180° (Closed) to 165° (Open)
- **Brow LL**: 42° (Bottom) to 7° (Top)
- **Brow LR**: 35° (Bottom) to 70° (Top)
- **Brow RR**: 137° (Bottom) to 172° (Top)
- **Brow RL**: 36° (Bottom) to 1° (Top)

## Setup & Upload

1. **Install Libraries**: This sketch uses the standard `Servo` library included with the Arduino IDE/Embedr.
2. **Select Board**: Choose `Arduino Mega or Mega 2560` from the board selector.
3. **Compile & Upload**: Click the upload button.

## Usage

1. **Power Up**: Connect the external power supply for the servos and plug in the Arduino Mega via USB.
2. **Run**: The system will immediately begin the random animation loop:
   - Eyes move and blink randomly.
   - Jaw occasionally moves (breathing/mumbling).
   - Eyebrows change expressions randomly (Neutral, Surprise, Suspicious, etc.).

## Quick Return (Launch GUI Fast)

When you come back to this project later, use this exact sequence:

```bash
cd /Users/rishabhsinha/EmbedrProjects/eye_mechanism_control

# Optional: stop any old app instance
pkill -f "voice_head_assistant.py" || true

# Launch GUI (recommended runtime on this machine)
OPENROUTER_MODEL="google/gemini-2.5-flash-lite" /opt/homebrew/bin/python3.11 voice_head_assistant.py
```

If you are using the project virtual environment instead:

```bash
cd /Users/rishabhsinha/EmbedrProjects/eye_mechanism_control
source .venv/bin/activate
python3 voice_head_assistant.py
```

## Voice Conversation Mode (Python)

This repo now includes a Python app: `voice_head_assistant.py`

Behavior:
- Hold `SPACE` to record microphone audio.
- Release `SPACE` to stop recording.
- Select the TTS voice from the GUI dropdown (`Voice`) before speaking.
- Use `Preset Lines` buttons to play pre-generated demo lines with synchronized jaw animation.
- Audio is sent to Sarvam STT.
- Transcript is sent to OpenRouter (`google/gemini-2.5-flash-lite`) for a reply.
- Reply is sent to Sarvam TTS.
- While audio is played, jaw commands are streamed to Arduino so the head appears to speak.

### 1) Install Python dependencies

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

### 2) Configure environment variables

```bash
export SARVAM_API_KEY=\"your_sarvam_key\"
export OPENROUTER_API_KEY=\"your_openrouter_key\"

# Optional overrides:
export OPENROUTER_MODEL=\"google/gemini-2.5-flash-lite\"
export ARDUINO_BAUD=\"9600\"
export SARVAM_STT_MODEL=\"saaras:v3\"
export SARVAM_TTS_MODEL=\"bulbul:v2\"
export SARVAM_TTS_SPEAKER=\"abhilash\"  # Default male voice
export SARVAM_TTS_LOUDNESS=\"1.5\"
export AUDIO_OUTPUT_GAIN=\"1.7\"
export AUDIO_OUTPUT_DEVICE=\"AirPods\"  # Optional: device index or case-insensitive name match
export PREFER_BLUETOOTH_OUTPUT=\"1\"    # Auto-pick Bluetooth output when available
```

### 3) Run app

Auto-detect Arduino serial port:

```bash
python3 voice_head_assistant.py
```

Specify a serial port manually:

```bash
python3 voice_head_assistant.py --port /dev/tty.usbmodemXXXX
```

Run without Arduino (voice pipeline only):

```bash
python3 voice_head_assistant.py --no-serial
```

## Arduino Serial Commands

The sketch now listens on `9600` baud:

- `MODE TALK` -> enables host-driven jaw mode (jaw follows audio while brows/eyes remain expressive).
- `MODE WAIT` -> waiting/listening animation (mostly eyebrows).
- `MODE IDLE` -> idle animation (mostly blinks).
- `MODE AUTO` -> alias for `MODE IDLE`.
- `JAW <0-100>` -> sets jaw openness percentage.
- `PING` -> returns `PONG`.

Notes:
- In `MODE TALK`, if jaw updates stop for ~350 ms, jaw automatically closes for safety.
- Eyes/blinks/brows continue animating while jaw is externally controlled.

## Documentation Used

- Sarvam STT/TTS docs: [docs.sarvam.ai](https://docs.sarvam.ai/)
- Sarvam STT endpoint: [Speech To Text](https://docs.sarvam.ai/api-reference-docs/speech-to-text)
- Sarvam TTS endpoint: [Text To Speech](https://docs.sarvam.ai/api-reference-docs/text-to-speech/convert)
- OpenRouter chat completions: [API Overview](https://openrouter.ai/docs/api-reference/overview)
- OpenRouter model page: [google/gemini-2.5-flash-lite](https://openrouter.ai/google/gemini-2.5-flash-lite)
- pySerial docs: [pyserial.readthedocs.io](https://pyserial.readthedocs.io/en/latest/pyserial_api.html)
