# Ping-Pong-Ping Interactive HTML demo + reference notes for **acoustic distance ranging** between USBL nodes (USV master ↔ AUV slaves). Built collaboratively between Flag and Poulpe on 2026-04-27 from a single design conversation. **Live demo** : https://laboratoire.freeboxos.fr/ping-pong-ping/ --- ## What this archives A self-contained `index.html` (no framework, no external assets) that explains and animates two acoustic ranging schemes used in underwater positioning: 1. **DS-TWR** (Double-Sided Two-Way Ranging) — symmetric ping/pong/ping where **both** sides learn the distance without clock synchronization. Used when the two nodes are peers (mobile-mobile, swarm coopératif). 2. **SS-TWR + passive OWR** (Single-Sided Two-Way Ranging + One-Way Ranging by passive listeners) — asymmetric scheme used when **only the master needs the distance**, with the bonus that any other AUV in acoustic range can compute its own distance to the master from the same single ping. Both animations run continuously, with realistic AUV operating parameters (1–2 kt cruise speed, 5–700 m range, c = 1500 m/s). ## The protocol — short version ### DS-TWR (animation 1) ``` A → B : ping1 B → A : pong (B encodes turnaround_B in the pong frame) A → B : ping2 (A encodes turnaround_A in the ping2 frame) A side : TOF = (round_trip_A − turnaround_B) / 2 B side : TOF = (round_trip_B − turnaround_A) / 2 distance = TOF · c ``` No clock sync required. Each side measures only local deltas. ### SS-TWR + passive OWR (animation 2) ``` USV → AUVi (addressed) : ping (frame carries target ID 0xAi + send timestamp) AUVi receives → match ID → responds: AUVi → USV : pong (encodes turnaround_AUVi) All other AUVj receive the same ping (medium is shared): AUVj computes distance passively : (T_recv_local − T_send_USV) · c USV side (active TWR for AUVi) : TOF = (round_trip − turnaround_AUVi) / 2 AUVj side (passive OWR) : TOF = T_recv_local − T_send_USV ``` **One ping → N range fixes.** The medium remains free between cycles. ### Required infrastructure for OWR The passive AUVs must share a **time reference** with the USV. Two practical options: - **GPS-disciplined oscillators** synchronized at the surface before mission launch, with bounded drift (typically < 1 µs over a few hours for OCXO-grade clocks). - **Send-timestamp embedded in the ping frame** : the USV writes its clock value `T_send` in the ping payload, every receiver reads it and compares to its own `T_recv`. Subject to the same clock-drift caveat. DS-TWR (animation 1) does **not** need this — that's its main feature. SS-TWR + passive OWR (animation 2) trades the synchronization requirement for much faster scan rates. ## Design decisions taken in the conversation These reflect the iterative refinement during the conversation, summarized so the rationale isn't lost: | Decision | Why | |---|---| | **Two animations, not three** | Initially the multi-AUV section had a Broadcast (BC-DS-TWR) mode with N pongs in staggered slots. Flag judged it "relou" — addressed sequential is conceptually simpler, no slot collisions, and combined with passive OWR it's faster anyway. Dropped. | | **SS-TWR (not DS-TWR) for multi-AUV** | In the iUSBL setup (USV tracks AUVs), only the USV needs the distance. The third leg (ping2) is dead weight. Switched the multi-AUV animation to SS-TWR, kept DS-TWR for the principle demo where the symmetry matters. | | **Passive OWR for non-target AUVs** | Originally non-target AUVs were drawn as "✗ ignore". Flag pointed out they can use the ping passively. Each ping now produces N range fixes (1 active + N−1 passive). | | **Realistic AUV speeds (1–2 kt) and ranges (5–700 m)** | First version had AUVs moving at ~140 kt over 5 km — physically impossible. Recalibrated to typical coastal AUV ops. | | **No DS-TWR-vs-SS-TWR speedup table** | Removed cycle-time comparison readouts to avoid clutter. The "fluidity" is visible directly. | | **No ID match alarm** | Replaced "✗ ignore" red alert with "📡 passive OWR" cyan badge, since non-target AUVs are useful, not ignored. | ## File structure ``` ping-pong-ping/ ├── index.html # self-contained demo (HTML + CSS + JS, no externals) ├── README.md # this file └── deploy.sh # one-shot push to Core Caddy webroot ``` `index.html` contains two `` animations driven by independent IIFEs, prose sections explaining each scheme, and worked numerical examples. ## Deploy The page is served from Core (`192.168.0.82`) via Caddy on the path `laboratoire.freeboxos.fr/ping-pong-ping/`. Routing layers : - **Core Caddyfile** (`/docker/caddy/Caddyfile` on `.82`) : `handle /ping-pong-ping { redir /ping-pong-ping/ 307 }` + `handle_path /ping-pong-ping/* { root * /srv/www/ping-pong-ping; file_server }` - **Gateway Caddyfile** (`/etc/caddy/Caddyfile` on LXC 103, `.128`) : `handle /ping-pong-ping/* { reverse_proxy 192.168.0.82:80 }` — note `handle` (not `handle_path`) to **preserve the prefix** when forwarding to Core's path-based block. Otherwise Core sees `/` and falls into the catchall. To re-deploy after an edit : ```bash ./deploy.sh ``` ## Hardware companion repo For the Kogger USBL hardware described in the page : - **Wrapper Python "transpondeur continu"** : `poulpe/kogger-transpondeur-continu` on Gitea — high-level wrapper around the upstream `cosma-tech/kogger_acousticAntenna` driver that puts a Kogger antenna in permanent slave-transponder mode in a single `start()` call. Composes address filter + echo filter + TDMA sync slot + permanent response window + Python callbacks for received pings. No modification of the upstream driver. - **Driver upstream** : `cosma-tech/kogger_acousticAntenna` on GitHub (private). Active checkout on Pi 184 `cosma-auv2` at `/home/pi/dev/swarm-vehicle/src/drivers/kogger_acousticAntenna/`. Snapshot included read-only in the wrapper repo for reference. - **Log decoder** (post-acquisition USBL frame parsing for analysis) : `floppyrj45/cosma-nav/extract/decode_kogger.py` on Gitea. ## TODO / future work - [ ] Add a 3rd animation showing **2D positioning** — currently distance only is animated. AUVs equipped with USBL micro-arrays could also compute their bearing-to-USV; the page mentions this in passing but doesn't visualize it. - [ ] Show **clock drift visualization** in the OWR animation (the synchronization assumption is the load-bearing piece — worth illustrating). - [ ] **Compare with the real Kogger USBL frames** decoded in `floppyrj45/cosma-nav/extract/decode_kogger.py` (8 KB, K-Link `BB 55` protocol reverse-engineered). The 2026-04-08 La Ciotat dataset contained only setup/config frames, no acoustic fixes — when a dataset with real position responses lands, plug the numbers into this demo for end-to-end validation. - [ ] Add a **noise model** (USBL inherent precision is 0.5–2 % of slant range) so the plot dots scatter realistically around the truth curves. - [ ] **Multipath / NLOS** scenario : show what happens when an AUV's pong takes a bounced path. Worth its own panel. ## Credits Conversation between Flag (concept, design feedback, iterative steering) and Poulpe (implementation, deployment, prose) on 2026-04-27 in Discord `#ping-pong-ping`. Archived for future reference and iteration.