How an underwater robot writes things down
Five animated patterns that describe how autonomous underwater vehicles organize their data as ROS 2 messages and topics — and why, once you know them, a multi-terabyte mission recording is just a well-behaved dataset.
An autonomous underwater vehicle (AUV) on a long mission is cut off from the world: radio doesn't travel through seawater, so for days or weeks the vehicle simply records. What it records is not a pile of text logs. Modern vehicles run ROS 2, and everything every sensor says is written into a bag — a self-describing binary archive of typed, timestamped messages organized by topic. Surveying the drivers, simulators, message standards, and public datasets of the marine robotics world turns up the same handful of structural patterns over and over. Here are the five that matter, animated.
New to the jargon? Every dotted term is clickable — each opens a short three-part explanation: the technical definition, a plain-English version, and what the thing is actually used for. A full glossary sits at the bottom of the page.
Many sensors, few message types
What you're watching: each sensor on the vehicle publishes its readings as messages on a named topic, and the bag recorder subscribes to everything and writes it all into one file. The message types flying by are not invented per vehicle — they come from a small shared vocabulary. Across every driver, simulator, and dataset surveyed, the same core set covers nearly everything:
| Message type | What it carries | Typical rate |
|---|---|---|
sensor_msgs/Imu | attitude, angular rates, acceleration | 100–333 Hz |
nav_msgs/Odometry | the fused navigation solution | 10–50 Hz |
sensor_msgs/FluidPressure | depth | 30–60 Hz |
sensor_msgs/NavSatFix | GPS — only when surfaced | episodic |
| DVL message (see Pattern 3) | velocity over the seabed, altitude | 2–15 Hz |
sensor_msgs/Image / CompressedImage | cameras and imaging sonar | 1–20 Hz |
sensor_msgs/PointCloud2 | multibeam / 3-D sonar | 1–10 Hz |
sensor_msgs/LaserScan | profiling & scanning sonar | 1–10 Hz |
sensor_msgs/BatteryState | power system telemetry | ~1 Hz |
tf2 transforms | the frame tree tying it all together | with nav |
Learn roughly a dozen message types and you can read the recordings of nearly any vehicle — regardless of who built it. The data vocabulary is small; the volume is what's big.
Every topic keeps its own clock
What you're watching: eight real topics publishing at their characteristic rates. The hierarchy is remarkably consistent across vehicles — inertial sensing fastest, then depth, the fused nav solution, cameras, the Doppler velocity log, sonar frames, health telemetry, and finally the acoustic modem, which manages about thirty bytes every four seconds. The bars are on a log scale; within seconds they sort themselves into the same pyramid you'd find in any real mission bag.
This is the single most important thing to internalize before analyzing this data: a bag is not one table. It is a bundle of independent time series, each at its own rate, sharing nothing but a clock. Any cross-sensor question — what was the battery doing when the vehicle was at 40 m depth? — is a time-alignment problem: resample or as-of-join on timestamps, then analyze.
One DataFrame per topic, aligned on time. That's the entire mental model — and time-series alignment is a solved problem in the pandas ecosystem (merge_asof, resampling).
Where standards are missing, conventions grow anyway
What you're watching: there is no official ROS 2 message for a Doppler velocity log — the workhorse sensor of underwater navigation. Instead, five independent projects (a Swedish research fleet, two simulators, a community driver, and a multi-institution standards effort) each defined their own. Cycle through them and the field list barely moves: a header, a 3-D velocity vector, a covariance matrix, an altitude, and a per-beam array.
The same story repeats elsewhere. Imaging sonar has no standard message either — in practice it travels as sensor_msgs/Image, or as a vendor message published alongside a standard-type twin topic. And the whole marine domain is permanently bilingual between ROS's east-north-up coordinate convention and the maritime world's north-east-down, resolved by suffixing frames (odom_ned).
Missing standards are not chaos — they're convergent evolution. For an analyst the practical consequence is even better: bag files embed the schema of every custom message inside the file, so even a message you've never seen deserializes cleanly. The adapters you have to write are thin.
The public data landscape has an empty bin
What you're watching: the marine datasets that exist in public, sorting themselves into bins. Academic navigation datasets ship as legacy rosbag1 files. Industrial and institutional missions (Kongsberg HUGIN surveys, WHOI's Sentry, MBARI, NOAA archives) publish in vendor formats — .kmall, XTF, SEG-Y, netCDF. Sonar machine-learning datasets are distributed as plain image files, stripped of their context. And the modern format, rosbag2/MCAP, has essentially no established public data at all.
That empty bin is an opportunity. Anyone who can bridge the gap — convert legacy bags forward, parse vendor formats, and build first-look tooling for MCAP mission data — is working in territory the public tooling hasn't reached yet.
The bandwidth pyramid: terabytes on board, kilobytes ashore
What you're watching: an entire long-endurance sortie compressed into a loop. Underwater, side-scan and synthetic-aperture sonar accumulate on the order of 60–250 GB per surveying hour, so the onboard disk climbs toward tens of terabytes. Meanwhile the only paths to shore mid-mission are an acoustic modem at a few kilobits per second and satellite bursts of a few hundred bytes — roughly nine orders of magnitude narrower than the disk. Only when the vehicle is recovered does the flood arrive.
This single constraint shapes the entire software stack: onboard edge processing must reduce raw sensor data to tiny contact reports and health summaries the operator can act on now, and post-mission analysis must digest the full terabytes fast once they land — which questions did the mission answer, what did the detectors find, how is the vehicle aging.
The scarce resource isn't data — it's the time of whoever makes sense of it. That's a data engineering problem, and it's the one I find most interesting.
From bag to DataFrame in fifteen lines
The payoff of these five patterns: mission data that looks exotic from the outside is, structurally, a well-organized multi-rate time-series database. Because bags are self-describing, they open with an ordinary pure-Python library — no robot, no ROS installation — and each topic falls out as a tidy table:
from pathlib import Path
import pandas as pd
from rosbags.highlevel import AnyReader
rows = []
with AnyReader([Path("mission_bag")]) as reader:
conns = [c for c in reader.connections if c.topic == "/fuel_cell"]
for conn, timestamp, raw in reader.messages(connections=conns):
msg = reader.deserialize(raw, conn.msgtype)
rows.append({"t": timestamp / 1e9,
"voltage": msg.voltage,
"current": msg.current,
"temp": msg.temperature})
df = pd.DataFrame(rows).set_index("t") # and now it's just data science
From here it's resampling, as-of joins, anomaly detection, dashboards, and model-building — the standard toolkit, pointed at an unusually interesting ocean.
Every term, three ways
All 34 terms used on this page now live on their own page, each defined three ways — technical, plain English, and what it is actually used for — and each with a full infographic panel. The dotted terms above still explain themselves in place; the glossary is there when you want to read or search the whole vocabulary at once.