- simulator.py: flux JSONL réaliste (Ping360 angle/dist, IMU, heading, depth, altitude) + vérité terrain - slam.py: dead-reckoning + scan-to-map ICP 2D (cKDTree) + fermeture de boucle - process.py: ingestion streaming ligne-par-ligne → trajectory.csv + map_2d.csv + cloud.ply - stream_replay.py: rejoue le flux (vision streaming remote) - SCHEMA.md: contrat format données ROV réel↔sim - RMS dead-reckoning 0.386m → scan-matching 0.188m (2x)
117 lines
4.8 KiB
Markdown
117 lines
4.8 KiB
Markdown
# SCHEMA.md — Contrat de flux capteurs moulin-mapper
|
|
|
|
## Principe
|
|
|
|
Une ligne JSONL = un échantillon Ping360 (un faisceau sonar émis à un angle donné)
|
|
avec la **télémétrie co-enregistrée à cet instant exact**.
|
|
|
|
Le pipeline de traitement doit fonctionner identiquement sur :
|
|
- données simulées (simulator.py)
|
|
- données réelles BlueROV (juste changer la source)
|
|
|
|
Champs optionnels futurs (`image_ref`, `confidence`, etc.) peuvent s'ajouter
|
|
sans casser le pipeline — tous les champs inconnus sont ignorés.
|
|
|
|
---
|
|
|
|
## Format : JSONL (JSON Lines)
|
|
|
|
Un objet JSON par ligne, terminé par `\n`. Pas de tableau englobant.
|
|
|
|
### Exemple
|
|
|
|
```jsonl
|
|
{"t": 12.345, "ping360_angle": 174.6, "ping360_distance": 3.21, "heading": 88.2, "altitude": 1.05, "depth": 1.82, "ax": 0.01, "ay": -0.02, "az": 9.79, "gx": 0.001, "gy": 0.0, "gz": 0.05}
|
|
```
|
|
|
|
---
|
|
|
|
## Champs obligatoires
|
|
|
|
| Champ | Type | Unité | Description |
|
|
|--------------------|---------|-----------|-------------|
|
|
| `t` | float | s | Timestamp depuis le démarrage du flux (epoch relatif) |
|
|
| `ping360_angle` | float | deg | Angle du faisceau sonar **relatif au cap ROV** (0 = avant ROV) |
|
|
| `ping360_distance` | float | m | Distance mesurée jusqu'au premier écho (0.0 = dropout/pas d'écho) |
|
|
| `heading` | float | deg | Cap magnétique ROV, convention Nord=0, Est=90 (CW) |
|
|
| `altitude` | float | m | Hauteur au-dessus du fond (Ping1D vers le bas), 0.0 = dropout |
|
|
| `depth` | float | m | Profondeur sous la surface (pression bar → m d'eau), positif vers le bas |
|
|
| `ax` | float | m/s² | Accélération IMU axe X (avant ROV dans repère corps) |
|
|
| `ay` | float | m/s² | Accélération IMU axe Y (gauche ROV dans repère corps) |
|
|
| `az` | float | m/s² | Accélération IMU axe Z (haut ROV dans repère corps), ~+9.81 au repos |
|
|
| `gx` | float | rad/s | Gyromètre axe X (roulis) |
|
|
| `gy` | float | rad/s | Gyromètre axe Y (tangage) |
|
|
| `gz` | float | rad/s | Gyromètre axe Z (lacet, positif = rotation CW vue du dessus) |
|
|
|
|
---
|
|
|
|
## Repères et conventions
|
|
|
|
### Repère monde : ENU local
|
|
- X = Est, Y = Nord, Z = vers le haut
|
|
- Origine = position initiale du ROV au démarrage
|
|
- Le heading 0° correspond à +Y (Nord)
|
|
|
|
### Ping360
|
|
- **400 pas/tour** (comme le vrai Ping360 BlueRobotics) → résolution angulaire 0.9°/pas
|
|
- `ping360_angle` est **relatif au cap ROV** (0° = avant du ROV)
|
|
- Pour obtenir l'angle monde : `angle_monde = (heading + ping360_angle) % 360`
|
|
- Plage : [0, 360) degrés
|
|
- `ping360_distance = 0.0` signifie absence d'écho (dropout) — à ignorer dans le pipeline
|
|
|
|
### Heading
|
|
- Convention magnétique compas : 0°=Nord, 90°=Est, 180°=Sud, 270°=Ouest (CW)
|
|
- Bruit typique simulé : ~0.5° RMS
|
|
- Dérive lente optionnelle pour simuler un mauvais magnéto
|
|
|
|
### Altitude (Ping1D)
|
|
- Sonar vertical pointant vers le bas
|
|
- Mesure la distance ROV → fond en mètres
|
|
- `altitude = 0.0` signifie dropout (confidence trop basse)
|
|
- Hauteur ROV au-dessus du fond = `altitude`
|
|
- Profondeur fond = `depth + altitude`
|
|
|
|
### IMU
|
|
- Repère corps ROV (Body frame) — PAS ENU
|
|
- `az` ≈ +9.81 m/s² au repos (gravité remontant dans le repère corps)
|
|
- Biais gyro simulé : ~0.005 rad/s — cause dérive dead-reckoning ~18°/min
|
|
|
|
---
|
|
|
|
## Fréquences typiques
|
|
|
|
| Source | Fréquence |
|
|
|----------------|-----------|
|
|
| Ping360 | 400 msgs/sweep, ~1 sweep/4 s (configurable) |
|
|
| IMU | 1 msg par ligne JSONL (co-enregistré avec le ping sonar) |
|
|
| heading | idem |
|
|
| altitude | idem |
|
|
| depth | idem |
|
|
|
|
---
|
|
|
|
## Fichier vérité terrain (simulation uniquement)
|
|
|
|
`run_L_truth.csv` — colonnes : `t, x, y, heading_deg, z`
|
|
- x, y en mètres ENU depuis l'origine
|
|
- heading_deg : cap vrai (sans bruit)
|
|
- z : profondeur (positif vers le bas)
|
|
- Ce fichier n'existe PAS sur données réelles — sert uniquement à valider l'algo
|
|
|
|
---
|
|
|
|
## Champs optionnels (présents dans la simulation, rétrocompatibles)
|
|
|
|
| Champ | Type | Unité | Description |
|
|
|------------------|--------|-------|-------------|
|
|
| `vf` | float | m/s | Vitesse corps forward (avant ROV) — modèle thruster ou DVL |
|
|
| `vl` | float | m/s | Vitesse corps latérale — modèle thruster ou DVL |
|
|
| `image_ref` | string | — | Nom du fichier image caméra co-enregistrée |
|
|
| `confidence` | float | [0,1] | Confiance écho Ping360 |
|
|
| `temperature` | float | °C | Capteur eau |
|
|
| `battery_v` | float | V | Tension batterie |
|
|
|
|
`vf` et `vl` sont produits par le simulateur depuis le modèle de thruster.
|
|
Sur un vrai BlueROV, ils peuvent venir d'un DVL ou du contrôleur de poussée.
|
|
Le pipeline DR utilise `vf`/`vl` s'ils sont présents, sinon intègre `ax`/`ay`.
|