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

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 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

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

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 :

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.

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)
Description
Wrapper Python haut niveau autour du driver Kogger USBL pour mode transpondeur permanent. Aucun re-armement par ping.
Readme 132 KiB
Languages
Python 100%