# Project export: MIRAI

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Teaching robots to see, listen, and move like us. MIRAI is an experimental human-robot interaction framework that enables natural motion and voice-based control of robots.
- Devpost: https://devpost.com/software/boxing-robot
- GitHub: https://github.com/A-Mundanilkunathil/Unitree-G1
- Video: https://www.youtube.com/embed/rB6KpJc6uoU?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (BitRobot Network: Best Robotics Hack - 1st Place)
- Team: 4 GitHub contributor(s) — Uyen Pham (9 commits), A-Mundanilkunathil (5 commits), kundyzs (4 commits), nmhp16 (4 commits)

## Devpost submission (written by the team)

### Inspiration

We were inspired by the idea of making robots move more naturally — not through pre-programmed motions or scripts, but by understanding and reacting to human movement the same way humans do. Watching fighters and athletes move made us wonder: what if a robot could learn to mirror that instinctively, using only vision and sound? That curiosity turned into MIRAI — Machine Interaction through Real-time Awareness and Imitation, a system that lets a robot see you, follow you, and even understand your voice.

### What it does

MIRAI allows a Unitree G1 humanoid robot to perceive, imitate, and respond to human behavior in real time. Using a camera and microphone, the robot can: Detect and mirror human upper-body movements with natural motion. Follow the user’s position as they move through space. Respond to voice commands such as “follow me,” “stop,” or “mirror mode.” The result is a robot that doesn’t just move — it interacts.

### How we built it

We combined several cutting-edge tools and frameworks to bring MIRAI to life: MediaPipe and OpenCV for fast, real-time human pose detection and tracking from a camera feed. Pinocchio for inverse kinematics, converting human joint angles into robot joint configurations. SpeechRecognition for our speech-to-action pipeline, translating voice commands into behaviors that the robot executes. A lightweight Python control layer built on Unitree SDK2, which sends motion commands directly to the robot’s motors. Finally, we added motion smoothing and timing filters to eliminate jitter and make the robot’s imitation feel human — fluid, balanced, and reactive.

### Challenges we ran into

Human-to-robot mapping: Translating human motion data into robotic joint space was a major challenge, given that human anatomy doesn’t directly match the robot’s structure. Latency issues: Early tests showed slight delays in movement response, which we mitigated through data smoothing and async pipelines. Balance and stability: The G1 needed custom calibration to maintain stability while performing large arm movements during imitation. Speech reliability: Background noise often interfered with command recognition, requiring dynamic audio filtering.

### Accomplishments we're proud of

Achieved real-time motion imitation with minimal lag. Built a working speech-to-action system that allowed natural control of the robot. Developed a human-aware following mode, enabling the robot to track user position while maintaining a safe distance. Created an integrated control loop that combines vision, audio, and motor control — a step toward unified human-robot interaction. Seeing the robot shadow our movements and respond to our voice felt like the start of something bigger — almost like watching fiction turn into reality.

### What we learned

The importance of synchronizing multimodal systems (vision + audio + actuation). Fine-tuning inverse kinematics requires both math and intuition. Smooth motion is more impactful than just accuracy — a small delay feels more human than a perfect but robotic response. Combining multiple AI pipelines (speech and pose) is surprisingly powerful when done in real time. Most importantly, we learned that true human-robot interaction isn’t just about sensors — it’s about creating presence.

### What's next

We’re looking to expand MIRAI beyond shadowing and speech commands into intent recognition — where the robot predicts motion or responds emotionally to interaction cues. Our next milestones: Add gesture-based control and multi-person tracking. Port MIRAI to more robot platforms for teleoperation and rehabilitation robotics. Integrate LLMs for contextual speech understanding, allowing conversational coordination. Explore industrial and healthcare applications where intuitive motion mirroring could enhance safety and collaboration. MIRAI started as a boxing robot. It’s quickly becoming a framework for natural human-robot symbiosis.

## README (from the GitHub repository)

ssh unitree@192.168.123.164
ssh unitree@192.168.0.85 (same network no ethernet)
123


## Detected evidence (automated analysis)

Indexed codebase: 18 recognized source files, 200 KB.
- C++ (language) — detected in the code
- Python (language) — detected in the code

## Codebase structure (from repository index)

### Files (21 of 21)

