vibe coding an orbital mechanics simulation to try out claude code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

7.9 KiB

Maneuver Planning System - Implementation Plan

Overview

Add a maneuver planning system to SimulationState that allows pre-defining burns in config files, which will execute automatically when trigger conditions are met.


Design Decisions

  1. Trigger Types: Start with TIME and TRUE_ANOMALY only
  2. SOI Triggers: Not implementing SOI_ENTRY/EXIT to start
  3. Custom Burns: Not implementing custom burns to start (delta_v only)
  4. Error Handling: Fail config load if spacecraft_name doesn't exist or if maneuver name is not unique
  5. Manual Triggers: Deferred until later

1. Data Structures

A. Maneuver Struct (src/maneuver.h)

enum TriggerType {
    TRIGGER_TIME,           // Execute at specific simulation time (seconds)
    TRIGGER_TRUE_ANOMALY     // Execute at specific orbital true anomaly (radians)
};

struct Maneuver {
    char name[64];          // Maneuver identifier (must be unique)
    int craft_index;        // Index of spacecraft in sim->spacecraft
    
    // Burn parameters
    BurnDirection direction; // Prograde, retrograde, normal, etc.
    double delta_v;         // Magnitude (for standard directions)
    
    // Trigger condition
    TriggerType trigger_type;
    double trigger_value;    // Time (seconds) or true anomaly (radians)
    
    // Execution state
    bool executed;           // Has the burn been applied?
    double executed_time;    // Simulation time when executed
};

B. SimulationState Extension (src/simulation.h)

struct SimulationState {
    CelestialBody* bodies;
    int body_count;
    int max_bodies;
    
    Spacecraft* spacecraft;
    int craft_count;
    int max_craft;
    
    Maneuver* maneuvers;     // NEW: Planned maneuvers array
    int maneuver_count;       // NEW: Current number of maneuvers
    int max_maneuvers;       // NEW: Maximum capacity
    
    double time;
    double dt;
    char config_name[256];
};

2. Config File Format

[[maneuvers]]
name = "orbit_raise_1"
spacecraft_name = "LEO_Satellite"
trigger_type = "time"
trigger_value = 3600.0  # 1 hour into simulation
direction = "prograde"
delta_v = 500.0

[[maneuvers]]
name = "plane_change"
spacecraft_name = "LEO_Satellite"
trigger_type = "true_anomaly"
trigger_value = 1.5708  # 90 degrees in radians
direction = "normal"
delta_v = 300.0

Config Fields:

  • name - Maneuver identifier (must be unique)
  • spacecraft_name - Which spacecraft (string, resolved to index after loading)
  • trigger_type - One of: "time", "true_anomaly"
  • trigger_value - Numeric threshold (time in seconds, angle in radians)
  • direction - One of: "prograde", "retrograde", "normal", "antinormal", "radial_in", "radial_out"
  • delta_v - Magnitude for standard directions

3. Implementation Plan

Phase 1: Data Structures

  1. Update src/maneuver.h:

    • Add TriggerType enum (TIME, TRUE_ANOMALY)
    • Add Maneuver struct with all required fields
  2. Update src/simulation.h:

    • Add maneuver array fields to SimulationState
    • Add max_maneuvers parameter to create_simulation() signature
  3. Update src/simulation.cpp:

    • Allocate maneuver array in create_simulation()
    • Free maneuver array in destroy_simulation()
    • Initialize maneuver_count to 0

Phase 2: Config Loading

  1. Update src/config_loader.h:

    • No API changes - internal helper only
  2. Update src/config_loader.cpp:

    • Add static helper parse_toml_maneuver() to parse individual maneuver entries
    • Add load_maneuvers_from_toml(SimulationState* sim, toml_result_t result) helper
    • Call from load_system_config() after loading spacecraft
    • Resolve spacecraft_name → craft_index (requires spacecraft loaded first)
    • Validate spacecraft_name exists (fail config if not found)
    • Validate maneuver name uniqueness (fail config if duplicate)
  3. String parsing in config_loader.cpp:

    • Parse trigger_type string → enum ("time" → TRIGGER_TIME, "true_anomaly" → TRIGGER_TRUE_ANOMALY)
    • Parse direction string → BurnDirection enum

