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
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
- Trigger Types: Start with TIME and TRUE_ANOMALY only
- SOI Triggers: Not implementing SOI_ENTRY/EXIT to start
- Custom Burns: Not implementing custom burns to start (delta_v only)
- Error Handling: Fail config load if spacecraft_name doesn't exist or if maneuver name is not unique
- 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
-
Update
src/maneuver.h:- Add
TriggerTypeenum (TIME, TRUE_ANOMALY) - Add
Maneuverstruct with all required fields
- Add
-
Update
src/simulation.h:- Add maneuver array fields to SimulationState
- Add
max_maneuversparameter tocreate_simulation()signature
-
Update
src/simulation.cpp:- Allocate maneuver array in
create_simulation() - Free maneuver array in
destroy_simulation() - Initialize maneuver_count to 0
- Allocate maneuver array in
Phase 2: Config Loading
-
Update
src/config_loader.h:- No API changes - internal helper only
-
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)
- Add static helper
-
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
-
Update
src/maneuver.h:- Add function declarations for trigger checking and execution
-
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
- Add
-
Update
src/simulation.cpp:- In
update_simulation(), after spacecraft updates:- Call
execute_pending_maneuvers(sim)
- Call
- 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
- In
Phase 4: Trigger Condition Logic
-
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
- TIME: Check
-
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
-
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
-
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
-
Update all test files:
- Update
create_simulation()calls to include max_maneuvers parameter
- Update
-
Update main.cpp:
- Update
create_simulation()call with max_maneuvers parameter
- Update
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_velocityandvelocity - 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