```
.env.example
.gitignore
basic.cpp
diagnose_g1_sdk.py
enable_sdk_mode.py
find_cameras.py
g1_hand_low_level.py
g1_high_level_control.py
g1_mediapipe_arms_pinnochio.py
g1_mediapipe_arms_v2.py
g1_nlp_control.py
g1_vision_detection.py
g1_vision_with_control.py
g1_vlm_control.py
README.md
run_pinnochio.sh
test_g1_control.py
test_minimal_movement.py
test_punch_mirror.py
test_vision_headless.py
Unitree.esproj
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Remove GEMINI_API_KEY references from .env.example and update LLMInterpreter to use only GOOGLE_API_KEY
- Add initial implementation of G1 NLP control with LLM and environment configuration
- Merge pull request #3 from A-Mundanilkunathil/uyen
- Fix bug for tracking
- ssh connection details
- Merge pull request #2 from A-Mundanilkunathil/uyen
- very good arm track
- good arm track
- OpenCV for punch tracking
- Merge pull request #1 from A-Mundanilkunathil/uyen
- Create Lens Studio object to connect robot to Spectacles
- Enhance G1 movement and vision control with improved tracking, motion detection, and SDK diagnostics
- Enhance G1 vision control with multi-detection capabilities and aggressive tracking adjustments
- Enhance object tracking functionality with headless mode support and improved display options
- Enhance vision detection with model downloading and camera discovery features
- Implement VLM integration for Unitree G1 robot using Google Gemini 2.5 Flash
- Implement vision detection and movement control for Unitree G1 robot
- added gesture commands
- Merge branch 'kundyzz' of https://github.com/A-Mundanilkunathil/Unitree-G1 into kundyzz
- new movements

## Key source files (fetched from GitHub, selected and truncated for size)

### run_pinnochio.sh

```shell
#!/bin/bash
# Wrapper to run g1_mediapipe_arms_pinocchio.py with proper environment

# Use unitree SDK's bundled cyclonedds (remove CYCLONEDDS_HOME so it auto-detects)
export LD_LIBRARY_PATH=/home/unitree/unitree_sdk2/thirdparty/lib/aarch64:$LD_LIBRARY_PATH

# Add unitree SDK to Python path
export PYTHONPATH=/home/unitree/unitree_sdk2_python:$PYTHONPATH

# Run with micromamba tv environment python
exec $HOME/.local/share/mamba/envs/tv/bin/python3 /home/unitree/unitree_sdk2_python/g1_mediapipe_arms_pinocchio.py

```

### basic.cpp

```c++
#include <iostream>
#include "unitree_sdk2/low_level.h"  // adjust include path to your SDK

int main(int argc, char** argv) {
    std::string interface = "enp2s0";  // replace with your network interface
    unitree_sdk2::LowLevelClient client(interface);

    // connect
    if (!client.connect()) {
        std::cerr << "Failed to connect to robot low-level interface\n";
        return -1;
    }

    // Prepare a low-level command structure
    unitree_sdk2::MotorCommand cmd{};
    cmd.mode = unitree_sdk2::MotorMode::PMSM;  // for example
    cmd.q    = 0.0f;     // desired angle in rad
    cmd.dq   = 0.0f;     // desired velocity in rad/s
    cmd.tau  = 0.0f;     // desired torque in N·m
    cmd.Kp   = 10.0f;    // position stiffness
    cmd.Kd   = 1.0f;     // velocity stiffness

    // Example: set one joint
    client.setMotorCommand(joint_index = 0, cmd);

    // send the command
    if (!client.sendCommand()) {
        std::cerr << "Failed to send low-level motor command\n";
    }

    client.disconnect();
    return 0;
}
```

### diagnose_g1_sdk.py

```python
"""
G1 SDK Diagnostic - Find the Correct API
Run this on the robot to discover G1-specific modules
"""

import sys

print("="*60)
print("UNITREE G1 SDK DIAGNOSTIC")
print("="*60)

# Check SDK installation
print("\n1. Checking SDK installation...")
try:
    import unitree_sdk2py
    print(f"✓ unitree_sdk2py version: {getattr(unitree_sdk2py, '__version__', 'unknown')}")
    print(f"✓ Location: {unitree_sdk2py.__file__}")
except ImportError as e:
    print(f"✗ SDK not found: {e}")
    sys.exit(1)

# List top-level modules
print("\n2. Top-level modules in SDK:")
modules = [x for x in dir(unitree_sdk2py) if not x.startswith('_')]
for mod in sorted(modules):
    print(f"   - {mod}")

# Check for robot-specific modules
print("\n3. Checking for robot-specific modules:")
robot_types = ['g1', 'h1', 'go2', 'b2', 'humanoid', 'quadruped']
for robot in robot_types:
    try:
        mod = getattr(unitree_sdk2py, robot, None)
        if mod:
            print(f"✓ {robot}: {mod}")
            submods = [x for x in dir(mod) if not x.startswith('_')]
            for submod in submods[:5]:  # Show first 5
                print(f"     └─ {submod}")
        else:
            print(f"✗ {robot}: not found")
    except Exception as e:
        print(f"✗ {robot}: error - {e}")

# Check for sport/control modules
print("\n4. Checking control modules:")
try:
    from unitree_sdk2py.go2.sport import sport_client
    print("✓ go2.sport.sport_client (QUADRUPED - wrong for G1!)")
    print(f"   SportClient methods:")
    client_methods = [x for x in dir(sport_client.SportClient) if not x.startswith('_')]
    for method in sorted(client_methods)[:10]:
        print(f"     - {method}")
except ImportError as e:
    print(f"✗ go2.sport: {e}")