Phase 3: Execution Logic

  1. Update src/maneuver.h:

    • Add function declarations for trigger checking and execution
  2. Update src/maneuver.cpp:

    • Add check_maneuver_trigger(Maneuver* maneuver, Spacecraft* craft, SimulationState* sim, bool* triggered)
    • Add execute_maneuver(Maneuver* maneuver, Spacecraft* craft, double current_time)
    • Update executed flag and executed_time
  3. Update src/simulation.cpp:

    • In update_simulation(), after spacecraft updates:
      • Call execute_pending_maneuvers(sim)
    • Add execute_pending_maneuvers(SimulationState* sim) function that:
      • Loops through maneuvers
      • Skips executed ones
      • Checks trigger condition
      • Executes if triggered
      • Updates spacecraft velocity
      • Marks as executed

Phase 4: Trigger Condition Logic

  1. Implement trigger checks:

    • TIME: Check sim->time >= trigger_value
    • TRUE_ANOMALY: Calculate current true anomaly from position/velocity, compare to threshold
      • True anomaly ν = atan2(√(1-e²) * sin(E), cos(E)) where E is eccentric anomaly
      • Or use direct position/velocity: ν = atan2(r·v, r·v⊥) (simpler)
      • Use normalized position/velocity for stability
  2. True anomaly calculation:

    • Position vector r = local_position
    • Velocity vector v = local_velocity
    • Angular momentum h = r × v
    • Eccentricity vector e = (v × h) / μ - r/|r|
    • True anomaly ν = acos( (e·r) / (|e|·|r|) )
    • Check sign using (r·h) to determine quadrant (prograde vs retrograde)

Phase 5: Testing

  1. Create test config (tests/configs/maneuver_sequence.toml):

    • Time-based prograde burn to raise orbit
    • True anomaly-based normal burn for plane change
    • Verify spacecraft with specified name exists
  2. Create test file (tests/test_maneuver_planning.cpp):

    • Test config loading with valid maneuvers
    • Test config failure with duplicate maneuver names
    • Test config failure with non-existent spacecraft
    • Test time-based trigger execution
    • Test true anomaly trigger execution
    • Test maneuver executed state tracking
    • Test maneuvers only fire once
  3. Update all test files:

    • Update create_simulation() calls to include max_maneuvers parameter
  4. Update main.cpp:

    • Update create_simulation() call with max_maneuvers parameter

4. Key Design Decisions

A. Spacecraft Resolution

  • Config uses spacecraft_name (string)
  • After loading spacecraft array, resolve names to indices
  • Validate that spacecraft exists before loading maneuvers
  • Fail config load if spacecraft not found

B. Maneuver Name Uniqueness

  • Maneuver names must be unique identifiers
  • Check for duplicates while loading
  • Fail config load if duplicate found

C. Trigger Types (Initial Implementation)

  • TIME: Simple time-based trigger
  • TRUE_ANOMALY: Orbital position-based trigger
  • Deferred: SOI_ENTRY, SOI_EXIT, DISTANCE, MANUAL

D. Burn Directions (Initial Implementation)

  • Standard directions: prograde, retrograde, normal, antinormal, radial_in, radial_out
  • Deferred: custom burns with arbitrary delta_v vector

E. Execution Timing

  • Check triggers after physics update in update_simulation()
  • Apply burns to spacecraft local_velocity and velocity
  • Mark as executed to prevent re-firing
  • Record executed_time for debugging

F. True Anomaly Calculation

  • Use eccentric anomaly approach for numerical stability
  • Alternative: use position/velocity dot products directly
  • Need to calculate orbital elements from current state

5. Future Enhancements

  • Additional trigger types (distance, SOI entry/exit)
  • Custom burns with arbitrary delta-v vectors
  • Manual trigger API for interactive control
  • Maneuver groups/chaining
  • Delta-v budget tracking
  • Burn timeline visualization
  • Undo/revert maneuver capability