# Vision Service - Skull Pi

Service de détection et tracking de visages temps réel pour le projet Skull Pi.

## Vue d'ensemble

Le service Vision capture la caméra, détecte et tracke les visages avec MediaPipe, calcule les poses cibles et scores de mouvement, puis publie les données via MQTT. Il peut optionnellement émettre des commandes motion pour les servos eyes/neck.

### Caractéristiques principales

- **Détection multi-visages** avec MediaPipe Face Detection + Face Mesh
- **Tracking stable** avec IDs persistants et association par IoU
- **Politiques de sélection** : closest, largest, round_robin
- **Score de mouvement** basé sur variations temporelles des features
- **Lissage configurable** EMA pour eyes (réactif) et neck (stable)
- **Mapping automatique** vers commandes motion avec gains configurables
- **Monitoring santé** avec métriques FPS/latence et watchdog
- **Configuration dynamique** via MQTT retained
- **Mode dégradé** sans caméra ou MediaPipe

## Architecture

```
vision/
├── __init__.py
├── main.py              # Service principal et boucles
├── camera.py            # Interface caméra V4L2 + mock
├── mp.py                # Wrapper MediaPipe
├── tracker.py           # Tracking IDs + politiques sélection
├── motion_score.py      # Calcul score mouvement
├── smoothing.py         # Lissage EMA + buffer retard
├── mapper.py            # Mapping vers commandes eyes/neck
├── mqtt.py              # Client MQTT + publishers
├── config.py            # Gestion configuration
├── health.py            # Monitoring santé + watchdog
└── tests/               # Tests unitaires
```

## Installation

### Prérequis

```bash
# Dépendances système (Raspberry Pi OS)
sudo apt update
sudo apt install -y python3-venv python3-pip
sudo apt install -y libopencv-dev python3-opencv
sudo apt install -y mosquitto mosquitto-clients

# Permissions caméra
sudo usermod -a -G video skull
```

### Installation Python

```bash
# Créer environnement virtuel
python3 -m venv /opt/Skull/venv
source /opt/Skull/venv/bin/activate

# Installer dépendances
pip install --upgrade pip
pip install opencv-python
pip install mediapipe
pip install paho-mqtt
pip install numpy
pip install pytest pytest-asyncio

# Pour monitoring système (optionnel)
pip install psutil
```

### Déploiement

```bash
# Copier code
sudo cp -r vision/ /opt/Skull/apps/
sudo chown -R skull:skull /opt/Skull/apps/vision

# Copier script de lancement
sudo cp skull-vision.sh /opt/Skull/bin/
sudo chmod +x /opt/Skull/bin/skull-vision.sh

# Installer service systemd
sudo cp skull-vision.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable skull-vision
```

## Configuration

### Variables d'environnement (.env)

```bash
VISION_RES=320x240          # Résolution caméra
VISION_FPS=15               # FPS cible
VISION_MIN_DET_CONF=0.6     # Seuil confiance détection
VISION_MIN_TRACK_CONF=0.5   # Seuil confiance tracking
```

### Configuration MQTT retained

#### `skull/config/vision`

```json
{
  "min_det_conf": 0.6,
  "min_track_conf": 0.5,
  "motion_threshold": 0.35,
  "eyes_alpha": 0.5,
  "neck_alpha": 0.2,
  "neck_lag_ms": 120,
  "publish_motion_cmds": true
}
```

#### `skull/config/gaze`

```json
{
  "policy": "round_robin",
  "dwell_ms": 1200,
  "max_targets": 3,
  "g_eyes": 0.9,
  "g_neck": 0.6
}
```

### Paramètres expliqués

| Paramètre          | Description                                             | Valeur par défaut |
| ------------------ | ------------------------------------------------------- | ----------------- |
| `min_det_conf`     | Seuil confiance détection MediaPipe                     | 0.6               |
| `min_track_conf`   | Seuil confiance tracking MediaPipe                      | 0.5               |
| `motion_threshold` | Seuil activation score mouvement                        | 0.35              |
| `eyes_alpha`       | Coefficient lissage EMA eyes (réactivité)               | 0.5               |
| `neck_alpha`       | Coefficient lissage EMA neck (stabilité)                | 0.2               |
| `neck_lag_ms`      | Retard commandes neck                                   | 120ms             |
| `policy`           | Politique sélection (`closest`/`largest`/`round_robin`) | `round_robin`     |
| `dwell_ms`         | Durée round-robin par cible                             | 1200ms            |
| `max_targets`      | Nombre max visages trackés                              | 3                 |
| `g_eyes`/`g_neck`  | Gains mapping motion                                    | 0.9 / 0.6         |

## Topics MQTT

### Publications

#### `vision/targets` - Liste des visages détectés

```json
{
  "ts_ms": 1234567890,
  "targets": [
    {
      "id": 1,
      "conf": 0.92,
      "bbox": { "cx": 0.52, "cy": 0.41, "w": 0.22, "h": 0.28 },
      "yaw": -0.18,
      "pitch": 0.05,
      "roll": 0.02
    }
  ]
}
```

#### `vision/pose` - Cible courante

```json
{
  "ts_ms": 1234567890,
  "yaw": -0.18,
  "pitch": 0.05,
  "conf": 0.92,
  "target_id": 1
}
```

#### `vision/motion` - Score de mouvement

```json
{
  "ts_ms": 1234567890,
  "active": true,
  "score": 0.67,
  "reason": "face_motion"
}
```

#### `vision/capabilities` - Capacités (retained)

```json
{
  "mediapipe": true,
  "fps": 15,
  "res": "320x240",
  "multi_face": true
}
```

#### `vision/health` - État santé

