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:
2026-04-27 22:08:44 +00:00
commit 9a158f5c5f
53 changed files with 7894 additions and 0 deletions

111
driver/log_merge_nav_usbl.py Executable file
View File

@@ -0,0 +1,111 @@
#! /usr/bin/env python
import csv
import glob
import os
from datetime import datetime
import sys
def merge_log_files(nav_file, usbl_file, output_file):
"""
Merges navigation and USBL log files into a single CSV file with the format:
timestamp,data,value
Args:
nav_file (str): Path to the navigation log CSV file.
usbl_file (str): Path to the USBL log CSV file.
output_file (str): Path to the output merged CSV file.
"""
try:
all_lines = []
# Read the navigation log
with open(nav_file, 'r') as f:
reader = csv.reader(f)
header = next(reader) # Skip header
for row in reader:
all_lines.append(row)
# Remove last line if broken
if len(all_lines[-1]) != 3:
all_lines.pop()
# Read the USBL log
with open(usbl_file, 'r') as f:
reader = csv.reader(f)
for row in reader:
timestamp, data, value = row
if timestamp == "timestamp":
# Remove timestamp header if present (in merge from other merge)
continue
data = 'usbl_' + data
if data == 'usbl_ID':
value = str(int(float(value)))
all_lines.append([timestamp, data, value])
if len(all_lines[-1]) != 3:
all_lines.pop()
# Sort by timestamp
all_lines.sort(key=lambda x: datetime.strptime(x[0], '%Y-%m-%d %H:%M:%S.%f'))
# Write to CSV
with open(output_file, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['timestamp', 'data', 'value'])
writer.writerows(all_lines)
print(f"Successfully merged {nav_file} and {usbl_file} into {output_file}")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
try:
if len(sys.argv) == 2:
input_file_path = sys.argv[1]
target_directory = os.path.dirname(input_file_path)
if target_directory == "":
target_directory = "."
filename_only = os.path.basename(input_file_path)
base_name = "_".join(filename_only.split('_')[:3])
if not base_name:
raise ValueError("Could not parse base name from filename.")
print(f"Processing specific files for base name: {base_name}")
nav_log_file = os.path.join(target_directory, f'{base_name}_navigation_log.csv')
usbl_csv_file = os.path.join(target_directory, f'{base_name}_usbl_csv.csv')
output_filename = os.path.join(target_directory, f'{base_name}_merged_log.csv')
print(f"Merging {nav_log_file} and {usbl_csv_file} to {output_filename}")
merge_log_files(nav_log_file, usbl_csv_file, output_filename)
elif len(sys.argv) == 3:
nav_file = sys.argv[1]
usbl_file = sys.argv[2]
nav_basename = os.path.splitext(os.path.basename(nav_file))[0]
usbl_basename = os.path.splitext(os.path.basename(usbl_file))[0]
output_dir = os.path.dirname(nav_file)
if not output_dir:
output_dir = "."
output_filename = os.path.join(output_dir, f"{nav_basename}_{usbl_basename}_merged.csv")
print(f"Merging {nav_file} and {usbl_file} to {output_filename}")
merge_log_files(nav_file, usbl_file, output_filename)
else:
print("Error: Invalid number of arguments. Please provide 1 or 2 arguments.")
print("")
print("Usage:")
print(" 1 argument: python log_merge_nav_usbl.py <any_log_file_from_session>")
print(" (This will find navigation and usbl logs from the same session and merge them)")
print(" 2 arguments: python log_merge_nav_usbl.py <navigation_log_file.csv> <usbl_log_file.csv>")
print(" (This will merge the two specified files)")
sys.exit(1)
except FileNotFoundError as e:
print(f"Error: File not found: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")