Reinforcement learning ◆ Guidance & control ◆ MuJoCo ◆ NYU ROB-GY 7863 ◆ 2025
Thrust-Integrated Neural Touchdown: a 5,000-tonne lunar lander, 100 m long, one gimbaled engine. Landings below — then fly it yourself.
Six touchdowns, cut together. The vehicle is the rocket from The Adventures of Tintin, at 5,000 t and 100 m; every arrival below is a real descent flown in MuJoCo.
Every clip is one real MuJoCo descent of the 5,000-tonne vehicle that ended on the pad — no scripted trajectories, live telemetry in the corner, playback speed in the top right. Clips that share a starting condition are the same descent from a different camera. Filter by controller or by camera.
Loading the landings…
How many attempts each of these took, straight from the render log: 30 m hover 2 landings in 2 tries, 45 m 2 in 3, 6–10 m downrange 2 in 9, 4° of entry tilt 2 in 2 — and 1 m/s of entry speed 1 in 24. Altitude and offset are cheap; arriving with velocity is not. The four SAC clips are the 1.5 M-step policy on the same hover start, where it lands about one attempt in three. One rung further up the ladder nothing lands at all, and that is the interesting part.
One policy sees the state and emits throttle and two gimbal angles — guidance and control as a single map. Burning 4,500 t of 5,000 t changes the plant underneath the controller as it flies.
The same vehicle in your browser — 5,000 t, one 25 MN engine on a ±30° gimbal 30 m below the centre of mass — tracking MuJoCo to 1.3 m over a 45 s descent. Fly it, or hand it to the PD or to any SAC checkpoint.
Drag to orbit, scroll to zoom. Vehicle randomisation resamples mass, propellant, Isp, engine, gimbal gain, a gimbal misalignment up to 2.5° and a small body rate — the envelope the policy trained against. The last two are the ones that matter (why).
Altitude against downrange, speed against descent rate, tilt against gimbal, throttle against propellant — live as it flies.
Green lands inside the box — 10 m, 3 m/s, 25°; red does not. The bundle is drawn into the scene above.
Press the button.
The clips above are hover starts. One rung up the ladder — 60 m, 10 m of offset — both controllers land 0 % of the time. Building the 3-D PD (scripts/tools/pd3d.py) turned up why, and the last two are the ones worth reading.
One parameter randomised at a time, 60 m straight down, ten descents each: mass ±20 %, thrust ±20 %, gimbal gain ±15 % and the whole sensor-noise budget each leave it at 10/10. A persistent 2.5° gimbal misalignment takes it to 0/10 (median touchdown tilt 36.1°), and so does an initial body rate of 0.04 rad/s (36.5°). Both are attitude disturbances, and both are tiny.
Gimbal torque is τ = L·T·sin θg, proportional to thrust. An efficient descent wants the throttle low — at 8 % throttle the attitude loop has 8 % of its authority and demands three times the torque available. It saturates at ±30°, overshoots, saturates the other way, and the vehicle limit-cycles: tilt sawtoothing 0–33° every eight seconds with the descent stalled at 35 m. Holding a thrust floor fixes the attitude and runs the 45 s clock out instead: 10/10 landings become 1/10. Attitude authority wants thrust; an efficient descent wants none — which is the argument for integrated guidance and control the project is about.
SAC on the same MuJoCo vehicle, randomised every episode: dry mass ±20 %, propellant ±35 %, Isp ±12 %, engine ±20 %, gimbal gain ±15 %, a permanent gimbal misalignment up to 2.5°, an initial body rate, and noise on what the policy sees. 1.5 M steps, 10 parallel envs.
train_freq is per-env — 10 envs × 32 is 320 samples per call, and 8 gradient steps against that is one per forty samples. 80 changed the whole curve.| SAC on RocketGym-DR | value |
|---|---|
| Policy network | [256, 256] MLP |
| Observation / action | 17 / 3 |
| Learning rate | 3×10⁻⁴ |
| Batch / buffer | 256 / 6×10⁵ |
| γ / τ | 0.985 / 0.005 |
| train_freq / gradient_steps | 32 / 80 |
| Parallel MuJoCo envs | 10 |
| Environment steps | 1.5 M, at 20 Hz control |
Median arrival speed falls from 16.3 m/s at 1 k steps to 5.3 m/s by 50 k, median touchdown offset from 78.9 m to 18.7 m, and success on the curriculum's own conditions peaked at 47.5 % near 750 k. On the fixed held-out envelope it lands 0 % at every checkpoint — so does the PD. 1.5 M steps under this much randomisation is not enough; the report used 5 M on an easier box.
Every number and figure on this page regenerates from scratch with fixed seeds, in the project repository.
The browser model in assets/js/tintin3d.js is a transliteration of the MuJoCo vehicle — same inertia, same RK4 at 100 Hz, the same second-order gimbal servos (ωn = 54.5 rad/s, ζ = 0.30) and the measured tilt-dependent contact height. Replaying identical actions through both, the trajectories stay within 1.29 m over 45 s. Landing clips: scripts/tools/render_landings.py.
TINTIN was the Project 2 of ROB-GY 7863 at NYU, taught by Prof. Benjamin Rivière. Joint work with Juncheng Zhou — equal contribution. The vehicle geometry is adapted from the rocket in The Adventures of Tintin; the lunar terrain is an imported Unreal Engine asset.
The MuJoCo environment, the SAC/PPO/DQN training, the report and its figures are from the course project. The planar re-implementation, the 500-descent PD study, the gain and envelope sweeps, and the browser sandbox on this page were built afterwards for this write-up.