Stonefish native station hold
A Girona 500 underwater vehicle moves 1.5 m north, 1.0 m east and 1.5 m deeper, turns to heading 045 and holds that station for 15 seconds in the Stonefish marine simulator.
This is an authored variant of the upstream Tests/UnderwaterTest example, with the example’s ocean currents disabled.
Upstream ships no controller, success check or reward for this test. The controller and the pass criteria were written for this site.
Native video · Native verification · Reproduction notes (repository access required)
What the recording establishes
| Item | Recorded evidence |
|---|---|
| Upstream example | Stonefish 1.5.0 at commit 7d526737, Tests/UnderwaterTest. At this commit PARSED_SCENARIO is commented out, so the programmatic branch of BuildScenario is what compiles: one Girona 500 with a four-joint arm, a heightfield seabed, one cylinder and two lights. The parsed scenario file with several vehicles is not read by this binary. |
| Authored changes | Currents disabled; fixed 0.005 s stepping in place of the wall-clock thread; a world-fixed native camera; a fixed seed for sensor noise; a four-axis PID controller on the native Odometry sensor; the start-up console thread replaced by a no-op; journals. Upstream source files, meshes, textures, masses, thruster models and sensor placement are unchanged. |
| Why currents are disabled | The compiled scenario has a 1 m/s current toward north and a 5 m/s jet. With zero command the vehicle drifted 17.9 m in 20 s. With both surge thrusters at full astern for 10 s it was still moving north at 0.65 m/s over ground. The compiled thrusters cannot hold station in the compiled current. |
| Declared criteria | Frozen before any controller run: at every physics step from 25 s to 40 s, horizontal error ≤0.10 m, depth error ≤0.10 m, heading error ≤0.0873 rad and speed ≤0.10 m/s; over the whole 40 s, zero contact points, depth ≥0.8 m, roll and pitch ≤0.35 rad, all values finite. |
| Measured hold | Passed. Maxima over the 3,001 hold-window physics steps: horizontal error 0.0355 m, depth error 0.0128 m, heading error 0.0127 rad, speed 0.0163 m/s. Over the whole run: zero contact points, minimum depth 1.914 m, maximum roll or pitch 0.211 rad. The vehicle is positively buoyant; at the end each heave thruster holds about 48 N. |
| Independent replay | A fresh native process with no controller and no camera applied the 2,000 recorded command rows at their recorded physics steps. All 380,108 compared scalars (108,108 in 1,001 samples and 272,000 in 8,000 physics-step rows) are exactly equal; the declared tolerance was 1e-9. The predicate evaluates to the same result on the replayed journal. |
| Video | 1,001 native RGB frames, 960 × 540, 25 fps; 2,904,552-byte H.264 file lasting 40.04 s. Every decoded frame was compared with its native frame; minimum PSNR 42.95 dB against a 35 dB floor. |
| Counted as | One simulation recording. Zero upstream registered tasks, learned-policy evaluations, benchmark scores or browser world assemblies. |
Controller and what it may read
The controller is a PID on four axes: north, east, down and heading. It reads only the vehicle’s native Odometry sensor.
The compiled scenario sets no noise on that sensor, so the controller sees exact simulator position, body velocity, attitude and yaw rate. That is privileged state, not an estimated navigation solution.
The noisy pressure, DVL, IMU, compass and GPS channels are recorded but not used for control.
Efforts are clamped to [-1, 1], mixed to the five thrusters and passed through a signed square root before being written as normalized thruster setpoints.
Gains were chosen in one grid of eight development runs, all scored with the already frozen criteria. Six met them and two did not.
The set with the smallest hold error was frozen, then the single capture was made.
The protocol file lists every development run, including eleven open-loop runs used to read thruster signs and authority.
Time, state and commands
Physics runs at 200 Hz as in the upstream main.cpp. Commands are issued at 50 Hz and held for four physics steps.
Sample 0 is the state after the native initial-condition solve, before any command. Sample i and camera frame i follow physics step 8·i.
State and camera clocks are therefore 25 Hz, and encoded frame i has presentation time i/25 s.
The 40-second horizon is authored. No reward or end signal is recorded because the source defines none.
Native samples keep the vehicle origin pose and velocity and six scalar sensors: Odometry, pressure, DVL, IMU, compass and GPS.
They also keep per-thruster setpoint, rotor speed, thrust and torque, arm servo state, water velocity at the vehicle and contact counts.
Physics-step rows keep pose, velocity, thrusters and contacts for all 8,000 steps. The outcome is computed from these.
Command rows keep each issued setpoint with the controller’s error, integral and effort terms.
Stonefish works in NED: x north, y east, z down, metres and radians, with xyzw body-to-world quaternions. Those values are published unchanged.
The generic body pose used by the player is the same frame rotated 180 degrees about x: x north, y west, z up, wxyz order.
The conversion was checked against the rotation-matrix form for all 1,001 poses; maximum difference 0.
Original inputs
The pinned Stonefish tree supplies 951 verified files / 126,959,720 bytes, extracted from Git objects into a tree the build only reads.
The input receipt keeps Git identities, modes, sizes and SHA-256 hashes.
It binds the 15 data files the compiled branch names: 11 OBJ meshes, three textures and the seabed heightmap, 13,061,051 bytes in all.
No geometry was exported or converted. Meshes and textures stay in the native checkout.
The build uses the pinned CMake defaults (Release, C++20) with SDL2 2.30.0 and GLM 0.9.9.8 under a task-local prefix. No system package was installed or upgraded.
Rendering used an OpenGL 4.3 core context on an NVIDIA RTX 4090 (driver 580.173.02) through VirtualGL 3.1.3’s EGL back end. Xvfb supplied only the X11 window.
The pinned CMake file links OpenMP but does not compile with it, so the library’s parallel loops run serially in this build.
Faults worked around
Two faults were observed and worked around without editing upstream files.
- The start-up console is drawn by a second thread with its own GL context. Through VirtualGL this faulted inside the NVIDIA driver and corrupted the heap in most runs. The adapter replaces that thread with a no-op.
- Scenario teardown faults after the GL context is released. The adapter ends the process once its journals are closed.
Counts and the fault traces are in the runtime record.
The unchanged upstream binary’s start-up log and window capture are kept as an upstream check. A start-up earns no recording credit.
Attribution and limits
Stonefish is written by Patryk Cieślak and contributors and is licensed under GPL-3.0-or-later.
Its 3rdparty folder bundles other code with its own notices. The receipt counts notices per file.
- Bullet Physics, tinyxml2 and tinyexpr: zlib-style notices.
- tinyspline: MIT notice.
- stb_image and stb_image_write: public-domain statement in the file.
- A generated glad loader: no notice in the file.
The pinned tree contains no licence or attribution statement specific to the Girona 500 model, its meshes and textures, or the two bundled fonts. Those terms are not stated here.
This site generated the video and measured-state recording. It does not redistribute Stonefish, its binaries or its model files.
One authored hold in still water with a controller that reads exact simulator state does not establish station keeping in a current, navigation from real sensors, or any benchmark result.
Replay equality is established for this host, build and seed.