Summary
The TVC path reduces axial thrust and applies the moments of a deflected thrust vector, but the lateral components of that same vector never reach the translational equations.
In rocketpy/simulation/flight.py, u_dot_generalized:
thrust3 = effective_thrust * np.sqrt(
1 - np.sin(gimbal_angle_x * pi/180) ** 2 - np.sin(gimbal_angle_y * pi/180) ** 2
)
tvc_lever = self.rocket.nozzle_to_cdm
M1 += np.sin(gimbal_angle_x * pi/180) * effective_thrust * tvc_lever
M2 += np.sin(gimbal_angle_y * pi/180) * effective_thrust * tvc_lever
R1 and R2 only ever accumulate aerodynamic contributions (R1 += X, R2 += Y from the surfaces). I could not find T*sin(x) or T*sin(y) being added anywhere, and the body-axis equations use R1 and R2 as they stand while the axial one adds thrust3.
So a gimbal command produces a moment and a reduced axial force, but no lateral force on the centre of mass. The same physical force cannot do one without the other.
Numbers
With a 15 degree limit on each axis, commanding both at once:
|
|
| omitted lateral force |
0.366 * T |
thrust3 |
0.931 * T |
| actual combined deflection |
21.47 degrees |
That last row is worth noting separately. Two independent 15 degree axes reach a combined deflection of 21.47 degrees, so a parameter documented as a maximum gimbal angle does not bound what the model actually applies.
There is also a domain problem at larger limits: sin(x)^2 + sin(y)^2 > 1 makes the square root argument negative, which happens once both axes exceed 45 degrees. Nothing validates that when the actuator range is configured.
Is it deliberate?
I considered that TVC might be intended as a pure control-moment actuator. If it were, thrust3 would not be reduced by the deflection. Reducing it is what says the code means to model a real deflected vector, so this reads as an oversight rather than a modelling choice.
Suggestion
Build the body-frame thrust vector once and use it for both sides:
F = effective_thrust * Vector([sin(x), sin(y), sqrt(1 - sin(x)**2 - sin(y)**2)])
# translational: add F
# rotational: add r x F
That keeps the force and the moment consistent by construction rather than by two formulas that have to be kept in step, and it removes the question of which convention each one follows.
Worth deciding at the same time whether the configured limit is per axis or a total cone angle, and validating the two-axis domain so the square root cannot go negative.
A regression test could assert that the force norm equals the effective thrust, that both lateral components are non-zero for a two-axis command, and that the moment matches r x F.
Context
Found while reviewing the TVC integration in BalloonPoppingChallenge, which pins this code. It does not affect that competition's fairness, since every entrant runs the same model, and I am not proposing to change it there before their release. Raising it here because it is a physics question rather than an integration one.
Summary
The TVC path reduces axial thrust and applies the moments of a deflected thrust vector, but the lateral components of that same vector never reach the translational equations.
In
rocketpy/simulation/flight.py,u_dot_generalized:R1andR2only ever accumulate aerodynamic contributions (R1 += X,R2 += Yfrom the surfaces). I could not findT*sin(x)orT*sin(y)being added anywhere, and the body-axis equations useR1andR2as they stand while the axial one addsthrust3.So a gimbal command produces a moment and a reduced axial force, but no lateral force on the centre of mass. The same physical force cannot do one without the other.
Numbers
With a 15 degree limit on each axis, commanding both at once:
0.366 * Tthrust30.931 * TThat last row is worth noting separately. Two independent 15 degree axes reach a combined deflection of 21.47 degrees, so a parameter documented as a maximum gimbal angle does not bound what the model actually applies.
There is also a domain problem at larger limits:
sin(x)^2 + sin(y)^2 > 1makes the square root argument negative, which happens once both axes exceed 45 degrees. Nothing validates that when the actuator range is configured.Is it deliberate?
I considered that TVC might be intended as a pure control-moment actuator. If it were,
thrust3would not be reduced by the deflection. Reducing it is what says the code means to model a real deflected vector, so this reads as an oversight rather than a modelling choice.Suggestion
Build the body-frame thrust vector once and use it for both sides:
That keeps the force and the moment consistent by construction rather than by two formulas that have to be kept in step, and it removes the question of which convention each one follows.
Worth deciding at the same time whether the configured limit is per axis or a total cone angle, and validating the two-axis domain so the square root cannot go negative.
A regression test could assert that the force norm equals the effective thrust, that both lateral components are non-zero for a two-axis command, and that the moment matches
r x F.Context
Found while reviewing the TVC integration in BalloonPoppingChallenge, which pins this code. It does not affect that competition's fairness, since every entrant runs the same model, and I am not proposing to change it there before their release. Raising it here because it is a physics question rather than an integration one.