# Check for humanoid-specific modules
print("\n5. Searching for humanoid/G1-specific controllers...")
try:
    import pkgutil
    import importlib
    
    for importer, modname, ispkg in pkgutil.walk_packages(
        path=unitree_sdk2py.__path__,
        prefix=unitree_sdk2py.__name__ + '.',
        onerror=lambda x: None
    ):
        if any(keyword in modname.lower() for keyword in ['g1', 'h1', 'humanoid', 'biped']):
            print(f"✓ Found: {modname}")
            try:
                mod = importlib.import_module(modname)
                items = [x for x in dir(mod) if not x.startswith('_')][:5]
                for item in items:
                    print(f"     └─ {item}")
            except:
                pass
except Exception as e:
    print(f"✗ Search failed: {e}")

# Check IDL messages
print("\n6. Checking available message types...")
try:
    from unitree_sdk2py.idl import unitree_go
    print("✓ IDL messages available:")
    print(f"   {dir(unitree_go.msg)[:5]}")
except ImportError as e:
    print(f"✗ IDL messages: {e}")

# Summary
print("\n" + "="*60)
print("DIAGNOSTIC COMPLETE")
print("="*60)
print("\n📋 Action Items:")
print("1. Look for modules with 'g1', 'h1', or 'humanoid' in the name above")
print("2. If only 'go2' modules exist, contact Unitree for G1-specific SDK")
print("3. Check /opt/unitree/ or robot docs for G1 examples")
print("4. Try Unitree's GitHub: github.com/unitreerobotics")
print("\n⚠️  IMPORTANT: go2.sport.SportClient is for QUADRUPEDS, not humanoids!")

```

### enable_sdk_mode.py

```python
#!/usr/bin/env python3
"""
Unitree G1 - Enable SDK Mode and Test Basic Commands

This script helps you verify the robot is ready for SDK control.
"""

import time
from unitree_sdk2py.core.channel import ChannelFactoryInitialize
from unitree_sdk2py.go2.sport.sport_client import SportClient


def main():
    print("=" * 70)
    print("Unitree G1 - SDK Mode Verification")
    print("=" * 70)
    print()
    
    print("BEFORE running this script, ensure:")
    print("  1. Robot is powered on")
    print("  2. eth0 is connected to robot")
    print("  3. Robot is in SDK/Developer mode")
    print()
    print("HOW TO ENABLE SDK MODE:")
    print("  Method 1: Use Unitree app")
    print("    - Open Unitree app")
    print("    - Go to Settings → Control Mode")
    print("    - Select 'SDK Mode' or 'Developer Mode'")
    print()
    print("  Method 2: Use controller")
    print("    - Hold L2 + A buttons simultaneously")
    print("    - Wait for confirmation on robot display")
    print()
    print("  Method 3: Robot display/button")
    print("    - Check robot's onboard display")
    print("    - Navigate to SDK/Developer mode")
    print()
    
    input("Press ENTER when robot is in SDK mode...")
    print()
    
    # Initialize SDK
    print("Initializing SDK on eth0...")
    try:
        ChannelFactoryInitialize(0, "eth0")
        print("✓ SDK initialized")
    except Exception as e:
        print(f"✗ Initialization failed: {e}")
        return 1
    
    # Create client
    print("Creating SportClient...")
    try:
        client = SportClient()
        client.Init()
        print("✓ SportClient created")
    except Exception as e:
        print(f"✗ SportClient failed: {e}")
        return 1
    
    # Test heartbeat
    print("\nTesting communication with robot...")
    print("Sending 5 heartbeats (watch for errors):")
    
    errors = 0
    for i in range(5):
        try:
            client.HeartBeat()
            print(f"  ✓ Heartbeat {i+1}/5 sent")
            time.sleep(0.5)
        except Exception as e:
            errors += 1
            print(f"  ✗ Heartbeat {i+1}/5 failed: {e}")
    
    print()
    
    if errors > 0:
        print("⚠️  COMMUNICATION ERRORS DETECTED")
        print()
        print("Troubleshooting:")
        print("  1. [ClientStub] send error = Robot not in SDK mode")
        print("     → Enable SDK mode using app or controller")
        print()
        print("  2. Check robot display shows 'SDK Mode'")
        print()
        print("  3. Try rebooting robot and enabling SDK mode again")
        print()
        print("  4. Verify with working SDK examples:")
        print("     cd ~/unitree_sdk2_python/example")
        print("     python3 <example_script>.py")
        print()
        return 1
    else:
        print("✓ SUCCESS! Robot is responding to SDK commands")
        print()
        print("You can now run your control scripts.")
        print()
        
        # Optional: Test a simple command
        print("Testing stand command (robot should respond)...")
        try:
            client.StandUp()
            print("✓ Stand command sent")
            time.sleep(2)
        except Exception as e:
            print(f"✗ Stand command failed: {e}")
        
        return 0


if __name__ == "__main__":
    exit(main())

```

### test_minimal_movement.py

```python
"""
Minimal G1 Movement Test
Tests if Move() commands work at all
"""

import time
from unitree_sdk2py.core.channel import ChannelFactoryInitialize
from unitree_sdk2py.g1.loco.g1_loco_client import LocoClient

