Files
Poulpe 9a158f5c5f Initial: ContinuousTransponder wrapper for Kogger USBL
High-level Python wrapper around the upstream cosma-tech/kogger_acousticAntenna
driver. Configures a Kogger acoustic antenna as a permanent slave transponder
in a single start() call: address filter, echo filter, optional TDMA sync slot,
permanent response window, and Python callbacks for each ping received.

No modification to the upstream driver — only composes existing public methods
in the right order. Snapshot of upstream driver included read-only under driver/
for reference.

Includes:
- transponder_continu.py (302 lines): the wrapper class + CLI
- examples/auv_slave.py (79 lines): usage example with logging
- README.md: design rationale, usage, multi-AUV TDMA, watchdog, hardware wiring
- driver/: snapshot of cosma-tech/kogger_acousticAntenna at commit 1b539f9
  ('Add index slot for multi pinger', 2025-03-11)

Built for Cosma context (USV master + N AUVs slaves) following the design
conversation in Discord #ping-pong-ping (2026-04-27). See poulpe/ping-pong-ping
on Gitea for the interactive demo of the protocol.
2026-04-27 22:08:44 +00:00

144 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kogger USBL — mode transpondeur continu
Wrapper Python de haut niveau autour du driver Kogger `kogger_acousticAntenna` (cosma-tech) qui configure une antenne acoustique en **slave transpondeur permanent** : elle écoute en continu les pings adressés à son ID, répond automatiquement, ignore les autres, et expose un callback Python pour chaque ping reçu.
**Pas de re-armement par ping. Une seule init. Le device répond tant que le process tourne.**
Construit pour le contexte Cosma (USV master + N AUVs slaves), suite à la conversation Discord [#ping-pong-ping](https://gitea.nowyouknow.fr/poulpe/ping-pong-ping) du 2026-04-27 sur les schémas SS-TWR + écoute passive OWR.
---
## Pourquoi ce wrapper
Le driver Kogger upstream (`kogger_protocol_driver.KoggerSBPDevice`) expose toutes les commandes bas niveau nécessaires pour le mode transpondeur :
| Commande | Rôle |
|---|---|
| `set_usbl_transponder(enable)` | Ouvre/ferme la fenêtre de réponse acoustique. `True` = always (timeout `0xFFFFFFFF` µs). |
| `set_usbl_request_address_filter([...])` | Liste 8 adresses (0-7 ou `0xFF`=désactivé) pour lesquelles le device doit répondre. |
| `set_usbl_monitor_config(enable, echo_filter_response_us, echo_filter_request_us)` | Active la surveillance + le filtre d'écho (évite l'auto-déclenchement par réverbération). |
| `set_sync_mode(slot_total, slot_index, slot_duration, enable_delay)` | Enrôle le device dans un slot TDMA (utile en multi-slave). |
| `register_callback(ID_USBL_SOLUTION, fn)` | Branche un callback Python sur les frames USBL solution reçues. |
Mais il faut les composer dans **le bon ordre**, gérer les callbacks, et idéalement avoir un watchdog qui ré-applique la config si le device a redémarré ou que le master a été silencieux trop longtemps.
C'est exactement ce que `ContinuousTransponder` fait — un appel `start()` configure tout et le device entre en mode permanent.
## Architecture
```
.
├── README.md # ce fichier
├── transponder_continu.py # ★ wrapper haut niveau (zéro modif du driver)
├── examples/
│ └── auv_slave.py # exemple AUV slave avec logging
└── driver/ # snapshot read-only du driver upstream
├── kogger_protocol_driver.py (1509 lignes, 78 KB)
├── communication.py
├── interface.py
├── simulation_kogger.py
├── README.md
└── ...
```
**Aucune modification du driver Kogger d'origine.** Tout passe par les méthodes publiques. Quand cosma-tech publie une nouvelle version du driver, il suffit de remplacer le contenu de `driver/` — ce wrapper continue de fonctionner.
## Usage minimal
```python
from transponder_continu import ContinuousTransponder
t = ContinuousTransponder(port="/dev/ttyUSB0", my_address=2,
vehicle_name="AUV-2")
t.on_ping_received(lambda solution: print("ping →", solution))
t.start()
try:
t.run_forever()
finally:
t.stop()
```
## CLI directement
```bash
python3 transponder_continu.py --port /dev/ttyUSB0 --address 2
```
Options utiles :
```
--vehicle AUV-2 # étiquette pour les logs CSV du driver
--watchdog-s 15 # ré-applique la config si silence > 15 s
--slot-total 4 --slot-index 1 --slot-duration 2.0 # enrôle en TDMA
--echo-filter-us 400000 # 400 ms (défaut)
```
## Contenu de la trame transpondeur
Chaque fois que le master USV envoie un ping ciblé sur l'adresse de cet AUV :
1. Le hardware Kogger filtre par adresse (configuré par `set_usbl_request_address_filter`).
2. Si l'adresse correspond, le hardware **répond automatiquement** (le pong est généré par l'antenne, pas par Python — c'est rapide et déterministe).
3. Le driver émet une frame `ID_USBL_SOLUTION` (0x65) sur la sortie UART contenant la distance hardware-computed, le SNR, l'ID source.
4. Le wrapper appelle votre callback `on_ping_received(message)`.
5. Le state interne (`t.state.last_distance_m`, `last_snr`, `last_ping_id`, `pings_received`) est mis à jour.
Tout cela en boucle, sans intervention.
## Multi-AUV en TDMA
Si N AUVs partagent le canal et que le master scanne en round-robin, configurer chaque slave dans son propre slot évite les collisions de pong :
```python
ContinuousTransponder(
port="/dev/ttyUSB0",
my_address=2,
sync=SyncSlot(slot_total=4, slot_index=1, slot_duration=2.0),
)
```
→ AUV-2 ne répond que pendant son slot (slot_index=1, durée 2 s, cycle complet 8 s).
Convention proposée : `slot_index = my_address - 1`.
## Watchdog
Si on n'a rien reçu depuis `watchdog_timeout_s` secondes (et qu'on a au moins reçu un ping au démarrage), le wrapper ré-applique `set_usbl_transponder(enable=True)`. Couvre le cas où l'antenne Kogger reboot silencieusement et perd sa config.
```python
ContinuousTransponder(..., watchdog_timeout_s=15.0)
```
Off par défaut. Activer en prod si le master est censé pinger en continu.
## Hardware
Câblage Kogger côté antenne (recopié du README upstream pour référence) :
| Couleur | Signal |
|---|---|
| Brown | +V supply |
| Blue | GND |
| Green | UART RX (USBL ← host) |
| Yellow | UART TX (USBL → host) |
| Pink | GND (relié au bleu interne) |
| Gray | TRIGGER_IN |
| White | TRIGGER_OUT |
Connexion typique : `Pi4B → USB-UART converter → antenne Kogger`. Baudrate par défaut 921600.
## Limites / TODO
- [ ] Pas testé sur hardware réel (uniquement statique). Cf. test sur AUV-2 cosma au prochain déploiement.
- [ ] Pas de gestion de reconnexion USB-UART. Si le port disparaît, le process meurt — relancer côté systemd.
- [ ] Pas de support multi-port (un wrapper = une antenne). Pour multi-antennes sur un même Pi, instancier N `ContinuousTransponder` indépendants.
- [ ] L'écoute passive OWR (calcul de distance par non-ciblés à partir de `T_recv T_send`) n'est **pas** dans ce wrapper — elle nécessite une référence temporelle synchronisée USV↔AUVs et l'extraction de `T_send` depuis la trame du ping (pas exposé proprement par le driver upstream pour l'instant). À ajouter quand le besoin se présente.
- [ ] Ajouter un `start()` idempotent (actuellement appeler 2× réenroule les callbacks).
## Références
- Driver upstream : `git@github.com:cosma-tech/kogger_acousticAntenna.git`
- Page démo USBL DS-TWR + SS-TWR + OWR : <https://laboratoire.freeboxos.fr/ping-pong-ping/>
- Repo demo : `poulpe/ping-pong-ping` sur Gitea
- Conversation Discord d'origine : `#ping-pong-ping` (2026-04-27)