Circularize at Target Altitude (#789)
Overview
Extend the existing circularize automation maneuver to accept an optional target_altitude parameter (meters above surface). The maneuver burns to achieve a circular orbit at the specified altitude. When omitted, defaults to the ship’s current altitude (distance from body surface).
Parameters
target_altitude(float, optional): Target altitude in meters above body surface. Must be > 0. Internally converted to target SMA:target_sma = body_radius + target_altitude. When omitted, uses the ship’s current altitude:target_sma = r(current distance from body center).
Algorithm
Vis-Viva Targeting
At each tick, compute the desired velocity at the ship’s current radius r for an orbit with a = target_sma:
target_sma = body_radius + target_altitude (or current r if no altitude given)
v_desired = sqrt(mu * (2/r - 1/target_sma))
Direction: tangential (prograde), using the angular momentum vector to define the orbital plane.
Delta-v: dv = v_desired_vec - v_current_vec
This naturally produces efficient transfers:
- When
r < target_sma: ship is below target, burns prograde to raise apoapsis - When
r > target_sma: ship is above target, burns retrograde to lower periapsis - As orbit approaches circular at
target_sma: delta-v → 0
Edge Cases
- Hyperbolic/escape:
2/r - 1/target_smacould be negative ifr > 2 * target_sma. In this case, usev_desired = sqrt(mu / target_sma)(circular velocity at target) and burn purely retrograde to shed excess energy. - No target altitude: Default to current distance from body center (
r), which circularizes at the current altitude.
Completion Criteria
All must be satisfied:
- Eccentricity < 0.03
|a - target_sma| / target_sma < 0.02(2% relative tolerance on SMA)- Periapsis altitude ≥ 0 (orbit does not intersect the surface)
Periapsis Safety Clamping
When lowering orbit (r > target_sma), the transfer orbit’s periapsis could dip below the surface. Clamp effective_sma >= (r + body_radius + 10km) / 2 to prevent this. This clamping may nullify the burn at positions far from periapsis (effective_sma ≈ current SMA → dv ≈ 0).
Dead Zone Pre-Steering
When |dv| < 0.5 m/s (coast), pre-steer toward the expected apse burn direction:
- Lowering orbit (
sma > target_sma * 1.01) → steer retrograde (periapsis burn will be retrograde) - Raising orbit (
sma < target_sma * 0.99) → steer prograde (apoapsis burn will be prograde) - Otherwise → steer prograde (default)
This ensures the ship is aligned when it reaches the apse where dv becomes significant, avoiding missed burn windows due to the 5° alignment gate.
Throttle Control
Proportional throttle: thrust = min(1.0, |dv| / dv_per_tick) to avoid overshooting.
Status Text
- With target:
"Circularize {alt}km — dv={dv}m/s, e={e}, Δalt={da}km" - Without target:
"Circularizing — dv={dv}m/s, e={e}"(unchanged)
API Changes
Automation Rule Action
{
"action": "circularize",
"target_altitude": 200000
}
target_altitude is optional (meters above surface). When omitted, circularizes at current altitude.
Maneuver Redis Fields
New optional field in maneuver:{ship_id}:
target_sma: target semi-major axis in meters (computed from target_altitude + body_radius at maneuver start)
Files Changed
services/tick-engine/src/automation_maneuvers.py— modifymaneuver_circularize_tickservices/tick-engine/src/automation.py— compute target_sma from target_altitude + body_radius, store in maneuverservices/api-gateway/src/routes/automation.py— validatetarget_altitudeparamservices/tick-engine/tests/— tests for target altitude circularization