Source code for ADCS.CONOPS.goals.attitude_goal

__all__ = ["Attitude_Goal"]

import numpy as np
from typing import Tuple

from .goal import Goal
from ADCS.orbits.orbital_state import Orbital_State
from ADCS.helpers.math_helpers import normalize, rot_mat, quat_mult, quat_inv

[docs] class Attitude_Goal(Goal): r""" Abstract base class for attitude-based pointing goals. This class specializes :class:`~ADCS.goals.goal.Goal` for goals whose primary output is a desired spacecraft attitude expressed as a reference quaternion. Subclasses define a desired reference attitude :math:`\mathbf{q}_{\mathrm{ref}}` as a function of the current orbital state. The reference mapping implemented by subclasses takes the form .. math:: G_{\mathrm{att}}(\mathcal{O}(t)) = \left( \mathbf{q}_{\mathrm{ref}}, \boldsymbol{\omega}_{\mathrm{ref}} \right) where :math:`\mathbf{q}_{\mathrm{ref}} \in \mathbb{R}^4` is a unit quaternion representing the desired body-to-inertial rotation and :math:`\boldsymbol{\omega}_{\mathrm{ref}} \in \mathbb{R}^3` is the corresponding reference angular velocity. This class additionally provides a common quaternion-based attitude error computation suitable for feedback control laws. Subclasses must implement :meth:`to_ref`. See Also -------- :class:`~ADCS.goals.goal.Goal` :class:`~ADCS.goals.goal_list.GoalList` """ def __init__(self) -> None: r""" Initialize an attitude goal. This constructor performs no initialization beyond invoking the base :class:`~ADCS.goals.goal.Goal` constructor. :return: None :rtype: None """ super().__init__()
[docs] def to_ref(self, os0: Orbital_State) -> Tuple[np.ndarray, np.ndarray]: r""" Generate a reference attitude and angular velocity. Subclasses must implement this method to compute a desired reference quaternion and angular velocity based on the current orbital state. This method is expected to return .. math:: \mathbf{q}_{\mathrm{ref}} \in \mathbb{R}^4, \quad \boldsymbol{\omega}_{\mathrm{ref}} \in \mathbb{R}^3 with :math:`\lVert \mathbf{q}_{\mathrm{ref}} \rVert = 1`. :param os0: Current orbital state. :type os0: Orbital_State :return: Reference attitude quaternion and reference angular velocity. :rtype: Tuple[numpy.ndarray, numpy.ndarray] """ raise NotImplementedError("Choose a subclass for Attitude_Goal.")
[docs] def error(self, q: np.ndarray, body_boresight: np.ndarray, os0: Orbital_State) -> np.ndarray: r""" Compute the quaternion-based attitude error vector. Let :math:`\mathbf{q}` denote the current spacecraft attitude quaternion and :math:`\mathbf{q}_{\mathrm{ref}}` the reference attitude returned by :meth:`to_ref`. The attitude error quaternion is defined as .. math:: \mathbf{q}_{\mathrm{err}} = \mathbf{q}^{-1} \otimes \mathbf{q}_{\mathrm{ref}} where :math:`\otimes` denotes quaternion multiplication. To enforce the shortest-rotation convention, the quaternion is negated if its scalar component is negative: .. math:: \mathbf{q}_{\mathrm{err}} \leftarrow -\mathbf{q}_{\mathrm{err}} \quad \text{if} \quad q_{\mathrm{err},0} < 0 The returned error vector is the vector part of the error quaternion: .. math:: \mathbf{e} = \begin{bmatrix} q_{\mathrm{err},1} & q_{\mathrm{err},2} & q_{\mathrm{err},3} \end{bmatrix}^{\mathsf{T}} This representation is commonly used for small-angle feedback control laws. The body-frame boresight argument is accepted for interface compatibility but is not used in this computation. :param q: Current spacecraft attitude quaternion. :type q: numpy.ndarray :param body_boresight: Boresight direction expressed in the spacecraft body frame. :type body_boresight: numpy.ndarray :param os0: Current orbital state. :type os0: Orbital_State :return: Vector part of the quaternion attitude error. :rtype: numpy.ndarray """ q_ref, _ = self.to_ref(os0) # Body-frame attitude error quaternion. # We want q_err such that applying -q_err[1:4] as torque drives q toward q_ref. # The correct formulation is: q_err = q_ref^-1 * q # This represents the rotation FROM q_ref TO q, so negating it drives toward q_ref. q_err = quat_mult(quat_inv(q_ref), q) # shortest rotation if q_err[0] < 0.0: q_err = -q_err return q_err[1:4]