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.
This commit is contained in:
143
README.md
Normal file
143
README.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user