Files
moulin-mapper/pipeline/stream_replay.py
Flag 85e9a4d4b0 feat(moulin-mapper): simulateur capteurs + pipeline SLAM Python (JSONL stream → trajectoire + nuage .ply)
- 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)
2026-06-06 20:01:22 +00:00

81 lines
2.2 KiB
Python

"""
stream_replay.py — Rejoue un fichier JSONL sur stdout avec timing optionnel.
Simule le streaming live d'un capteur ROV.
Peut se chaîner avec process.py :
python3 stream_replay.py | python3 process.py --stdin
python3 stream_replay.py --realtime | python3 process.py --stdin
Usage :
python3 stream_replay.py [--input ../data/sim/run_L.jsonl] [--realtime] [--speed 10.0]
"""
import argparse
import json
import sys
import time
import os
def replay(
input_path: str,
realtime: bool = False,
speed: float = 1.0,
output=None,
):
"""
Lit le JSONL et écrit sur stdout (ou output) ligne par ligne.
Si realtime=True, attend le bon délai entre les lignes.
speed > 1 accélère le replay (utile pour tests).
"""
if output is None:
output = sys.stdout
prev_t = None
n = 0
with open(input_path) as f:
for line in f:
line = line.strip()
if not line:
continue
if realtime:
try:
rec = json.loads(line)
t = rec.get("t", 0.0)
if prev_t is not None:
dt = (t - prev_t) / speed
if dt > 0:
time.sleep(dt)
prev_t = t
except json.JSONDecodeError:
pass
output.write(line + "\n")
output.flush()
n += 1
# Signal de fin (ligne vide → process.py ignore)
sys.stderr.write(f"[stream_replay] {n} lignes émises\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Replay JSONL stream")
parser.add_argument("--input", default="../data/sim/run_L.jsonl")
parser.add_argument("--realtime", action="store_true",
help="Respecter les délais temporels")
parser.add_argument("--speed", type=float, default=1.0,
help="Facteur d'accélération (ex: 10 = 10x plus rapide)")
args = parser.parse_args()
if not os.path.exists(args.input):
sys.stderr.write(f"ERREUR : fichier introuvable : {args.input}\n")
sys.exit(1)
replay(
input_path=args.input,
realtime=args.realtime,
speed=args.speed,
)