Thrust Direction And Kinematic Attitude
Finite-thrust phases use Phase.thrust_control to separate propulsion from
the choice of direction variables. The translational force and propellant
model remain unchanged.
Free Vector-Throttle Control
The default is a dimensionless three-component vector. Its norm is throttle and is bounded by one; its direction is the thrust direction.
from octavian import ThrustControl
inertial_control = ThrustControl.vector(frame="inertial")
ric_control = ThrustControl.vector(frame="ric")
An RIC vector is rotated into inertial coordinates from the propagated state at every collocation point. For an inertial mission, RIC is defined by that spacecraft's position and velocity. For exact relative motion, it is defined by the propagated chief.
Use this representation when the optimizer should choose both throttle and direction freely.
Prescribed Direction
Fixed control removes direction from the decision vector and leaves only scalar throttle:
constant_inertial = ThrustControl.fixed(
[1.0, 0.0, 0.0],
frame="inertial",
)
always_in_track = ThrustControl.fixed(
[0.0, 1.0, 0.0],
frame="ric",
)
Input vectors are normalized. A fixed inertial direction remains constant in inertial space. A fixed RIC direction follows the local orbital frame.
Euler-Angle Kinematics
Euler control adds yaw, pitch, and roll states. It uses a 3-2-1 convention relative to the selected frame, and the body +X axis is the thrust direction. The controls are scalar throttle plus yaw, pitch, and roll rates.
import numpy as np
from octavian import ThrustControl
attitude = ThrustControl.euler(
frame="ric",
initial_angles_rad=np.deg2rad([90.0, 0.0, 0.0]),
max_slew_rate_radps=np.deg2rad(0.5),
yaw_bounds_rad=np.deg2rad([-180.0, 180.0]),
pitch_bounds_rad=np.deg2rad([-80.0, 80.0]),
roll_bounds_rad=np.deg2rad([-180.0, 180.0]),
)
This is a kinematic attitude model. It does not introduce torque, inertia, reaction wheels, or full six-degree-of-freedom dynamics. Roll is carried so attitude can remain continuous even though rotation about body +X does not change the translational thrust direction.
The maximum slew rate bounds the magnitude of the Euler-rate vector, not each axis independently. Internally, Octavian normalizes the optimizer variables for conditioning; returned histories are always in physical radians per second.
Attach Control To A Phase
from octavian import Phase
burn = Phase(
name="departure_burn",
mode="finite_thrust",
spacecraft=spacecraft,
dynamics=dynamics,
thrust_control=attitude,
# states, time bounds, and constraints...
)
The same declarations work for ordinary inertial dynamics and exact
Dynamics.relative(..., propagation_mode="coupled_eci") deputy burns.
Continuous Burn-Coast-Burn Attitude
In a powered chain, a kinematic attitude can continue through an intermediate coast:
departure = Phase(
name="departure",
mode="finite_thrust",
spacecraft=spacecraft,
dynamics=dynamics,
thrust_control=attitude,
)
coast = Phase(
name="coast",
mode="coast",
previous=departure,
)
arrival = Phase(
name="arrival",
mode="finite_thrust",
previous=coast,
)
The later phases inherit thrust_control. Octavian carries mass and attitude
through the coast and links yaw, pitch, and roll continuously at both
boundaries. Every phase from the first through the last powered phase must use
the same Euler reference frame. Set thrust_control explicitly on a later
phase only when changing another compatible setting such as its angle bounds.
Read The Result
solution = mission.solve()
for control_history in solution.phase_control_trajectories:
# [time, controls...]
print(control_history.shape)
for attitude_history in solution.attitude_phase_trajectories:
# [yaw, pitch, roll, time, yaw_rate, pitch_rate, roll_rate]
print(attitude_history[-1])
For powered Euler phases, phase_control_trajectories contains
[time, throttle, yaw_rate, pitch_rate, roll_rate]. Euler coasts contain
[time, yaw_rate, pitch_rate, roll_rate]. Rates are radians per second.
solution.result.info["thrust_controls"] records the declaration used by each
powered phase for reproducible output.
See
examples/composable/earth_centered/12_thrust_frames_and_attitude.py
for a complete executable mission.