print("="*60)
print("MINIMAL G1 MOVEMENT TEST")
print("="*60)

# Initialize SDK
print("\n1. Initializing SDK...")
ChannelFactoryInitialize(0, "eth0")
print("✓ SDK initialized")

# Create loco client (for G1 humanoid robot)
print("\n2. Creating LocoClient for G1...")
client = LocoClient()
client.SetTimeout(10.0)
client.Init()
print("✓ LocoClient created")

# Check if robot is already standing
print("\n3. Checking robot state...")
print("   ⚠️  Assuming robot is ALREADY STANDING")
print("   (If robot is NOT standing, manually stand it up first)")
time.sleep(1)
print("✓ Robot ready for movement commands")

# Test 1: Simple forward walk
print("\n4. TEST 1: Walk forward for 3 seconds...")
print("   Sending continuous Move(0.2, 0, 0) commands...")
start_time = time.time()
while time.time() - start_time < 3.0:
    client.Move(0.2, 0.0, 0.0)
    time.sleep(0.1)  # Send every 100ms
print("   ✓ Forward walk complete!")

# Stop
print("\n5. Stopping...")
client.StopMove()
time.sleep(2)  # Longer pause to ensure robot stops
print("✓ Should have stopped")

# Test 2: Strafe left (PURE strafe, no forward)
print("\n6. TEST 2: Strafe left for 3 seconds (NO FORWARD)...")
print("   Sending continuous Move(0, 0.3, 0) commands...")
print("   ⚠️  Watch carefully - robot should move LEFT only!")
start_time = time.time()
while time.time() - start_time < 3.0:
    client.Move(0.0, 0.3, 0.0)  # vx=0, vy=0.3 (left)
    time.sleep(0.1)  # Send every 100ms
print("   ✓ Strafe left complete!")

# Stop
print("\n7. Stopping...")
client.StopMove()
time.sleep(2)  # Longer pause
print("✓ Should have stopped")

# Test 3: Strafe right (opposite direction)
print("\n8. TEST 3: Strafe right for 3 seconds (NO FORWARD)...")
print("   Sending continuous Move(0, -0.3, 0) commands...")
print("   ⚠️  Watch carefully - robot should move RIGHT only!")
start_time = time.time()
while time.time() - start_time < 3.0:
    client.Move(0.0, -0.3, 0.0)  # vx=0, vy=-0.3 (right)
    time.sleep(0.1)  # Send every 100ms
print("   ✓ Strafe right complete!")

# Stop
print("\n9. Stopping...")
client.StopMove()
time.sleep(2)  # Longer pause
print("✓ Should have stopped")

# Test 4: Turn in place
print("\n10. TEST 4: Turn right for 2 seconds...")
print("    Sending continuous Move(0, 0, -0.3) commands...")
start_time = time.time()
while time.time() - start_time < 2.0:
    client.Move(0.0, 0.0, -0.3)
    time.sleep(0.1)  # Send every 100ms
print("    ✓ Turn right complete!")

# Stop
print("\n11. Stopping...")
client.StopMove()
time.sleep(1)
print("✓ Should have stopped")

print("\n" + "="*60)
print("TEST COMPLETE - Check robot movements!")
print("="*60)
print("\n✅ The robot should have:")
print("   1. Walked FORWARD (vx=+0.2)")
print("   2. Strafed LEFT (vy=+0.3)")
print("   3. Strafed RIGHT (vy=-0.3)")
print("   4. Turned RIGHT (vyaw=-0.3)")
print("\n💡 CRITICAL INSIGHTS:")
print("   - G1 needs CONTINUOUS Move() commands (send every 100ms)")
print("   - This test assumes robot is ALREADY STANDING")
print("   - If robot drops, it may have been in an unstable state")
print("   - For standup sequence, use: Damp() → Squat2StandUp() → wait 8s")
print("\n📋 COORDINATE SYSTEM (from robot's view):")
print("   • vx  > 0 → FORWARD  | vx  < 0 → BACKWARD")
print("   • vy  > 0 → LEFT     | vy  < 0 → RIGHT")
print("   • vyaw > 0 → Rotate LEFT | vyaw < 0 → Rotate RIGHT")





```

### g1_hand_low_level.py

```python
"""
Unitree G1 Hand Low-Level Control
Demonstrates correct SDK initialization and basic motor commands for the hand
"""

import time
from unitree_sdk2py.core.channel import ChannelFactoryInitialize

# Import low-level commands if available (SDK may expose these differently)
# Adjust imports based on your SDK version
try:
    from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_
    from unitree_sdk2py.comm.motion_switcher import MotionSwitcher
    print("✓ Low-level imports available")
except ImportError as e:
    print(f"Low-level imports not available: {e}")
    LowCmd_ = None


