diff --git a/.vscode/settings.json b/.vscode/settings.json index 45bd304e9..ac2bb1cab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,12 +14,14 @@ "cSpell.language": "en-US", "cSpell.words": [ "Abdulklech", + "addsurface", "adjugate", "akima", "allclose", "altitudemode", "Alves", "amax", + "angularpos", "arange", "arccos", "arcsin", @@ -39,6 +41,7 @@ "axvline", "axvspan", "Barrowman", + "Baruh", "behaviour", "Bigl", "Bigr", @@ -77,6 +80,7 @@ "csys", "datapoints", "datetime", + "dcsys", "ddot", "deepcopy", "deletechars", @@ -105,6 +109,7 @@ "figsize", "filt", "firstsimulation", + "flightcsys", "Fluxogram", "fmax", "fmin", @@ -130,6 +135,7 @@ "Gonçalvez", "grav", "Guilherme", + "Haim", "hemis", "hgtprs", "hgtsfc", diff --git a/CHANGELOG.md b/CHANGELOG.md index 37c2bb0d0..d9aa30969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Attention: The newest changes should be on top --> ### Added +- ENH: Rocket Axis Definition [#635](https://github.com/RocketPy-Team/RocketPy/pull/635) ### Changed diff --git a/docs/static/rocket/3dcsys.png b/docs/static/rocket/3dcsys.png new file mode 100644 index 000000000..57c8a7184 Binary files /dev/null and b/docs/static/rocket/3dcsys.png differ diff --git a/docs/static/rocket/angularpos.png b/docs/static/rocket/angularpos.png new file mode 100644 index 000000000..d68300bef Binary files /dev/null and b/docs/static/rocket/angularpos.png differ diff --git a/docs/static/rocket/flightcsys.png b/docs/static/rocket/flightcsys.png new file mode 100644 index 000000000..0d3ec7028 Binary files /dev/null and b/docs/static/rocket/flightcsys.png differ diff --git a/docs/user/index.rst b/docs/user/index.rst index 7d8c12241..5698aafcc 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -14,7 +14,7 @@ RocketPy's User Guide Positions and Coordinate Systems Motors - Rocket + Rocket Environment .. toctree:: diff --git a/docs/user/rocket/rocket.rst b/docs/user/rocket/rocket.rst new file mode 100644 index 000000000..17ec63c1a --- /dev/null +++ b/docs/user/rocket/rocket.rst @@ -0,0 +1,15 @@ +Rocket Usage +============ + +.. toctree:: + :maxdepth: 2 + :caption: Rocket Class Usage + + Rocket Class Usage + +.. toctree:: + :maxdepth: 3 + :caption: Rocket Class Axes Definitions + + Rocket Class Axes Definitions + \ No newline at end of file diff --git a/docs/user/rocket/rocket_axes.rst b/docs/user/rocket/rocket_axes.rst new file mode 100644 index 000000000..3dfaced8c --- /dev/null +++ b/docs/user/rocket/rocket_axes.rst @@ -0,0 +1,156 @@ +Rocket Class Axes Definitions +============================= + +The Rocket class has two different coordinate systems: + +1. **User Defined Coordinate System**: Used for geometrical inputs of the \ + aerodynamic surfaces and motor. +2. **Body Axes Coordinate System**: Used during the flight simulation to assess \ + the governing equations of motion. + +All inputs are automatically converted from the user's coordinate system to the +rocket body axes coordinate system for use during the simulation. + +Let's dive into the definitions of these coordinate systems: + + +1. User Defined Coordinate System +--------------------------------- + +Two things are set by the user in the user input coordinate system: + +1. **Coordinate System Origin**: The origin of the coordinate system is set at \ + any point along the rocket's center line. This point can be arbitrarily chosen \ + and is not explicitly defined. All inputs must be given relative to this \ + point. +2. **Direction of Center Axis**: Specified by the ``coordinate_system_orientation`` \ + argument when initializing the Rocket (:class:`rocketpy.Rocket.__init__`). This \ + argument defines the direction of the axis that follows the rocket's center \ + line. It can be either ``"nose_to_tail"`` or ``"tail_to_nose"``. + +.. tip:: + + If you are using some CAD software to design your rocket, you can imagine the \ + coordinate system as the one used in the CAD software. The origin of the \ + coordinate system is the origin of the rocket in the CAD software, and the \ + direction of the center axis is the direction of the rocket's centerline. \ + You don't need to worry about the exact position of the origin, as long as \ + all inputs are given relative to this point. + +.. seealso:: + + See `Positions and Coordinate Systems `_ for more \ + information on the definitions of the rocket's aerodynamic surfaces and motor. + +The ``x`` and ``y`` axes are defined at the plane perpendicular to the center axis, +while the ``z`` axis is defined along the center axis. Depending on the choice of +``coordinate_system_orientation``, the ``x`` axis and ``y`` axis can be inverted. + +The following figure shows the two possibilities for the user input coordinate system: + +.. figure:: ../../static/rocket/3dcsys.png + :align: center + :alt: Rocket axes + +.. note:: + + When ``coordinate_system_orientation`` is set to ``"tail_to_nose"``, the direction \ + of the ``x``, ``y``, and ``z`` axes of the **User Defined Coordinate System** is \ + the same as the **Body Axes Coordinate System**. The origin of the coordinate \ + system may still be different. + +Angular Position Inputs +~~~~~~~~~~~~~~~~~~~~~~~ + +Angular position inputs (``angular_position``) refer to the roll angle position +of that surface along the rocket's tube. The roll angle is defined as the angle +from the ``y`` axis to the surface. +Currently, only the :class:`rocketpy.RailButtons` class uses this kind of input. + +The following figure shows the roll angle +definition for both ``coordinate_system_orientation`` options: + +.. figure:: ../../static/rocket/angularpos.png + :align: center + :alt: Angular position + + +.. note:: + + The positive direction of the roll angle is defined as the direction that \ + rotates the surface in the positive direction of the ``z`` axis. + +.. _rocket_axes_body_axes: + +2. Body Axes Coordinate System +------------------------------ + +The body axes coordinate system is used inside the simulation to assess the +governing equations of motion. The body axes coordinate system is defined as follows: + +- The origin is at the rocket's center of dry mass (``center_of_dry_mass_position``). +- The ``z`` axis is defined along the rocket's centerline, pointing from the center of dry mass towards the nose. +- The ``x`` and ``y`` axes are perpendicular. + +3. Relation to Flight Coordinates +--------------------------------- + +The ``Flight`` class uses a coordinate system defined as follows: + +- The origin is at the launch rail. +- The ``Z`` axis is positive upwards. +- The ``X`` axis is position eastwards. +- The ``Y`` axis is positive northwards. + +The following figure shows the rotational relationship between the +**Body Axes Coordinate System** and the **Flight Coordinate System**: + +.. figure:: ../../static/rocket/flightcsys.png + :align: center + :alt: Flight coordinate system + +In the figure above, :math:`\bf{i}` is the ``inclination`` and :math:`\bf{h}` +is the ``heading`` of the launch rail. + +The heading and inclination can be described in terms of Euler angles. +The relation is given by: + +.. math:: + \begin{aligned} + &\text{Precession:} \quad &\psi &= -\bf{h} \\ + &\text{Nutation:} \quad &\theta &= \bf{i} - 90° \\ + \end{aligned} + +A last rotation is defined by the ``angular_position`` of the rocket's rail buttons. +This is a rotation around the rocket's centerline, and describes the last +Euler angle: + +.. math:: + \begin{aligned} + &\text{Spin:} \quad &φ & \\ + \end{aligned} + +If no rail buttons pair ir present, the spin angle is set to **0°**. + +.. note:: + + With spin angle set to **0°**, if the launch rail ``heading`` is set to \ + **0°** and rail ``inclination`` to **90°**, the **Body Axes Coordinate \ + System** is aligned with the **Flight Coordinate System**. + +Rocket's initial orientation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The initial orientation of the rocket is expressed in Euler parameters (quaternions). +The Euler parameters are defined using the 3-1-3 rotation sequence: + +.. math:: + + \begin{aligned} + e_{0} &= \cos\left(\frac{φ}{2}\right) \cos\left(\frac{θ}{2}\right) \cos\left(\frac{ψ}{2}\right) - \sin\left(\frac{φ}{2}\right) \cos\left(\frac{θ}{2}\right) \sin\left(\frac{ψ}{2}\right) \\ + e_{1} &= \cos\left(\frac{φ}{2}\right) \cos\left(\frac{ψ}{2}\right) \sin\left(\frac{θ}{2}\right) + \sin\left(\frac{φ}{2}\right) \sin\left(\frac{θ}{2}\right) \sin\left(\frac{ψ}{2}\right) \\ + e_{2} &= \cos\left(\frac{φ}{2}\right) \sin\left(\frac{θ}{2}\right) \sin\left(\frac{ψ}{2}\right) - \sin\left(\frac{φ}{2}\right) \cos\left(\frac{ψ}{2}\right) \sin\left(\frac{θ}{2}\right) \\ + e_{3} &= \cos\left(\frac{φ}{2}\right) \cos\left(\frac{θ}{2}\right) \sin\left(\frac{ψ}{2}\right) + \cos\left(\frac{θ}{2}\right) \cos\left(\frac{ψ}{2}\right) \sin\left(\frac{φ}{2}\right) \\ + \end{aligned} + + diff --git a/docs/user/rocket.rst b/docs/user/rocket/rocket_usage.rst similarity index 99% rename from docs/user/rocket.rst rename to docs/user/rocket/rocket_usage.rst index 8f5ebf8d9..d25608dc7 100644 --- a/docs/user/rocket.rst +++ b/docs/user/rocket/rocket_usage.rst @@ -209,7 +209,7 @@ to the rocket in one step: .. caution:: - Once again, pay special attention to the ``position`` parameter. Check + Once again, pay special attention to the ``position`` parameter. Check \ the :meth:`rocketpy.Rocket.add_surfaces` method for more information. .. seealso:: diff --git a/rocketpy/mathutils/vector_matrix.py b/rocketpy/mathutils/vector_matrix.py index 03d2d5b51..6060d387f 100644 --- a/rocketpy/mathutils/vector_matrix.py +++ b/rocketpy/mathutils/vector_matrix.py @@ -955,6 +955,10 @@ def transformation(quaternion): ------- Matrix The transformation matrix from frame B to frame A. + + Reference + --------- + https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles """ q_w, q_x, q_y, q_z = quaternion return Matrix( diff --git a/rocketpy/rocket/aero_surface/fins/elliptical_fins.py b/rocketpy/rocket/aero_surface/fins/elliptical_fins.py index 5622900d6..d30cf9aa1 100644 --- a/rocketpy/rocket/aero_surface/fins/elliptical_fins.py +++ b/rocketpy/rocket/aero_surface/fins/elliptical_fins.py @@ -13,9 +13,11 @@ class EllipticalFins(Fins): Note ---- - Local coordinate system: Z axis along the longitudinal axis of symmetry, - positive downwards (top -> bottom). Origin located at the top of the root - chord. + Local coordinate system: + - Origin located at the top of the root chord. + - Z axis along the longitudinal axis of symmetry, positive downwards (top -> bottom). + - Y axis perpendicular to the Z axis, in the span direction, positive upwards. + - X axis completes the right-handed coordinate system. See Also -------- diff --git a/rocketpy/rocket/aero_surface/fins/fins.py b/rocketpy/rocket/aero_surface/fins/fins.py index 2de0176b0..74f7922f7 100644 --- a/rocketpy/rocket/aero_surface/fins/fins.py +++ b/rocketpy/rocket/aero_surface/fins/fins.py @@ -11,9 +11,11 @@ class Fins(AeroSurface): Note ---- - Local coordinate system: Z axis along the longitudinal axis of symmetry, - positive downwards (top -> bottom). Origin located at the top of the root - chord. + Local coordinate system: + - Origin located at the top of the root chord. + - Z axis along the longitudinal axis of symmetry, positive downwards (top -> bottom). + - Y axis perpendicular to the Z axis, in the span direction, positive upwards. + - X axis completes the right-handed coordinate system. Attributes ---------- diff --git a/rocketpy/rocket/aero_surface/fins/trapezoidal_fins.py b/rocketpy/rocket/aero_surface/fins/trapezoidal_fins.py index 15caa38e8..3040e21c9 100644 --- a/rocketpy/rocket/aero_surface/fins/trapezoidal_fins.py +++ b/rocketpy/rocket/aero_surface/fins/trapezoidal_fins.py @@ -13,9 +13,11 @@ class TrapezoidalFins(Fins): Note ---- - Local coordinate system: Z axis along the longitudinal axis of symmetry, - positive downwards (top -> bottom). Origin located at the top of the root - chord. + Local coordinate system: + - Origin located at the top of the root chord. + - Z axis along the longitudinal axis of symmetry, positive downwards (top -> bottom). + - Y axis perpendicular to the Z axis, in the span direction, positive upwards. + - X axis completes the right-handed coordinate system. See Also -------- diff --git a/rocketpy/rocket/aero_surface/nose_cone.py b/rocketpy/rocket/aero_surface/nose_cone.py index 8886be8c5..1ad07bd07 100644 --- a/rocketpy/rocket/aero_surface/nose_cone.py +++ b/rocketpy/rocket/aero_surface/nose_cone.py @@ -15,9 +15,9 @@ class NoseCone(AeroSurface): Note ---- - The local coordinate system has the origin at the tip of the nose cone - and the Z axis along the longitudinal axis of symmetry, positive - downwards (top -> bottom). + Local coordinate system: + - the origin at the tip of the nose cone and + - the Z axis along the longitudinal axis of symmetry, positive downwards (top -> bottom). Attributes ---------- diff --git a/rocketpy/rocket/aero_surface/rail_buttons.py b/rocketpy/rocket/aero_surface/rail_buttons.py index 102f35737..facd8b157 100644 --- a/rocketpy/rocket/aero_surface/rail_buttons.py +++ b/rocketpy/rocket/aero_surface/rail_buttons.py @@ -1,3 +1,5 @@ +import numpy as np + from rocketpy.mathutils.function import Function from rocketpy.prints.aero_surface_prints import _RailButtonsPrints @@ -15,6 +17,8 @@ class RailButtons(AeroSurface): Angular position of the rail buttons in degrees measured as the rotation around the symmetry axis of the rocket relative to one of the other principal axis. + RailButtons.angular_position_rad : float + Angular position of the rail buttons in radians. """ def __init__( @@ -40,11 +44,6 @@ def __init__( Radius of the rocket at the location of the rail buttons in meters. If not provided, it will be calculated when the RailButtons object is added to a Rocket object. - - Returns - ------- - None - """ super().__init__(name, None, None) self.buttons_distance = buttons_distance @@ -56,6 +55,10 @@ def __init__( self.prints = _RailButtonsPrints(self) + @property + def angular_position_rad(self): + return np.radians(self.angular_position) + def evaluate_center_of_pressure(self): """Evaluates the center of pressure of the rail buttons. Rail buttons do not contribute to the center of pressure of the rocket. diff --git a/rocketpy/rocket/aero_surface/tail.py b/rocketpy/rocket/aero_surface/tail.py index a5c5cf939..b053eae2f 100644 --- a/rocketpy/rocket/aero_surface/tail.py +++ b/rocketpy/rocket/aero_surface/tail.py @@ -12,9 +12,9 @@ class Tail(AeroSurface): Note ---- - Local coordinate system: Z axis along the longitudinal axis of symmetry, - positive downwards (top -> bottom). Origin located at top of the tail - (generally the portion closest to the rocket's nose). + Local coordinate system: + - Z axis along the longitudinal axis of symmetry, positive downwards (top -> bottom). + - Origin located at top of the tail (generally the portion closest to the rocket's nose). Attributes ---------- diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 7eb1610f6..952390723 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -885,7 +885,7 @@ def add_motor(self, motor, position): # pylint: disable=too-many-statements See Also -------- - :ref:`positions` + :ref:`addsurface` Returns ------- @@ -951,7 +951,7 @@ def add_surfaces(self, surfaces, positions): See Also -------- - :ref:`positions` + :ref:`addsurface` Returns ------- @@ -1015,10 +1015,16 @@ def add_tail( By tail position, understand the point belonging to the tail which is highest in the rocket coordinate system (i.e. the point closest to the nose cone). + radius : int, float, optional + Reference radius of the tail. This is used to calculate lift + coefficient. If None, which is default, the rocket radius will + be used. + name : string + Tail name. Default is "Tail". See Also -------- - :ref:`positions` + :ref:`addsurface` Returns ------- @@ -1047,7 +1053,6 @@ def add_nose( along the rocket and its derivative of the coefficient of lift in respect to angle of attack. - Parameters ---------- length : int, float @@ -1073,7 +1078,7 @@ def add_nose( See Also -------- - :ref:`positions` + :ref:`addsurface` Returns ------- @@ -1260,6 +1265,10 @@ def add_elliptical_fins( The tuple's second item is the unit of the angle of attack, accepting either "radians" or "degrees". + See Also + -------- + :ref:`addsurface` + Returns ------- fin_set : EllipticalFins @@ -1486,7 +1495,11 @@ def add_air_brakes( return air_brakes def set_rail_buttons( - self, upper_button_position, lower_button_position, angular_position=45 + self, + upper_button_position, + lower_button_position, + angular_position=45, + radius=None, ): """Adds rail buttons to the rocket, allowing for the calculation of forces exerted by them when the rocket is sliding in the launch rail. @@ -1511,10 +1524,12 @@ def set_rail_buttons( relative to one of the other principal axis. Default value is 45 degrees, generally used in rockets with 4 fins. + radius : int, float, optional + Fuselage radius where the rail buttons are located. See Also -------- - :ref:`positions` + :ref:`addsurface` Returns ------- @@ -1525,7 +1540,8 @@ def set_rail_buttons( rail_buttons = RailButtons( buttons_distance=buttons_distance, angular_position=angular_position ) - rail_buttons.rocket_radius = rail_buttons.rocket_radius or self.radius + self.rail_buttons = Components() + rail_buttons.rocket_radius = radius or self.radius self.rail_buttons.add(rail_buttons, lower_button_position) return rail_buttons diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index 68033c07f..73bc715cb 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -14,6 +14,7 @@ from ..prints.flight_prints import _FlightPrints from ..tools import ( calculate_cubic_hermite_coefficients, + euler_angles_to_euler_parameters, find_closest, find_root_linear_interpolation, find_roots_cubic_function, @@ -291,15 +292,15 @@ class Flight: # pylint: disable=too-many-public-methods of time. Can be called or accessed as array. Flight.phi : Function Rocket's Spin Euler Angle, φ, according to the 3-2-3 rotation - system (NASA Standard Aerospace). Measured in degrees and + system nomenclature (NASA Standard Aerospace). Measured in degrees and expressed as a function of time. Can be called or accessed as array. Flight.theta : Function Rocket's Nutation Euler Angle, θ, according to the 3-2-3 rotation - system (NASA Standard Aerospace). Measured in degrees and + system nomenclature (NASA Standard Aerospace). Measured in degrees and expressed as a function of time. Can be called or accessed as array. Flight.psi : Function Rocket's Precession Euler Angle, ψ, according to the 3-2-3 rotation - system (NASA Standard Aerospace). Measured in degrees and + system nomenclature (NASA Standard Aerospace). Measured in degrees and expressed as a function of time. Can be called or accessed as array. Flight.R1 : Function Resultant force perpendicular to rockets axis due to @@ -523,7 +524,7 @@ def __init__( # pylint: disable=too-many-arguments,too-many-statements Default is 80. heading : int, float, optional Heading angle relative to north given in degrees. - Default is 90, which points in the x direction. + Default is 90, which points in the x (east) direction. initial_solution : array, Flight, optional Initial solution array to be used. Format is: @@ -1073,12 +1074,26 @@ def __init_flight_state(self): vx_init, vy_init, vz_init = 0, 0, 0 w1_init, w2_init, w3_init = 0, 0, 0 # Initialize attitude - psi_init = -self.heading * (np.pi / 180) # Precession / Heading Angle - theta_init = (self.inclination - 90) * (np.pi / 180) # Nutation Angle - e0_init = np.cos(psi_init / 2) * np.cos(theta_init / 2) - e1_init = np.cos(psi_init / 2) * np.sin(theta_init / 2) - e2_init = np.sin(psi_init / 2) * np.sin(theta_init / 2) - e3_init = np.sin(psi_init / 2) * np.cos(theta_init / 2) + # Precession / Heading Angle + self.psi_init = np.radians(-self.heading) + # Nutation / Attitude Angle + self.theta_init = np.radians(self.inclination - 90) + # Spin / Bank Angle + self.phi_init = 0 + + # Consider Rail Buttons position, if there is rail buttons + try: + self.phi_init += ( + self.rocket.rail_buttons[0].component.angular_position_rad + * self.rocket._csys + ) + except IndexError: + pass + + # 3-1-3 Euler Angles to Euler Parameters + e0_init, e1_init, e2_init, e3_init = euler_angles_to_euler_parameters( + self.phi_init, self.theta_init, self.psi_init + ) # Store initial conditions self.initial_solution = [ self.t_initial, @@ -2823,9 +2838,7 @@ def __calculate_rail_button_forces(self): # TODO: complex method. rail_buttons_tuple.component.buttons_distance + rail_buttons_tuple.position ) lower_button_position = rail_buttons_tuple.position - angular_position_rad = ( - rail_buttons_tuple.component.angular_position * np.pi / 180 - ) + angular_position_rad = rail_buttons_tuple.component.angular_position_rad D1 = ( upper_button_position - self.rocket.center_of_dry_mass_position ) * self.rocket._csys diff --git a/rocketpy/tools.py b/rocketpy/tools.py index 40fbaefea..6cddb2327 100644 --- a/rocketpy/tools.py +++ b/rocketpy/tools.py @@ -888,16 +888,14 @@ def parallel_axis_theorem_from_com(com_inertia_moment, mass, distance): float Moment of inertia relative to the new axis. - Reference - --------- + References + ---------- https://en.wikipedia.org/wiki/Parallel_axis_theorem """ return com_inertia_moment + mass * distance**2 # Flight - - def quaternions_to_precession(e0, e1, e2, e3): """Calculates the Precession angle @@ -911,11 +909,17 @@ def quaternions_to_precession(e0, e1, e2, e3): Euler parameter 2, must be between -1 and 1 e3 : float Euler parameter 3, must be between -1 and 1 + Returns ------- float Euler Precession angle in degrees + + References + ---------- + Baruh, Haim. Analytical dynamics """ + # minus sign in e2 and e1 is due to changing from 3-1-3 to 3-2-3 convention return (180 / np.pi) * (np.arctan2(e3, e0) + np.arctan2(-e2, -e1)) @@ -937,7 +941,12 @@ def quaternions_to_spin(e0, e1, e2, e3): ------- float Euler Spin angle in degrees + + References + ---------- + Baruh, Haim. Analytical dynamics """ + # minus sign in e2 and e1 is due to changing from 3-1-3 to 3-2-3 convention return (180 / np.pi) * (np.arctan2(e3, e0) - np.arctan2(-e2, -e1)) @@ -950,14 +959,57 @@ def quaternions_to_nutation(e1, e2): Euler parameter 1, must be between -1 and 1 e2 : float Euler parameter 2, must be between -1 and 1 + Returns ------- float Euler Nutation angle in degrees + + References + ---------- + Baruh, Haim. Analytical dynamics """ + # we are changing from 3-1-3 to 3-2-3 conventions return (180 / np.pi) * 2 * np.arcsin(-((e1**2 + e2**2) ** 0.5)) +def euler_angles_to_euler_parameters(phi, theta, psi): + """Convert 3-1-3 Euler Angles to Euler Parameters (quaternions). + + Parameters + ---------- + phi : float + Rotation angle around the z-axis (in radians). Represents the precession angle. + theta : float + Rotation angle around the x-axis (in radians). Represents the nutation angle. + psi : float + Rotation angle around the z-axis (in radians). Represents the spin angle. + + + Returns + ------- + tuple[float, float, float, float] + The Euler parameters or quaternions (e0, e1, e2, e3) + + References + ---------- + https://www.astro.rug.nl/software/kapteyn-beta/_downloads/attitude.pdf + """ + e0 = np.cos(phi / 2) * np.cos(theta / 2) * np.cos(psi / 2) - np.sin( + phi / 2 + ) * np.cos(theta / 2) * np.sin(psi / 2) + e1 = np.cos(phi / 2) * np.cos(psi / 2) * np.sin(theta / 2) + np.sin( + phi / 2 + ) * np.sin(theta / 2) * np.sin(psi / 2) + e2 = np.cos(phi / 2) * np.sin(theta / 2) * np.sin(psi / 2) - np.sin( + phi / 2 + ) * np.cos(psi / 2) * np.sin(theta / 2) + e3 = np.cos(phi / 2) * np.cos(theta / 2) * np.sin(psi / 2) + np.cos( + theta / 2 + ) * np.cos(psi / 2) * np.sin(phi / 2) + return e0, e1, e2, e3 + + if __name__ == "__main__": import doctest diff --git a/tests/fixtures/rockets/rocket_fixtures.py b/tests/fixtures/rockets/rocket_fixtures.py index 702506d06..ceab9d15a 100644 --- a/tests/fixtures/rockets/rocket_fixtures.py +++ b/tests/fixtures/rockets/rocket_fixtures.py @@ -83,7 +83,7 @@ def calisto_nose_to_tail(cesaroni_m1670): calisto.set_rail_buttons( upper_button_position=-0.082, lower_button_position=0.618, - angular_position=45, + angular_position=0, ) return calisto @@ -177,7 +177,7 @@ def calisto_robust( calisto.set_rail_buttons( upper_button_position=0.082, lower_button_position=-0.618, - angular_position=45, + angular_position=0, ) calisto.parachutes.append(calisto_main_chute) calisto.parachutes.append(calisto_drogue_chute) diff --git a/tests/unit/test_flight.py b/tests/unit/test_flight.py index 078c682c9..cea54e575 100644 --- a/tests/unit/test_flight.py +++ b/tests/unit/test_flight.py @@ -334,10 +334,10 @@ def test_rail_buttons_forces(flight_calisto_custom_wind): """ test = flight_calisto_custom_wind atol = 5e-3 - assert pytest.approx(3.833613, abs=atol) == test.max_rail_button1_normal_force - assert pytest.approx(1.648938, abs=atol) == test.max_rail_button1_shear_force - assert pytest.approx(1.165307, abs=atol) == test.max_rail_button2_normal_force - assert pytest.approx(0.501229, abs=atol) == test.max_rail_button2_shear_force + assert pytest.approx(3.876749, abs=atol) == test.max_rail_button1_normal_force + assert pytest.approx(1.544799, abs=atol) == test.max_rail_button1_shear_force + assert pytest.approx(1.178420, abs=atol) == test.max_rail_button2_normal_force + assert pytest.approx(0.469574, abs=atol) == test.max_rail_button2_shear_force def test_max_values(flight_calisto_robust):