```json
{
  "ok": true,
  "fps": 14.2,
  "latency_p50": 68.5,
  "ts_ms": 1234567890
}
```

### Commandes motion (optionnel)

#### `eyes/cmd` - Commande eyes immédiate

```json
{
  "h": 15.5,
  "spd": 0.8
}
```

#### `neck/cmd` - Commande neck avec retard

```json
{
  "pan": -25.3,
  "spd": 0.6,
  "lag_ms": 120
}
```

## Utilisation

### Démarrage service

```bash
# Via systemd
sudo systemctl start skull-vision
sudo systemctl status skull-vision

# Manuel avec logs
/opt/Skull/bin/skull-vision.sh

# Mode debug
cd /opt/Skull/apps/vision
python -m vision.main --log-level DEBUG

# Mode mock (sans caméra)
python -m vision.main --mock
```

### Benchmark performance

```bash
# Test 30 secondes
python -m vision.main --bench --duration 30

# Exemple sortie
FPS: 14.1, Latence P50: 72.3ms, OK: true
FPS: 14.8, Latence P50: 68.1ms, OK: true

=== RAPPORT BENCHMARK ===
{
  "health": {
    "performance": {
      "fps_pipeline": 14.5,
      "latency_p50_ms": 70.2,
      "latency_p95_ms": 95.8
    },
    "counters": {
      "frames_total": 435,
      "pipeline_total": 428,
      "errors_total": 2
    }
  }
}
```

### Tests unitaires

```bash
cd /opt/Skull/apps/vision
pytest tests/ -v

# Tests spécifiques
pytest tests/test_mqtt_formats.py -v
pytest tests/test_tracking.py -v
```

### Monitoring temps réel

```bash
# Observer publications
mosquitto_sub -t 'vision/+' -v

# Observer commandes motion
mosquitto_sub -t 'eyes/cmd' -v
mosquitto_sub -t 'neck/cmd' -v

# Changer politique
mosquitto_pub -t skull/config/gaze -r -m '{"policy":"largest","dwell_ms":800}'

# Ajuster lissage
mosquitto_pub -t skull/config/vision -r -m '{"eyes_alpha":0.7,"neck_alpha":0.3}'
```

## Performance attendues

### Raspberry Pi Zero 2W

| Métrique        | Cible   | Typique   |
| --------------- | ------- | --------- |
| FPS pipeline    | ≥12 FPS | 14-15 FPS |
| Latence P50     | ≤100ms  | 70-80ms   |
| Latence P95     | ≤150ms  | 95-110ms  |
| CPU utilisation | <80%    | 60-70%    |
| Mémoire         | <256MB  | 180-220MB |

### Résolutions supportées

- **320x240** (recommandé) - Performance optimale
- **640x480** - Performance réduite (~8-10 FPS)
- **160x120** - Ultra-léger (~20+ FPS)

## Dépannage

### Problèmes courants

#### Service ne démarre pas

```bash
# Vérifier logs
journalctl -u skull-vision -f

# Vérifier permissions
ls -la /dev/video0
groups skull

# Test manuel
cd /opt/Skull/apps/vision
python -m vision.main --mock --log-level DEBUG
```

#### Performance dégradée

```bash
# Monitoring ressources
htop
free -h

# Vérifier throttling Pi
vcgencmd get_throttled
vcgencmd measure_temp

# Réduire résolution/FPS
mosquitto_pub -t skull/config/vision -r -m '{"fps":10}'
```

#### MQTT indisponible

```bash
# Vérifier broker
systemctl status mosquitto
mosquitto_pub -t test -m "hello"

# Test connectivité
telnet 127.0.0.1 1883
```

#### MediaPipe échec

```bash
# Mode dégradé
python -m vision.main --mock

# Vérifier installation
python -c "import mediapipe; print('OK')"

# Logs détaillés
export GLOG_v=2
python -m vision.main
```

### Modes dégradés

1. **Sans caméra** : Mode mock avec visages synthétiques
2. **Sans MediaPipe** : Détection bbox uniquement (yaw/pitch=0)
3. **Sans MQTT** : Logs uniquement, pas de publication
4. **Performance faible** : Réduction automatique résolution/FPS

### Logs d'erreur typiques

```
{"level": "ERROR", "message": "Impossible d'ouvrir la caméra"}
→ Vérifier /dev/video0, permissions, mode mock

{"level": "WARNING", "message": "FPS faible (8.3 < 12.0)"}
→ Réduire résolution, vérifier CPU/throttling

{"level": "ERROR", "message": "Échec connexion MQTT"}
→ Vérifier broker mosquitto, réseau
```

## Développement

### Structure du code

- **Séparation claire** : capture, processing, publication
- **Threading** : boucles indépendantes pour performance
- **Configuration dynamique** : MQTT retained + callbacks
- **Tests** : mocks pour reproductibilité sans matériel
- **Monitoring** : métriques temps réel + watchdog

### Ajout de features

1. **Nouvelle métrique** : Étendre `HealthManager`
2. **Politique sélection** : Ajouter dans `TargetSelector`
3. **Filtrage** : Modifier `mp.py` ou `tracker.py`
4. **Commande motion** : Étendre `mapper.py`

### Debug avancé

```bash
# Profiling performance
python -m cProfile -o vision.prof -m vision.main --mock --duration 10
python -c "import pstats; pstats.Stats('vision.prof').sort_stats('cumulative').print_stats(20)"

# Memory profiling
pip install memory_profiler
python -m memory_profiler -m vision.main --mock

# Logs JSON structurés
python -m vision.main --log-level DEBUG | jq '.'
```

## License

Projet Skull Pi - Usage interne