def initialize_sdk():
    """
    Initialize the Unitree SDK DDS subsystem
    MUST be called before creating any clients (SportClient, etc.)
    """
    print("Initializing Unitree SDK DDS subsystem...")
    try:
        # Initialize the ChannelFactory with domain ID (typically 0)
        ChannelFactoryInitialize(0)
        print("✓ SDK initialized successfully")
        return True
    except Exception as e:
        print(f"✗ SDK initialization failed: {e}")
        import traceback
        traceback.print_exc()
        return False


def test_hand_commands():
    """
    Test basic hand motor commands
    This is a placeholder - actual commands depend on SDK version
    """
    print("\n=== Hand Command Test ===")
    
    # Hand joint indices (G1 specific - verify with your robot docs)
    # Typically hand joints are at higher indices (e.g., 20-29)
    LEFT_HAND_START = 20   # example
    RIGHT_HAND_START = 25  # example
    
    print("Hand motor control commands:")
    print("  - Joint position: cmd.q = <angle_rad>")
    print("  - Joint velocity: cmd.dq = <velocity_rad_s>")
    print("  - Joint torque: cmd.tau = <torque_Nm>")
    print("  - PD gains: cmd.Kp, cmd.Kd")
    
    # Example command structure (conceptual - adapt to your SDK)
    print("\nExample low-level command structure:")
    print("  motor_cmd = MotorCmd()")
    print("  motor_cmd.mode = 0x01  # Position/torque mode")
    print("  motor_cmd.q = 0.5      # Target angle (rad)")
    print("  motor_cmd.dq = 0.0     # Target velocity")
    print("  motor_cmd.tau = 0.0    # Feedforward torque")
    print("  motor_cmd.Kp = 10.0    # Position gain")
    print("  motor_cmd.Kd = 1.0     # Damping gain")
    
    return True


def basic_hand_movement_demo():
    """
    Demonstrates basic hand movement sequence
    NOTE: This is a safe demonstration - adapt for your specific hand
    """
    print("\n=== Basic Hand Movement Demo ===")
    
    # Common hand commands for G1
    commands = {
        "open_hand": {
            "description": "Open hand (extend fingers)",
            "joint_angles": [0.0, 0.0, 0.0, 0.0, 0.0],  # example
            "duration": 2.0
        },
        "close_hand": {
            "description": "Close hand (curl fingers)",
            "joint_angles": [1.2, 1.2, 1.2, 1.2, 1.2],  # example
            "duration": 2.0
        },
        "neutral": {
            "description": "Neutral position",
            "joint_angles": [0.5, 0.5, 0.5, 0.5, 0.5],  # example
            "duration": 1.5
        }
    }
    
    for cmd_name, cmd_data in commands.items():
        print(f"\n{cmd_data['description']}:")
        print(f"  Target angles: {cmd_data['joint_angles']}")
        print(f"  Duration: {cmd_data['duration']}s")
        # In real implementation: send_motor_commands(cmd_data['joint_angles'])
        time.sleep(0.5)
    
    return True


def main():
    """Main entry point"""
    print("=" * 60)
    print("Unitree G1 Hand Low-Level Control")
    print("=" * 60)
    
    # Step 1: Initialize SDK (CRITICAL - must be first)
    if not initialize_sdk():
        print("\n✗ Cannot proceed without SDK initialization")
        print("\nTroubleshooting:")
        print("1. Ensure cyclonedds.xml is valid or use default config")
        print("2. Check network interface is up")
        print("3. Verify SDK installation: pip3 show unitree-sdk2py")
        return 1
    
    # Step 2: Test command knowledge
    test_hand_commands()
    
    # Step 3: Demo movement sequence
    basic_hand_movement_demo()
    
    print("\n" + "=" * 60)
    print("Demo complete!")
    print("=" * 60)
    
    return 0


if __name__ == "__main__":
    exit(main())

```

### test_vision_headless.py

```python
#!/usr/bin/env python3
"""
Unitree G1 Vision Detection - Headless Mode
Saves snapshots to files instead of displaying windows
"""

import cv2
import numpy as np
import time
from g1_vision_detection import G1VisionDetector


