Skip to content

Commit 6d65fa9

Browse files
Merge pull request #674 from RocketPy-Team/bug/rotational-eoms-not-relative-to-cdm
BUG: Rotational EOMs Not Relative To CDM
2 parents 44beade + 3a4c742 commit 6d65fa9

File tree

8 files changed

+63
-53
lines changed

8 files changed

+63
-53
lines changed

.pylintrc

+1-2
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,7 @@ good-names=FlightPhases,
225225
motor_I_11_derivative_at_t,
226226
M3_forcing,
227227
M3_damping,
228-
CM_to_CDM,
229-
CM_to_CPM,
228+
CDM_to_CPM,
230229
center_of_mass_without_motor_to_CDM,
231230
motor_center_of_dry_mass_to_CDM,
232231
generic_motor_cesaroni_M1520,

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Attention: The newest changes should be on top -->
4343

4444
### Fixed
4545

46+
- BUG: Rotational EOMs Not Relative To CDM [#674](https://github.com/RocketPy-Team/RocketPy/pull/674)
4647
- BUG: Pressure ISA Extrapolation as "linear" [#675](https://github.com/RocketPy-Team/RocketPy/pull/675)
4748
- BUG: fix the Frequency Response plot of Flight class [#653](https://github.com/RocketPy-Team/RocketPy/pull/653)
4849

docs/user/rocket/rocket_usage.rst

+6-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ and radius:
4141
Pay special attention to the following:
4242

4343
- ``mass`` is the rocket's mass, **without the motor**, in kg.
44+
- All ``inertia`` values are given in relation to the rocket's center of
45+
mass without motor.
4446
- ``inertia`` is defined as a tuple of the form ``(I11, I22, I33)``.
4547
Where ``I11`` and ``I22`` are the inertia of the mass around the
4648
perpendicular axes to the rocket, and ``I33`` is the inertia around the
@@ -432,10 +434,10 @@ The lets check all the information available about the rocket:
432434
7. Inertia Tensors
433435
------------------
434436

435-
The inertia tensor of the rocket at a given time can be obtained using the
436-
``get_inertia_tensor_at_time`` method. This method evaluates each component of
437-
the inertia tensor at the specified time and returns a
438-
:class:`rocketpy.mathutils.Matrix` object.
437+
The inertia tensor relative to the center of dry mass of the rocket at a
438+
given time can be obtained using the ``get_inertia_tensor_at_time`` method.
439+
This method evaluates each component of the inertia tensor at the specified
440+
time and returns a :class:`rocketpy.mathutils.Matrix` object.
439441

440442
The inertia tensor is a matrix that looks like this:
441443

rocketpy/motors/motor.py

+6
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,12 @@ def __init__(self):
13521352
self.dry_I_12 = 0
13531353
self.dry_I_13 = 0
13541354
self.dry_I_23 = 0
1355+
self.propellant_I_11 = Function(0, "Time (s)", "Propellant I_11 (kg m²)")
1356+
self.propellant_I_22 = Function(0, "Time (s)", "Propellant I_22 (kg m²)")
1357+
self.propellant_I_33 = Function(0, "Time (s)", "Propellant I_33 (kg m²)")
1358+
self.propellant_I_12 = Function(0, "Time (s)", "Propellant I_12 (kg m²)")
1359+
self.propellant_I_13 = Function(0, "Time (s)", "Propellant I_13 (kg m²)")
1360+
self.propellant_I_23 = Function(0, "Time (s)", "Propellant I_23 (kg m²)")
13551361
self.I_11 = Function(0)
13561362
self.I_22 = Function(0)
13571363
self.I_33 = Function(0)

rocketpy/rocket/rocket.py

+27-27
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ def evaluate_static_margin(self):
596596

597597
def evaluate_dry_inertias(self):
598598
"""Calculates and returns the rocket's dry inertias relative to
599-
the rocket's center of mass. The inertias are saved and returned
599+
the rocket's center of dry mass. The inertias are saved and returned
600600
in units of kg*m². This does not consider propellant mass but does take
601601
into account the motor dry mass.
602602
@@ -605,27 +605,27 @@ def evaluate_dry_inertias(self):
605605
self.dry_I_11 : float
606606
Float value corresponding to rocket inertia tensor 11
607607
component, which corresponds to the inertia relative to the
608-
e_1 axis, centered at the instantaneous center of mass.
608+
e_1 axis, centered at the center of dry mass.
609609
self.dry_I_22 : float
610610
Float value corresponding to rocket inertia tensor 22
611611
component, which corresponds to the inertia relative to the
612-
e_2 axis, centered at the instantaneous center of mass.
612+
e_2 axis, centered at the center of dry mass.
613613
self.dry_I_33 : float
614614
Float value corresponding to rocket inertia tensor 33
615615
component, which corresponds to the inertia relative to the
616-
e_3 axis, centered at the instantaneous center of mass.
616+
e_3 axis, centered at the center of dry mass.
617617
self.dry_I_12 : float
618618
Float value corresponding to rocket inertia tensor 12
619619
component, which corresponds to the inertia relative to the
620-
e_1 and e_2 axes, centered at the instantaneous center of mass.
620+
e_1 and e_2 axes, centered at the center of dry mass.
621621
self.dry_I_13 : float
622622
Float value corresponding to rocket inertia tensor 13
623623
component, which corresponds to the inertia relative to the
624-
e_1 and e_3 axes, centered at the instantaneous center of mass.
624+
e_1 and e_3 axes, centered at the center of dry mass.
625625
self.dry_I_23 : float
626626
Float value corresponding to rocket inertia tensor 23
627627
component, which corresponds to the inertia relative to the
628-
e_2 and e_3 axes, centered at the instantaneous center of mass.
628+
e_2 and e_3 axes, centered at the center of dry mass.
629629
630630
Notes
631631
-----
@@ -681,23 +681,23 @@ def evaluate_dry_inertias(self):
681681

682682
def evaluate_inertias(self):
683683
"""Calculates and returns the rocket's inertias relative to
684-
the rocket's center of mass. The inertias are saved and returned
684+
the rocket's center of dry mass. The inertias are saved and returned
685685
in units of kg*m².
686686
687687
Returns
688688
-------
689689
self.I_11 : float
690690
Float value corresponding to rocket inertia tensor 11
691691
component, which corresponds to the inertia relative to the
692-
e_1 axis, centered at the instantaneous center of mass.
692+
e_1 axis, centered at the center of dry mass.
693693
self.I_22 : float
694694
Float value corresponding to rocket inertia tensor 22
695695
component, which corresponds to the inertia relative to the
696-
e_2 axis, centered at the instantaneous center of mass.
696+
e_2 axis, centered at the center of dry mass.
697697
self.I_33 : float
698698
Float value corresponding to rocket inertia tensor 33
699699
component, which corresponds to the inertia relative to the
700-
e_3 axis, centered at the instantaneous center of mass.
700+
e_3 axis, centered at the center of dry mass.
701701
702702
Notes
703703
-----
@@ -714,25 +714,25 @@ def evaluate_inertias(self):
714714
"""
715715
# Get masses
716716
prop_mass = self.motor.propellant_mass # Propellant mass as a function of time
717-
dry_mass = self.dry_mass # Constant rocket mass with motor, without propellant
718717

719718
# Compute axes distances
720-
CM_to_CDM = self.center_of_mass - self.center_of_dry_mass_position
721-
CM_to_CPM = self.center_of_mass - self.center_of_propellant_position
719+
CDM_to_CPM = (
720+
self.center_of_dry_mass_position - self.center_of_propellant_position
721+
)
722722

723723
# Compute inertias
724-
self.I_11 = parallel_axis_theorem_from_com(
725-
self.dry_I_11, dry_mass, CM_to_CDM
726-
) + parallel_axis_theorem_from_com(self.motor.I_11, prop_mass, CM_to_CPM)
724+
self.I_11 = self.dry_I_11 + parallel_axis_theorem_from_com(
725+
self.motor.propellant_I_11, prop_mass, CDM_to_CPM
726+
)
727727

728-
self.I_22 = parallel_axis_theorem_from_com(
729-
self.dry_I_22, dry_mass, CM_to_CDM
730-
) + parallel_axis_theorem_from_com(self.motor.I_22, prop_mass, CM_to_CPM)
728+
self.I_22 = self.dry_I_22 + parallel_axis_theorem_from_com(
729+
self.motor.propellant_I_22, prop_mass, CDM_to_CPM
730+
)
731731

732-
self.I_33 = self.dry_I_33 + self.motor.I_33
733-
self.I_12 = self.dry_I_12 + self.motor.I_12
734-
self.I_13 = self.dry_I_13 + self.motor.I_13
735-
self.I_23 = self.dry_I_23 + self.motor.I_23
732+
self.I_33 = self.dry_I_33 + self.motor.propellant_I_33
733+
self.I_12 = self.dry_I_12 + self.motor.propellant_I_12
734+
self.I_13 = self.dry_I_13 + self.motor.propellant_I_13
735+
self.I_23 = self.dry_I_23 + self.motor.propellant_I_23
736736

737737
# Return inertias
738738
return (
@@ -814,7 +814,7 @@ def evaluate_com_to_cdm_function(self):
814814

815815
def get_inertia_tensor_at_time(self, t):
816816
"""Returns a Matrix representing the inertia tensor of the rocket with
817-
respect to the rocket's center of mass at a given time. It evaluates
817+
respect to the rocket's center of dry mass at a given time. It evaluates
818818
each inertia tensor component at the given time and returns a Matrix
819819
with the computed values.
820820
@@ -844,8 +844,8 @@ def get_inertia_tensor_at_time(self, t):
844844

845845
def get_inertia_tensor_derivative_at_time(self, t):
846846
"""Returns a Matrix representing the time derivative of the inertia
847-
tensor of the rocket with respect to the rocket's center of mass at a
848-
given time. It evaluates each inertia tensor component's derivative at
847+
tensor of the rocket with respect to the rocket's center of dry mass at
848+
a given time. It evaluates each inertia tensor component's derivative at
849849
the given time and returns a Matrix with the computed values.
850850
851851
Parameters

rocketpy/simulation/flight.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,6 @@ def u_dot(
14001400
* self.rocket._csys
14011401
)
14021402
c = self.rocket.nozzle_to_cdm
1403-
a = self.rocket.com_to_cdm_function.get_value_opt(t)
14041403
nozzle_radius = self.rocket.motor.nozzle_radius
14051404
# Prepare transformation matrix
14061405
a11 = 1 - 2 * (e2**2 + e3**2)
@@ -1503,8 +1502,8 @@ def u_dot(
15031502
R1 += comp_lift_xb
15041503
R2 += comp_lift_yb
15051504
# Add to total moment
1506-
M1 -= (comp_cp + a) * comp_lift_yb
1507-
M2 += (comp_cp + a) * comp_lift_xb
1505+
M1 -= (comp_cp) * comp_lift_yb
1506+
M2 += (comp_cp) * comp_lift_xb
15081507
# Calculates Roll Moment
15091508
try:
15101509
clf_delta, cld_omega, cant_angle_rad = aero_surface.roll_parameters
@@ -1779,8 +1778,8 @@ def u_dot_generalized(
17791778
R1 += comp_lift_xb
17801779
R2 += comp_lift_yb
17811780
# Add to total moment
1782-
M1 -= (comp_cpz + r_CM_t) * comp_lift_yb
1783-
M2 += (comp_cpz + r_CM_t) * comp_lift_xb
1781+
M1 -= (comp_cpz) * comp_lift_yb
1782+
M2 += (comp_cpz) * comp_lift_xb
17841783
# Calculates Roll Moment
17851784
try:
17861785
clf_delta, cld_omega, cant_angle_rad = aero_surface.roll_parameters

tests/unit/test_flight.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ def test_out_of_rail_stability_margin(flight_calisto_custom_wind):
167167
@pytest.mark.parametrize(
168168
"flight_time, expected_values",
169169
[
170-
("t_initial", (0.17179073815516033, -0.431117, 0)),
171-
("out_of_rail_time", (0.543760, -1.364593, 0)),
172-
("apogee_time", (-0.5874848151271623, -0.7563596, 0)),
170+
("t_initial", (0.258818, -0.649515, 0)),
171+
("out_of_rail_time", (0.788918, -1.979828, 0)),
172+
("apogee_time", (-0.522394, -0.744154, 0)),
173173
("t_final", (0, 0, 0)),
174174
],
175175
)
@@ -208,7 +208,7 @@ def test_aerodynamic_moments(flight_calisto_custom_wind, flight_time, expected_v
208208
[
209209
("t_initial", (1.6542528, 0.65918, -0.067107)),
210210
("out_of_rail_time", (5.05334, 2.01364, -1.7541)),
211-
("apogee_time", (2.366258, -1.830744, -0.875342)),
211+
("apogee_time", (2.354663, -1.652953, -0.936126)),
212212
("t_final", (0, 0, 159.2212)),
213213
],
214214
)
@@ -247,7 +247,10 @@ def test_aerodynamic_forces(flight_calisto_custom_wind, flight_time, expected_va
247247
[
248248
("t_initial", (0, 0, 0)),
249249
("out_of_rail_time", (0, 2.248727, 25.703072)),
250-
("apogee_time", (-13.204789, 15.990903, -0.000138)),
250+
(
251+
"apogee_time",
252+
(-14.485655, 15.580647, -0.000240),
253+
),
251254
("t_final", (5, 2, -5.65998)),
252255
],
253256
)
@@ -334,10 +337,10 @@ def test_rail_buttons_forces(flight_calisto_custom_wind):
334337
"""
335338
test = flight_calisto_custom_wind
336339
atol = 5e-3
337-
assert pytest.approx(3.876749, abs=atol) == test.max_rail_button1_normal_force
338-
assert pytest.approx(1.544799, abs=atol) == test.max_rail_button1_shear_force
339-
assert pytest.approx(1.178420, abs=atol) == test.max_rail_button2_normal_force
340-
assert pytest.approx(0.469574, abs=atol) == test.max_rail_button2_shear_force
340+
assert pytest.approx(1.825283, abs=atol) == test.max_rail_button1_normal_force
341+
assert pytest.approx(0.727335, abs=atol) == test.max_rail_button1_shear_force
342+
assert pytest.approx(3.229578, abs=atol) == test.max_rail_button2_normal_force
343+
assert pytest.approx(1.286915, abs=atol) == test.max_rail_button2_shear_force
341344

342345

343346
def test_max_values(flight_calisto_robust):

tests/unit/test_rocket.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,9 @@ def test_evaluate_com_to_cdm_function(calisto):
458458
def test_get_inertia_tensor_at_time(calisto):
459459
# Expected values (for t = 0)
460460
# TODO: compute these values by hand or using CAD.
461-
I_11 = 10.31379
462-
I_22 = 10.31379
463-
I_33 = 0.039942
461+
I_11 = 10.516647727227216
462+
I_22 = 10.516647727227216
463+
I_33 = 0.0379420341586346
464464

465465
# Set tolerance threshold
466466
atol = 1e-5
@@ -484,9 +484,9 @@ def test_get_inertia_tensor_at_time(calisto):
484484
def test_get_inertia_tensor_derivative_at_time(calisto):
485485
# Expected values (for t = 2s)
486486
# TODO: compute these values by hand or using CAD.
487-
I_11_dot = -0.634805230901143
488-
I_22_dot = -0.634805230901143
489-
I_33_dot = -0.000671493662305
487+
I_11_dot = -0.7164327431607691
488+
I_22_dot = -0.7164327431607691
489+
I_33_dot = -0.0006714936623050
490490

491491
# Set tolerance threshold
492492
atol = 1e-3

0 commit comments

Comments
 (0)