1 · The brief
September 9, 2026, 12:50 PDT · a new goal, from a static scene to a finished video
The request was for the smallest MuJoCo simulation that shows a legged robot walking into water and out again, and how leg-mounted float attachments work. It needed no radio links and no autonomy: just the route in and out, the attachments doing their job, and a video of the whole crossing.
Two pieces of steering from the user shaped the result. Rock-like obstacles were added to the banks and then removed at the user's request, so the scene would show what it is really about; the banks became smooth 15.2° ramps. The user also asked two direct questions. Was the robot using walking dynamics already programmed for it? And did the front legs reach forward so the floats pointed ahead with them? The second question led to a correction: the float posture was changed so that both front legs, and their floats, extend forward. Chapter 4 covers both answers.
Robot
- Unitree Go2 physical model from MuJoCo Menagerie, used as a stand-in
- Unarmed; vendor mass 15.206 kg
- Four float capsules add 1.8 kg, for 17.006 kg in total
Course
- Start at x = −2.55 m on a level bank, finish at x = 3.95 m
- Two 1.4 m ramps at 15.2°, bed at −0.38 m
- Waterline at −0.14 m: 0.24 m of water in the middle
Not in scope
- Radio, perception or autonomy
- Waves, CFD or a fluid mesh
- A calibrated replica of any real hardware
2 · Four floats on the thighs
September 9 · rigid attachments; the vendor model left as shipped
Each thigh carries one capsule float: radius 0.085 m, a 0.20 m straight section, 0.37 m overall, about 7.11 L. It is a rigid child body of the thigh, mounted 0.14 m outward and 0.07 m below the thigh joint, so it turns with the upper leg. There is no separate deployment joint: the floats point forward when the legs do. Each capsule has a mass of 0.45 kg and its own capsule inertia. The straps, brackets and thruster shells are drawn with zero mass; their mass is counted inside that allowance.
The Go2 model stays as Menagerie ships it: inertias, joint limits and meshes are untouched, and all 22 vendor files match a SHA-256 manifest. Our changes are made where the scene is assembled: the floats, a stiffer foot contact (chapter 6), and actuator force limits that enforce the motor torque caps. The floats are real collision shapes, not decoration.
| Property | Value |
|---|---|
| Vendor Go2 mass | 15.206408 kg |
| Floats | 4 × 0.45 kg = 1.8 kg |
| Total mass | 17.006408 kg, weight 166.83 N |
| Capsule | radius 0.085 m, straight section 0.20 m, overall 0.37 m, about 7.11 L |
| Mount | rigid on the thigh, 0.14 m lateral, 0.07 m below the thigh origin |
| Torque caps | abduction and thigh ±23.7 N·m, knee ±45.43 N·m, in both the control range and the actuator force limit |
| Joint limits | inherited from the Go2: abduction ±1.0472 rad, knee −2.7227 to −0.83776 rad |
| Integration | 2 ms implicitfast; control at 100 Hz; water forces every step (500 Hz) |
3 · A water model from sampled volume
September 9 · buoyancy and drag on each float, rebuilt and applied every physics step
MuJoCo supplies rigid-body dynamics and contact, but no water. Its built-in fluid models act as a medium filling the whole scene, so we added localised forces instead. Each capsule is filled with sample points on a 25 mm grid, weighted to the capsule's exact volume. A sample counts as wet below the waterline at −0.14 m, with a 25 mm smooth transition, and only inside the basin. The wet fraction gives the buoyancy, F = ρ g Vsubmerged with fresh water at 1,000 kg/m³, applied at the centre of the submerged volume. A float riding lower than the others therefore also rolls or pitches the body. The central body is treated as a sealed hull of about 4.01 L, matching the base collision box.
Drag acts at the same point: linear plus quadratic, −f(7v + 12|v|v), and rotational,
−f(0.20ω + 0.10|ω|ω), where f is the submerged fraction. The coefficients are chosen to dissipate
energy; they are not tank measurements. The five contributions (four floats and the hull) and the thrusters are
cleared and rebuilt at every 2 ms step and applied with mj_applyFT, so no stale force carries over
from one step to the next.
The still-water check
Before any wading, an isolated test places the robot in its float posture over the middle of the basin and runs 7,000 steps of 2 ms. Then it runs again with buoyancy switched off.
Another test pins the model down. Fully submerged, the total buoyancy equals ρ g times the summed volume of the four capsules and the hull, and with the body moving the drag power is negative.
4 · A scripted crawl and a float posture
September 9 · programmed control on a known course; nothing is learned
The walking is a slow crawl written for this scene, with one leg in the air at a time, in the order rear-left, front-left, rear-right, front-right. Before each step the body shifts its centre of mass over the three supporting feet (to within 4.5 cm, or for at most 2 s). The swing leg then moves 12 cm forward in 0.65 s with a 7 cm lift. The next step waits until that foot reports contact, after at least 0.2 s and at most 0.9 s. Inverse kinematics turns foot targets into joint targets. Each motor applies 120 N·m/rad stiffness and 4 N·m·s/rad damping plus gravity and contact-force feedforward, clipped to its torque cap. The body pitches to follow the ramp, and as the robot wades deeper, the feedforward subtracts the current buoyancy from the weight the feet must carry.
The course is known in advance. The controller reads exact ramp heights from the scene definition and walks a fixed lane. That is a scripted terrain fixture, not perception.
Front legs forward
When the body passes x = 0.10 m, in the deep middle of the basin, the controller stops stepping and moves the joints, at up to 0.8 rad/s, to the float posture. The front thighs go to −1.50 rad and the knees to −0.90 rad, so the front legs reach forward; the rear legs fold at 1.30 and −2.50 rad. The floats turn with the thighs. In this pose the front floats point about 99.7% forward and 7.1% downward relative to the body. A test checks the pose against the joint limits and checks the float direction. At x = 1.60 m the exit phase begins: the feet are placed back under the hips and the stepping order restarts.
| Phase | Starts at (s, simulated) | Body x (m) | Switch |
|---|---|---|---|
| Approach | 2.00 | −2.57 | after a 2 s settle |
| Water entry | 75.79 | −1.60 | top of the entry ramp |
| Floating | 225.59 | 0.10 | deep middle of the basin |
| Exit | 238.22 | 1.60 | near the exit ramp |
| Complete | 443.01 | 3.96 | past the 3.95 m finish, nearly stopped |
Phases switch on the measured body position along the known course. The thrusters (next chapter) are gated by measured float immersion instead.
5 · Idealised thrusters
September 9 · forces applied by feedback, with nothing simulated behind them
Floating needs propulsion, and the robot has no propellers. Two thrust points sit at the rear of the body, 0.21 m behind its centre and 0.10 m to each side. Each applies a force along the body's forward axis, capped at ±6 N. That is all they are: idealised applied forces. No propeller, paddling leg, wake or reaction flow is simulated.
A feedback loop sets them, with a forward-speed target of 0.17 m/s while floating and 0.055 m/s while wading, and a differential term that holds heading and lane. They act only inside the basin and only when the floats are wet: the force scales with mean float immersion and reaches full strength at 25%. On dry land no propulsion is applied at all. A test commands 6 N on both thrusters with the robot standing on the bank and checks that no force reaches the chassis.
6 · What went wrong on the way
September 9 · four failures fixed during the build, and one change of scope
Several failed runs came before the crossing completed. Each fix changed physics settings or control. No test threshold was relaxed.
solref 0.01/1 and
solimp 0.95/0.99/0.001 with no margin. The deepest ground penetration in the final crossing is
6.9 mm.7 · Results
September 9, 13:30 PDT · one complete crossing, validated twice and recorded
| Measured in the final crossing | Value |
|---|---|
| Success: finished, floated over 2 s unsupported, 4 feet down, buoyancy under 1 N at the end | yes |
| Simulated time, including a 3 s final settle | 446.0 s |
| Wall time for the run | 67.4 s |
| Longest / total unsupported float | 10.816 s / 11.010 s |
| Peak buoyancy (weight 166.83 N) | 170.99 N |
| Final buoyancy; feet touching | 0 N; 4 / 4 |
| Finish line x = 3.95 m crossed at | 443.01 s |
| Final body x, after settling back about 4 cm | 3.92 m |
| Deepest ground penetration | 6.9 mm |
| Lowest body up-vector (largest tilt about 16.9°) | 0.957 |
| Peak motor torque, fraction of cap | 100% |
| Float contact with terrain | rear-left float, entry ramp |
| MuJoCo warnings | 0 |
On Apple Silicon macOS, all 20 tests passed (16 from the earlier demos plus 4 new), the native viewer smoke test passed, and all 22 vendor file hashes matched. The final video is 1920 × 1080 at 25 fps, 1,712 frames and 68.48 s; its full stream decoded without errors, and the entry, floating, climb and final frames were checked by eye. This page plays a web re-encode of that video.
The goal took 40 min 5 s of elapsed time, from 12:50:04 to 13:30:09 PDT, including the user's steering, development, failed experiments, tests, rendering and communication. MuJoCo ran on the CPU, and nothing was trained.
8 · Next steps
What one scripted crossing on one known course does not yet show
Float sizes, drag coefficients and the sealed hull are assumptions. This is a concept demonstration in simulation, not a calibrated replica of any hardware.