def test_vision_headless():
    """Test vision detection without display (headless mode)"""
    print("\n" + "="*60)
    print("G1 VISION DETECTION - HEADLESS MODE")
    print("="*60)
    
    print("\nSelect detection model:")
    print("1. Cascade (face/eye detection) - No external files needed")
    print("2. YOLO (object detection) - Requires model files")
    print("3. MobileNet SSD (object detection) - Requires model files")
    
    choice = input("\nChoice [1]: ").strip() or "1"
    
    model_map = {'1': 'cascade', '2': 'yolo', '3': 'mobilenet'}
    model_type = model_map.get(choice, 'cascade')
    
    # Create detector
    detector = G1VisionDetector(model_type=model_type, confidence_threshold=0.5)
    
    print("\nSelect camera source:")
    print("1. G1 Camera 1 (index 2) - Recommended")
    print("2. G1 Camera 2 (index 4)")
    print("3. Custom camera index")
    
    cam_choice = input("\nChoice [1]: ").strip() or "1"
    
    if cam_choice == "1":
        camera_source = 2
    elif cam_choice == "2":
        camera_source = 4
    elif cam_choice == "3":
        camera_source = int(input("Enter camera index: ").strip())
    else:
        camera_source = 2
    
    # Connect to camera
    if not detector.connect_camera(camera_source):
        print("\n✗ Failed to connect to camera")
        print("\nTrying fallback cameras...")
        for fallback in [2, 4]:
            print(f"Trying camera {fallback}...")
            if detector.connect_camera(fallback):
                break
        else:
            print("✗ No camera available")
            return
    
    # Start capture
    detector.start_capture()
    time.sleep(1)
    
    print("\n✓ Detection system ready (headless mode)")
    print("\nOptions:")
    print("  1. Capture single frame")
    print("  2. Capture 10 frames (1 per second)")
    print("  3. Continuous capture (Ctrl+C to stop)")
    
    mode = input("\nChoice [1]: ").strip() or "1"
    
    print("\nStarting capture...")
    print("Frames will be saved to: detection_<timestamp>.jpg")
    print("="*60 + "\n")
    
    frame_count = 0
    
    try:
        if mode == "1":
            # Single frame
            time.sleep(0.5)
            with detector.frame_lock:
                if detector.frame is not None:
                    frame = detector.frame.copy()
                    
                    detections = detector.detect_objects(frame)
                    annotated = detector.draw_detections(frame, detections)
                    summary = detector.get_detection_summary(detections)
                    
                    filename = f"detection_{int(time.time())}.jpg"
                    cv2.imwrite(filename, annotated)
                    
                    print(f"✓ Saved: {filename}")
                    print(f"  Detected: {summary['total_objects']} objects")
                    for class_name, info in summary['by_class'].items():
                        print(f"    - {class_name}: {info['count']} ({info['avg_confidence']:.2f})")
        
        elif mode == "2":
            # 10 frames
            for i in range(10):
                with detector.frame_lock:
                    if detector.frame is not None:
                        frame = detector.frame.copy()
                        
                        detections = detector.detect_objects(frame)
                        annotated = detector.draw_detections(frame, detections)
                        summary = detector.get_detection_summary(detections)
                        
                        filename = f"detection_{int(time.time())}_{i:02d}.jpg"
                        cv2.imwrite(filename, annotated)
                        
                        print(f"✓ Frame {i+1}/10: {filename}")
                        if summary['total_objects'] > 0:
                            print(f"  Detected: {summary['total_objects']} objects")
                            for class_name, info in summary['by_class'].items():
                                print(f"    - {class_name}: {info['count']}")
                
                time.sleep(1)
        
        else:
            # Continuous
            print("Capturing continuously (Ctrl+C to stop)...")
            print("Saving one frame every 2 seconds\n")
            
            while True:
                with detector.frame_lock:
                    if detector.frame is not None:
                        frame = detector.frame.copy()
                        
                        detections = detector.detect_objects(frame)
                        annotated = detector.draw_detections(frame, detections)
                        summary = detector.get_detection_summary(detections)
                        
                        filename = f"detection_{int(time.time())}.jpg"
                        cv2.imwrite(filename, annotated)
                        frame_count += 1
                        
                        status = f"Frame {frame_count}: {filename} | Objects: {summary['total_objects']}"
                        if summary['by_class']:
                            status += " | " + ", ".join([f"{k}:{v['count']}" for k, v in summary['by_class'].items()])
                        print(status)
                
                time.sleep(2)
    
    except KeyboardInterrupt:
        print("\n\nStopped by user")
    
    finally:
        detector.release()
        print(f"\n✓ Saved {frame_count} frames")
        print("✓ Test complete")


if __name__ == "__main__":
    test_vision_headless()

```

### find_cameras.py

```python
#!/usr/bin/env python3
"""
Find all available cameras on the G1 robot
"""

import cv2
import subprocess
import os


def check_video_devices():
    """Check for /dev/video* devices"""
    print("=" * 60)
    print("1. Checking Video Devices")
    print("=" * 60)
    
    devices = []
    for i in range(10):
        device = f"/dev/video{i}"
        if os.path.exists(device):
            devices.append(device)
            print(f"  ✓ Found: {device}")
    
    if not devices:
        print("  ✗ No /dev/video* devices found")
        print("  → Robot may not have USB cameras attached")
    
    print()
    return devices


def test_opencv_cameras():
    """Test OpenCV camera indices"""
    print("=" * 60)
    print("2. Testing OpenCV Camera Indices")
    print("=" * 60)
    
    working_cameras = []
    
    for i in range(10):
        print(f"  Testing camera index {i}...", end=" ")
        cap = cv2.VideoCapture(i)
        
        if cap.isOpened():
            ret, frame = cap.read()
            if ret and frame is not None:
                h, w = frame.shape[:2]
                print(f"✓ Working ({w}x{h})")
                working_cameras.append(i)
            else:
                print("✗ Opens but no frame")
        else:
            print("✗ Cannot open")
        
        cap.release()
    
    print()
    if not working_cameras:
        print("  ✗ No working OpenCV cameras found")
    else:
        print(f"  ✓ Found {len(working_cameras)} working camera(s): {working_cameras}")
    
    print()
    return working_cameras


