# 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 : - Repo demo : `poulpe/ping-pong-ping` sur Gitea - Conversation Discord d'origine : `#ping-pong-ping` (2026-04-27)