Instructions to use physicalai-bmi/orbital-landing-tgo with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use physicalai-bmi/orbital-landing-tgo with Keras:
# Available backend options are: "jax", "torch", "tensorflow". import os os.environ["KERAS_BACKEND"] = "jax" import keras model = keras.saving.load_model("hf://physicalai-bmi/orbital-landing-tgo") - Notebooks
- Google Colab
- Kaggle
orbital-landing-tgo
A learned powered-descent guidance net — 1,281 parameters — that lands a vehicle on the Moon, Mars, or Earth from one forward pass, with no flight plan and no clock. It matches the analytic optimal guidance it was distilled from (91.7% vs 90.8% on a held-out benchmark) while touching down at 0.03 m/s, 0.00 m from the pad.
Institute for Physical AI @ BMI · The Charlot Lab · Technical Report TR-2026-17
- Live, in-browser: physicalai-bmi.org/assets/sims/landing — the precision-landing instrument, "Learned" mode.
- Code + physics core + benchmark: github.com/dcharlot-physicalai-bmi/orbital-logistics (
policy/,bench/landing_bench.mjs).
What it is, and why it is shaped this way
ZEM/ZEV is the classic closed-form powered-descent law — but it needs a time-to-go. Classically you search for a flight time before ignition and then fly that clock down, which makes the guidance a function of the schedule rather than of the vehicle's state.
It does not have to be. For a fixed tgo, the minimum-energy cost of the ZEM/ZEV solution is itself closed-form:
J(tgo) = 12|ZEM|²/tgo³ − 12(ZEM·ZEV)/tgo² + 4|ZEV|²/tgo
so the optimal time-to-go can be solved from the state at every step — no clock, no plan. That scalar minimisation is then the only expensive part of the loop, and it is exactly what this net replaces.
The net predicts the time-to-go; the closed form does the rest.
- Input (5):
[dx, dy, vx, vy, g]— position relative to the pad (m), velocity (m/s), the body's gravity (m/s²). One net spans Moon / Mars / Earth. - Output (1):
tgo— the optimal time-to-go (s). Feed it to ZEM/ZEV, clamp to the engine limit, fly. - Arch:
5 → 32 → 32 → 1, ReLU, input/output normalization. 1,281 parameters.
The finding: factorization beat the training algorithm
Cloning the thrust directly is the obvious approach and it fails. The ZEM/ZEV gains go as 6/tgo², so the target is stiff exactly at touchdown, where being wrong matters most — and a smooth net cannot track it. DAgger (rolling out the learner, relabelling with the expert) helps a lot but plateaus well short:
| Approach | soft landings (held-out, 120 starts) | miss | touchdown |
|---|---|---|---|
| Clone thrust — plain behavior cloning | 9/120 | — | — |
| Clone thrust — + DAgger, 6 rounds | 72/120 | 0.12 m | 1.05 m/s |
| Clone the time-to-go (this model) | 110/120 | 0.00 m | 0.03 m/s |
The time-to-go model reached 109/120 at round 0 — plain behavior cloning, before any DAgger. Choosing the right seam to cut the controller at mattered far more than the training algorithm: learn the part that is expensive and smooth, keep the part that is cheap and exact.
Benchmark (Landing-Bench, 120 fixed starts)
| Guidance | success | mean miss | touchdown | mean Δv |
|---|---|---|---|---|
| Scheduled ZEM/ZEV (search a flight time, fly the clock) | 95.0% | 0.03 m | 0.45 m/s | 139 m/s |
| Clock-free ZEM/ZEV (solve tgo every step) | 90.8% | 0.00 m | 0.02 m/s | 159 m/s |
| Learned · thrust (1,346p) | 60.0% | 0.12 m | 1.05 m/s | 142 m/s |
| Learned · tgo (this model) | 91.7% | 0.00 m | 0.03 m/s | 160 m/s |
Reproduce with node bench/landing_bench.mjs. Note the honest trade the benchmark exposes: the scheduled search still wins on success rate and fuel, because on thrust-marginal starts it can find some feasible flight time where the energy-optimal tgo demands more thrust than the engine has. The clock-free family buys an order of magnitude in precision, and needs no plan, for about 15% more Δv.
Use
Everything the runtime needs is in land_policy.json (W1,b1,W2,b2,W3,b3 and the xm/xsd/ym/ysd normalization; mode: "tgo"). The net is one forward pass; ZEM/ZEV is four lines:
const P = await (await fetch('land_policy.json')).json();
const mv = (W,a)=>W[0].map((_,j)=>a.reduce((s,ai,i)=>s+ai*W[i][j],0)), relu=z=>z.map(v=>v>0?v:0);
function tgo(obs){ // obs = [dx, dy, vx, vy, g]
const x = obs.map((v,j)=>(v-P.xm[j])/P.xsd[j]);
const a1 = relu(mv(P.W1,x).map((v,j)=>v+P.b1[j]));
const a2 = relu(mv(P.W2,a1).map((v,j)=>v+P.b2[j]));
return Math.max(0.5, mv(P.W3,a2).map((v,j)=>v+P.b3[j])[0]*P.ysd[0]+P.ym[0]);
}
function thrust(r, v, rT, g, aMax){ // r,v,rT,g are 2-vectors; g = [0,-grav]
const t = tgo([r[0]-rT[0], r[1]-rT[1], v[0], v[1], -g[1]]);
const zx = rT[0]-(r[0]+v[0]*t+0.5*g[0]*t*t), zy = rT[1]-(r[1]+v[1]*t+0.5*g[1]*t*t);
const ex = -(v[0]+g[0]*t), ey = -(v[1]+g[1]*t);
let a = [6/(t*t)*zx - 2/t*ex, 6/(t*t)*zy - 2/t*ey];
const am = Math.hypot(...a);
return am > aMax ? a.map(x => x*aMax/am) : a;
}
Honest scope
This is a research demonstrator, not flight software. The dynamics are a planar double integrator under constant gravity with a hard thrust limit; there is no attitude loop, no mass depletion, no navigation error, no atmosphere. The pad is assumed known and the guidance is unconstrained apart from the thrust clamp (no glide-slope or thrust-pointing constraints). It reports no flight result. It exists to show that the expensive part of an optimal guidance law can be compressed into a net small enough to ship as JSON and run in a browser tab, on the device.
MIT licensed. Institute for Physical AI @ BMI · The Charlot Lab.
- Downloads last month
- -