def check_rtsp_streams():
    """Check common G1 RTSP camera streams"""
    print("=" * 60)
    print("3. Checking G1 Robot RTSP Streams")
    print("=" * 60)
    
    # Common G1 camera IPs and ports
    streams = [
        "rtsp://192.168.123.161:8554/main_stream",
        "rtsp://192.168.123.161:8554/sub_stream",
        "rtsp://192.168.123.164:8554/main_stream",
        "rtsp://192.168.123.164:8554/sub_stream",
        "rtsp://192.168.123.15:8554/main_stream",   # Go2 default
    ]
    
    working_streams = []
    
    for stream in streams:
        print(f"  Testing: {stream}")
        print(f"    Trying connection...", end=" ")
        
        cap = cv2.VideoCapture(stream, cv2.CAP_FFMPEG)
        cap.set(cv2.CAP_PROP_OPEN_TIMEOUT_MSEC, 3000)  # 3 second timeout
        
        if cap.isOpened():
            ret, frame = cap.read()
            if ret and frame is not None:
                h, w = frame.shape[:2]
                print(f"✓ Working ({w}x{h})")
                working_streams.append(stream)
            else:
                print("✗ Opens but no frame")
        else:
            print("✗ Connection refused")
        
        cap.release()
    
    print()
    if not working_streams:
        print("  ✗ No RTSP streams accessible")
        print("  → Check robot IP and camera service")
    else:
        print(f"  ✓ Found {len(working_streams)} working stream(s):")
        for s in working_streams:
            print(f"    - {s}")
    
    print()
    return working_streams


def check_http_streams():
    """Check common HTTP/MJPEG streams"""
    print("=" * 60)
    print("4. Checking HTTP/MJPEG Streams")
    print("=" * 60)
    
    streams = [
        "http://192.168.123.161:8080/video",
        "http://192.168.123.164:8080/video",
        "http://192.168.123.161:8000/stream.mjpg",
    ]
    
    working_streams = []
    
    for stream in streams:
        print(f"  Testing: {stream}...", end=" ")
        
        cap = cv2.VideoCapture(stream)
        if cap.isOpened():
            ret, frame = cap.read()
            if ret and frame is not None:
                h, w = frame.shape[:2]
                print(f"✓ Working ({w}x{h})")
                working_streams.append(stream)
            else:
                print("✗ Opens but no frame")
        else:
            print("✗ Cannot open")
        
        cap.release()
    
    print()
    if working_streams:
        print(f"  ✓ Found {len(working_streams)} working stream(s):")
        for s in working_streams:
            print(f"    - {s}")
    else:
        print("  ✗ No HTTP streams accessible")
    
    print()
    return working_streams


def check_network():
    """Check network connectivity to robot"""
    print("=" * 60)
    print("5. Checking Network to Robot")
    print("=" * 60)
    
    ips = ["192.168.123.161", "192.168.123.164", "192.168.123.15"]
    
    reachable = []
    for ip in ips:
        print(f"  Pinging {ip}...", end=" ")
        result = subprocess.run(['ping', '-c', '1', '-W', '1', ip],
                              capture_output=True, text=True)
        if result.returncode == 0:
            print("✓ Reachable")
            reachable.append(ip)
        else:
            print("✗ Not reachable")
    
    print()
    if not reachable:
        print("  ✗ Robot not reachable on network")
        print("  → Check eth0 configuration and robot power")
    else:
        print(f"  ✓ Robot reachable at: {', '.join(reachable)}")
    
    print()
    return reachable


