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_sma could be negative if r > 2 * target_sma. In this case, use v_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 — modify maneuver_circularize_tick
  • services/tick-engine/src/automation.py — compute target_sma from target_altitude + body_radius, store in maneuver
  • services/api-gateway/src/routes/automation.py — validate target_altitude param
  • services/tick-engine/tests/ — tests for target altitude circularization

Back to top

Galaxy — Kubernetes-based multiplayer space game

This site uses Just the Docs, a documentation theme for Jekyll.