Maneuver
/maneuver/simulate/maneuver/targetPurpose
POST /maneuver/simulate propagates a spacecraft through a sequence of burns and
coast arcs, reporting what each burn cost.
POST /maneuver/target solves the inverse: state the orbital goals and a
differential corrector adjusts the burns until they are met.
Neither takes a constellation_id. Both take a self-contained mission plan, so
they work immediately after startup.
POST /maneuver/simulate
Request
| Parameter | Type | Unit | Default | Required | Description |
|---|---|---|---|---|---|
plan | object | n/a | — | Yes | Mission plan: epoch, initial orbit, thruster, tank, and burns. Nested, unlike the flat econ request. |
duration_hours | number | h | 6 | No | Total propagation duration. |
step_seconds | number | s | 60 | No | Output sampling step. |
coast | string | n/a | two_body | No | Coast-arc force model: `two_body`, `j2`, or `j4`. Underscored, unlike the CLI hyphen. |
czml | boolean | n/a | false | No | Include CZML with orbit and burn markers in the response. |
Example
A two-burn raise in the style of a Hohmann transfer:
curl -s -X POST http://127.0.0.1:8080/maneuver/simulate \
-H 'content-type: application/json' \
-d '{
"plan": {
"epoch": "2026-01-01T00:00:00Z",
"initial_orbit": {
"semi_major_axis_km": 6878.0, "eccentricity": 0.0,
"inclination_deg": 51.6, "raan_deg": 0.0,
"argument_of_perigee_deg": 0.0, "true_anomaly_deg": 0.0
},
"thruster": { "isp_s": 220.0, "max_thrust_n": 22.0 },
"tank": { "fuel_kg": 40.0, "dry_mass_kg": 240.0 },
"burns": [
{ "type": "impulsive",
"trigger": { "kind": "at_elapsed", "seconds": 600.0 },
"frame": "ric", "dv_mps": [0.0, 30.0, 0.0] },
{ "type": "impulsive",
"trigger": { "kind": "at_apoapsis", "orbit": 1 },
"frame": "ric", "dv_mps": [0.0, 29.0, 0.0] }
]
},
"duration_hours": 4.0,
"step_seconds": 60.0
}'{
"total_dv_mps": 59.0,
"propellant_used_kg": 7.553389982293602,
"final_mass_kg": 272.4466100177064,
"sample_count": 244,
"events": [
{
"index": 0,
"epoch": "2026-01-01T00:10:00Z",
"elapsed_s": 600.0,
"frame": "ric",
"dv_mps": 30.0,
"dv_eci_mps": [-18.49028135001945, 14.674207076712879, 18.51424160658147],
"propellant_kg": 3.8665172150187965,
"mass_after_kg": 276.1334827849812,
"finite": false
}
]
}Response elided after the first burn event.
The response gives you both frames
dv_mps is the commanded magnitude, 30 m/s. dv_eci_mps is the same burn
resolved into inertial components. The commanded vector was [0, 30, 0] in RIC,
purely along-track, and the ECI components are large in all three axes because
RIC rotates with the spacecraft.
Commanding in RIC and receiving ECI is the useful pairing. RIC is how a burn is designed, because along-track and radial have direct orbital meaning. ECI is what a propagator and a spacecraft attitude system need.
If you only ever read dv_mps, you will not notice a frame mistake. Check that
the ECI magnitude matches the commanded magnitude.
Propellant falls per burn
Burn 0 consumed 3.867 kg for 30 m/s. The second burn consumes less for a comparable delta-v, because propellant per unit delta-v scales with current mass and the vehicle is lighter after the first burn:
This is why delta-v, not propellant mass, is the currency of mission design: delta-v is a property of the trajectory, while propellant depends on the mass you happen to be carrying.
POST /maneuver/target
Solves for burn parameters using the Vary and Achieve formulation: nominate free variables, nominate orbital goals, and a differential corrector iterates until the residuals are within tolerance.
The request carries the same mission plan as an initial guess, plus a targeting
problem with vary, achieve, and max_iterations.
Count variables against goals. Two free variables and two goals is a square system with a unique solution. More goals than variables is over-constrained and generally has no exact solution.
Residuals far tighter than tolerance describe the model, not reality. A solved plan achieves its goals under the coast force model selected, which defaults to two-body, and real execution adds pointing and magnitude error.
See also
orbitforge maneuverandtarget, which document the plan and problem schemas in full./transfer/lambertfor a closed-form initial guess.
main (pre-release)