def main():
    print("\n" + "=" * 60)
    print("UNITREE G1 CAMERA DISCOVERY")
    print("=" * 60)
    print()
    
    # Run all checks
    video_devices = check_video_devices()
    opencv_cameras = test_opencv_cameras()
    rtsp_streams = check_rtsp_streams()
    http_streams = check_http_streams()
    reachable_ips = check_network()
    
    # Summary
    print("=" * 60)
    print("SUMMARY & RECOMMENDATIONS")
    print("=" * 60)
    print()
    
    if opencv_cameras:
        print("✓ Use OpenCV camera:")
        for cam in opencv_cameras:
            print(f"  detector.connect_camera({cam})")
        print()
    
    if rtsp_streams:
        print("✓ Use RTSP stream:")
        for stream in rtsp_streams:
            print(f'  detector.connect_camera("{stream}")')
        print()
    
    if http_streams:
        print("✓ Use HTTP stream:")
        for stream in http_streams:
            print(f'  detector.co
[truncated — 992 more characters]
```

### test_g1_control.py

```python
"""
Test file for Unitree G1 High-Level Control
Run this to test various control functions
"""

import time
import sys
from g1_high_level_control import G1HighLevelController


def test_basic_movements(controller):
    """Test basic movement commands"""
    print("\n" + "="*50)
    print("TEST 1: Basic Movements")
    print("="*50)
    
    try:
        # Stand up
        print("\n1. Standing up...")
        controller.stand_up()
        time.sleep(4)
        
        # Walk forward
        print("\n2. Walking forward...")
        controller.walk_forward(speed=0.2, duration=3)
        time.sleep(1)
        
        # Walk backward
        print("\n3. Walking backward...")
        controller.walk_backward(speed=0.2, duration=3)
        time.sleep(1)
        
        # Stop
        print("\n4. Stopping...")
        controller.stop_move()
        time.sleep(1)
        
        print("\n✓ Basic movements test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Basic movements test failed: {e}")
        return False


def test_rotation(controller):
    """Test rotation commands"""
    print("\n" + "="*50)
    print("TEST 2: Rotation")
    print("="*50)
    
    try:
        # Turn left
        print("\n1. Turning left...")
        controller.turn_left(speed=0.3, duration=2)
        time.sleep(1)
        
        # Turn right
        print("\n2. Turning right...")
        controller.turn_right(speed=0.3, duration=2)
        time.sleep(1)
        
        # Stop
        controller.stop_move()
        time.sleep(1)
        
        print("\n✓ Rotation test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Rotation test failed: {e}")
        return False


def test_strafing(controller):
    """Test strafing movements"""
    print("\n" + "="*50)
    print("TEST 3: Strafing")
    print("="*50)
    
    try:
        # Strafe left
        print("\n1. Strafing left...")
        controller.strafe_left(speed=0.15, duration=2)
        time.sleep(1)
        
        # Strafe right
        print("\n2. Strafing right...")
        controller.strafe_right(speed=0.15, duration=2)
        time.sleep(1)
        
        # Stop
        controller.stop_move()
        time.sleep(1)
        
        print("\n✓ Strafing test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Strafing test failed: {e}")
        return False


def test_pose_control(controller):
    """Test body pose control"""
    print("\n" + "="*50)
    print("TEST 4: Pose Control")
    print("="*50)
    
    try:
        # Raise body
        print("\n1. Raising body height...")
        controller.pose(body_height=0.02)
        time.sleep(2)
        
        # Lower body
        print("\n2. Lowering body height...")
        controller.pose(body_height=-0.05)
        time.sleep(2)
        
        # Pitch forward
        print("\n3. Pitching forward...")
        controller.pose(pitch=0.1)
        time.sleep(2)
        
        # Return to neutral
        print("\n4. Returning to neutral pose...")
        controller.pose(body_height=0.0, pitch=0.0)
        time.sleep(2)
        
        print("\n✓ Pose control test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Pose control test failed: {e}")
        return False


def test_circle_walk(controller):
    """Test circular walking pattern"""
    print("\n" + "="*50)
    print("TEST 5: Circle Walk")
    print("="*50)
    
    try:
        print("\n1. Walking in a circle...")
        controller.circle_walk(radius=1.0, speed=0.25, duration=8)
        time.sleep(1)
        
        controller.stop_move()
        
        print("\n✓ Circle walk test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Circle walk test failed: {e}")
        return False


def test_gait_switching(controller):
    """Test different gait patterns"""
    print("\n" + "="*50)
    print("TEST 6: Gait Switching")
    print("="*50)
    
    try:
        # Trot gait
        print("\n1. Switching to trot gait...")
        controller.switch_gait(1)
        time.sleep(2)
        
        controller.walk_forward(speed=0.3, duration=3)
        time.sleep(1)
        
        # Back to idle
        print("\n2. Returning to idle gait...")
        controller.switch_gait(0)
        time.sleep(2)
        
        print("\n✓ Gait switching test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Gait switching test failed: {e}")
        return False


def test_balance_modes(controller):
    """Test different balance and standing modes"""
    print("\n" + "="*50)
    print("TEST 7: Balance Modes")
    print("="*50)
    
    try:
        # Balance stand
        print("\n1. Testing balance stand...")
        controller.balance_stand()
        time.sleep(3)
        
        # Euler stand
        print("\n2. Testing euler stand...")
        controller.euler_stand()
        time.sleep(3)
        
        print("\n✓ Balance modes test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ Balance modes test failed: {e}")
        return False


def test_combined_movement(controller):
    """Test combined movements (diagonal, curved paths)"""
    print("\n" + "="*50)
    print("TEST 8: Combined Movement")
    print("="*50)
    
    try:
        # Diagonal forward-left
        print("\n1. Moving diagonally forward-left...")
        controller.move(vx=0.2, vy=0.1, vyaw=0.0)
        time.sleep(3)
        
        # Diagonal backward-right with rotation
        print("\n2. Moving diagonally backward-right with rotation...")
        controller.move(vx=-0.15, vy=-0.1, vyaw=0.2)
        time.sleep(3)
        
        # Stop
        controller.stop_move()
        time.sleep(1)
        
        print("\n✓ Combined movement test completed")
        return True
        
    except Exception as e:
        print(f"\n✗ C
[truncated — 5615 more characters]
```

[8 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]