|
| 1 | +.. _tipoff: |
| 2 | + |
| 3 | +=========================================== |
| 4 | +Tip-off: the 3-DOF Single Rail Button Phase |
| 5 | +=========================================== |
| 6 | + |
| 7 | +Introduction |
| 8 | +------------ |
| 9 | + |
| 10 | +Between the moment the *upper* rail button leaves the launch rail and the moment |
| 11 | +the *lower* button follows it, the rocket is still guided --- but only at one |
| 12 | +point. It slides along the rail while free to pitch and yaw about that remaining |
| 13 | +button. This short interval is what the literature calls **tip-off**, and it sets |
| 14 | +the attitude and angular rate with which the rocket begins free flight. |
| 15 | + |
| 16 | +This document derives the equations of motion used by |
| 17 | +:meth:`rocketpy.Flight.udot_rail2`, the flight phase that models this interval. |
| 18 | +It is enabled with ``Flight(..., use_udot_rail2=True)``; when disabled (the |
| 19 | +default) the simulation transitions straight from the 1-DOF rail phase to the |
| 20 | +generalized 6-DOF equations, exactly as it did before this phase existed. |
| 21 | + |
| 22 | +Because the phase works by patching the *generalized* 6-DOF solution with a |
| 23 | +constraint wrench built from the full inertia tensor, it requires |
| 24 | +``simulation_mode="6 DOF"`` and ``equations_of_motion="standard"``. The reduced |
| 25 | +formulations do not carry the state the patch describes --- the 3 DOF equations |
| 26 | +model no attitude at all, and ``solid_propulsion`` uses a different, |
| 27 | +axisymmetric set --- so asking for the tip-off phase together with either of |
| 28 | +them raises a ``ValueError`` instead of silently producing non-physical |
| 29 | +kinematics. Note that a point-mass motor forces ``simulation_mode`` to |
| 30 | +``"3 DOF"``, and therefore cannot be combined with this phase either. |
| 31 | + |
| 32 | +The three flight phases around rail departure are, in order of the distance |
| 33 | +``d`` travelled from the launch point: |
| 34 | + |
| 35 | +.. math:: |
| 36 | +
|
| 37 | + \begin{aligned} |
| 38 | + \texttt{udot_rail1} \quad & \text{for } d < \ell_1 |
| 39 | + && \text{(both buttons engaged, 1 DOF)} \\ |
| 40 | + \texttt{udot_rail2} \quad & \text{for } \ell_1 \le d < \ell_2 |
| 41 | + && \text{(upper button gone, lower engaged, 3 DOF)} \\ |
| 42 | + \texttt{u_dot_generalized} \quad & \text{for } d \ge \ell_2 |
| 43 | + && \text{(free flight, 6 DOF)} |
| 44 | + \end{aligned} |
| 45 | +
|
| 46 | +where :math:`\ell_1` and :math:`\ell_2` are the ``effective_1rl`` and |
| 47 | +``effective_2rl`` attributes of :class:`rocketpy.Flight` --- the distances at |
| 48 | +which the upper and the lower button reach the end of the rail. Their difference |
| 49 | +is the button-to-button distance, so the phase has zero length for a rocket with |
| 50 | +a single rail button and is skipped in that case. |
| 51 | + |
| 52 | +Frames and conventions |
| 53 | +---------------------- |
| 54 | + |
| 55 | +The solver integrates the same 13-element state vector used by the other |
| 56 | +right-hand sides, |
| 57 | + |
| 58 | +.. math:: |
| 59 | +
|
| 60 | + \mathbf{u} = [\,x,\ y,\ z,\ v_x,\ v_y,\ v_z,\ e_0,\ e_1,\ e_2,\ e_3,\ |
| 61 | + \omega_1,\ \omega_2,\ \omega_3\,] |
| 62 | +
|
| 63 | +with :math:`\mathbf{r} = [x, y, z]` the inertial position of the **center of dry |
| 64 | +mass** (CDM, the tracked point), :math:`\mathbf{v}` its inertial velocity, |
| 65 | +:math:`\mathbf{e}` the attitude quaternion and :math:`\boldsymbol{\omega}` the |
| 66 | +angular velocity in the **body** frame. The matrix |
| 67 | +:math:`\mathbf{K} = \texttt{Matrix.transformation}(\mathbf{e})` rotates body |
| 68 | +components into inertial ones, and :math:`\hat{\mathbf{z}}_b = [0, 0, 1]` is the |
| 69 | +body roll (symmetry) axis. |
| 70 | + |
| 71 | +The relevant mass geometry at time :math:`t`, in the body frame, is the total |
| 72 | +mass :math:`m`, the CDM-to-center-of-mass offset :math:`\mathbf{r}_{CM}`, and the |
| 73 | +inertia tensor about the CDM, :math:`\mathbf{I}`. Shifting the latter to the |
| 74 | +instantaneous center of mass gives |
| 75 | + |
| 76 | +.. math:: |
| 77 | +
|
| 78 | + \mathbf{I}_{CM} = \mathbf{I} - m\left(|\mathbf{r}_{CM}|^2 \mathbb{1} |
| 79 | + - \mathbf{r}_{CM}\mathbf{r}_{CM}^{\mathsf T}\right). |
| 80 | +
|
| 81 | +**Rail geometry.** The rail is a line fixed in the inertial frame, set by the |
| 82 | +launch inclination and heading. Its unit vector is the ``attitude_unit`` |
| 83 | +attribute of :class:`rocketpy.Flight`; the constrained body point is the lower |
| 84 | +rail button, at the fixed body position :math:`\mathbf{r}_{B}` relative to the |
| 85 | +CDM. |
| 86 | + |
| 87 | +The constraint |
| 88 | +-------------- |
| 89 | + |
| 90 | +A free rigid body has six degrees of freedom. The single engaged button removes |
| 91 | +three of them: |
| 92 | + |
| 93 | +#. **The button stays on the rail line.** Its position may only vary along the |
| 94 | + rail, so the component of its acceleration perpendicular to the rail |
| 95 | + vanishes. That is **two** scalar constraints. |
| 96 | +#. **Roll is suppressed** by the button in its rail slot: |
| 97 | + :math:`\dot{\boldsymbol{\omega}} \cdot \hat{\mathbf{z}}_b = 0`. That is |
| 98 | + **one** more. |
| 99 | + |
| 100 | +Three constraints leave :math:`6 - 3 = 3` degrees of freedom: translation along |
| 101 | +the rail, pitch and yaw --- the 3 DOF this phase is named for. |
| 102 | + |
| 103 | +The forces that enforce them are the unknowns of the problem: |
| 104 | + |
| 105 | +* a **normal reaction** at the button, perpendicular to the rail because a |
| 106 | + frictionless slot can neither pull nor push along it. Writing an orthonormal |
| 107 | + body triad :math:`\{\hat{\mathbf{e}}_1, \hat{\mathbf{e}}_2, \hat{\mathbf{n}}_b\}` |
| 108 | + around the body-frame rail direction |
| 109 | + :math:`\hat{\mathbf{n}}_b = \mathbf{K}^{\mathsf T}\hat{\mathbf{n}}`, it has two |
| 110 | + components: :math:`\mathbf{N}_b = \lambda_1 \hat{\mathbf{e}}_1 + \lambda_2 |
| 111 | + \hat{\mathbf{e}}_2`; |
| 112 | +* a **roll reaction moment** :math:`\mu \hat{\mathbf{z}}_b` about the body axis. |
| 113 | + |
| 114 | +Three unknowns, three constraints: a :math:`3\times3` linear system, solved once |
| 115 | +per evaluation of the right-hand side. |
| 116 | + |
| 117 | +The initial conditions are consistent with the constraint. The phase is entered |
| 118 | +from ``udot_rail1``, where the rocket has no angular velocity and its velocity is |
| 119 | +along the rail, so the button's perpendicular *velocity* is already zero. |
| 120 | +Enforcing zero perpendicular *acceleration* therefore keeps it on the rail. |
| 121 | + |
| 122 | +Augmented dynamics |
| 123 | +------------------ |
| 124 | + |
| 125 | +The generalized equations of motion assemble a total force |
| 126 | +:math:`\mathbf{T}_{20}` and a total moment about the CDM :math:`\mathbf{T}_{21}`, |
| 127 | +both in the body frame, and solve |
| 128 | + |
| 129 | +.. math:: |
| 130 | +
|
| 131 | + \dot{\boldsymbol{\omega}}_{\text{free}} = \mathbf{I}_{CM}^{-1} |
| 132 | + \left(\mathbf{T}_{21} + \mathbf{T}_{20} \times \mathbf{r}_{CM}\right), |
| 133 | + \qquad |
| 134 | + \mathbf{a}_{\text{free}} = \frac{\mathbf{T}_{20}}{m} |
| 135 | + - \mathbf{r}_{CM} \times \dot{\boldsymbol{\omega}}_{\text{free}}. |
| 136 | +
|
| 137 | +Both totals are *sums of external contributions*, which is what makes the |
| 138 | +constraint clean to add: the reaction wrench simply enters the sums, |
| 139 | + |
| 140 | +.. math:: |
| 141 | +
|
| 142 | + \mathbf{T}_{20}' = \mathbf{T}_{20} + \mathbf{N}_b, |
| 143 | + \qquad |
| 144 | + \mathbf{T}_{21}' = \mathbf{T}_{21} + \mathbf{r}_{B} \times \mathbf{N}_b |
| 145 | + + \mu \hat{\mathbf{z}}_b, |
| 146 | +
|
| 147 | +after which the same two lines apply. Since the solve is linear in the totals, |
| 148 | +the result splits into the free solution plus a response to the unknowns. Using |
| 149 | +:math:`\mathbf{r}_B \times \mathbf{N} + \mathbf{N} \times \mathbf{r}_{CM} |
| 150 | += (\mathbf{r}_B - \mathbf{r}_{CM}) \times \mathbf{N}` and writing |
| 151 | +:math:`\mathbf{d} = \mathbf{r}_{B} - \mathbf{r}_{CM}` for the center-of-mass-to-button |
| 152 | +vector, |
| 153 | + |
| 154 | +.. math:: |
| 155 | +
|
| 156 | + \Delta\dot{\boldsymbol{\omega}} = \mathbf{I}_{CM}^{-1} |
| 157 | + \left(\mathbf{d} \times \mathbf{N}_b + \mu \hat{\mathbf{z}}_b\right), |
| 158 | + \qquad |
| 159 | + \Delta\mathbf{a} = \frac{\mathbf{N}_b}{m} |
| 160 | + - \mathbf{r}_{CM} \times \Delta\dot{\boldsymbol{\omega}}. |
| 161 | +
|
| 162 | +The button is body-fixed, so its acceleration in body components is |
| 163 | + |
| 164 | +.. math:: |
| 165 | +
|
| 166 | + \mathbf{A} = \mathbf{A}_{\text{free}} + \Delta\mathbf{a} |
| 167 | + + \Delta\dot{\boldsymbol{\omega}} \times \mathbf{r}_{B}, |
| 168 | + \qquad |
| 169 | + \mathbf{A}_{\text{free}} = \mathbf{K}^{\mathsf T}\mathbf{a}_{\text{free}} |
| 170 | + + \dot{\boldsymbol{\omega}}_{\text{free}} \times \mathbf{r}_{B} |
| 171 | + + \boldsymbol{\omega} \times |
| 172 | + \left(\boldsymbol{\omega} \times \mathbf{r}_{B}\right). |
| 173 | +
|
| 174 | +The linear solve |
| 175 | +---------------- |
| 176 | + |
| 177 | +Collect the unknowns in :math:`\boldsymbol{\chi} = [\lambda_1, \lambda_2, \mu]`. |
| 178 | +The three constraints read |
| 179 | + |
| 180 | +.. math:: |
| 181 | +
|
| 182 | + \mathbf{A} \cdot \hat{\mathbf{e}}_1 = 0, |
| 183 | + \qquad |
| 184 | + \mathbf{A} \cdot \hat{\mathbf{e}}_2 = 0, |
| 185 | + \qquad |
| 186 | + \dot{\boldsymbol{\omega}} \cdot \hat{\mathbf{z}}_b = 0, |
| 187 | +
|
| 188 | +and because :math:`\mathbf{A}` and :math:`\dot{\boldsymbol{\omega}}` are linear |
| 189 | +in :math:`\boldsymbol{\chi}`, they form the system |
| 190 | +:math:`\mathbf{J}\boldsymbol{\chi} = -\mathbf{g}_{\text{free}}` with |
| 191 | + |
| 192 | +.. math:: |
| 193 | +
|
| 194 | + \mathbf{g}_{\text{free}} = |
| 195 | + \begin{bmatrix} |
| 196 | + \mathbf{A}_{\text{free}} \cdot \hat{\mathbf{e}}_1 \\ |
| 197 | + \mathbf{A}_{\text{free}} \cdot \hat{\mathbf{e}}_2 \\ |
| 198 | + \dot{\boldsymbol{\omega}}_{\text{free}} \cdot \hat{\mathbf{z}}_b |
| 199 | + \end{bmatrix}. |
| 200 | +
|
| 201 | +Each column of :math:`\mathbf{J}` is obtained by evaluating the response above at |
| 202 | +one of the three unit inputs :math:`(\mathbf{N}_b, \mu) = |
| 203 | +(\hat{\mathbf{e}}_1, 0)`, :math:`(\hat{\mathbf{e}}_2, 0)`, |
| 204 | +:math:`(\mathbf{0}, 1)`. Solving for :math:`\boldsymbol{\chi}` and substituting |
| 205 | +back gives the constrained accelerations, which override the free ones in the |
| 206 | +returned derivative: |
| 207 | + |
| 208 | +.. math:: |
| 209 | +
|
| 210 | + \dot{\boldsymbol{\omega}} = \dot{\boldsymbol{\omega}}_{\text{free}} |
| 211 | + + \Delta\dot{\boldsymbol{\omega}}, |
| 212 | + \qquad |
| 213 | + \mathbf{a}_{CDM} = \mathbf{a}_{\text{free}} |
| 214 | + + \mathbf{K}\,\Delta\mathbf{a}. |
| 215 | +
|
| 216 | +The position and quaternion derivatives are the ordinary kinematic ones. In |
| 217 | +particular :math:`\dot{\mathbf{r}} = \mathbf{v}`: the velocity is **not** |
| 218 | +projected onto the rail. The constraint acts at the acceleration level on the |
| 219 | +*button*, and the CDM legitimately acquires a small perpendicular velocity as the |
| 220 | +rocket pitches about that button. |
| 221 | + |
| 222 | +Modelling assumptions and edge cases |
| 223 | +------------------------------------ |
| 224 | + |
| 225 | +* **Roll axis.** The constraint suppresses roll about the *body* axis. The rocket |
| 226 | + travels only the button-to-button distance during this phase, so the tip-off |
| 227 | + angle is small and the body axis stays close to the rail direction; the |
| 228 | + difference between body roll and rail-axis roll is of that order. This is |
| 229 | + consistent with ``udot_rail1``, which freezes rotation entirely. |
| 230 | +* **Radial button offset.** The button is modelled on the rocket axis. The roll |
| 231 | + constraint is enforced explicitly by :math:`\mu`, so what is lost is only the |
| 232 | + (small) roll coupling through the button's radial standoff. |
| 233 | +* **Zero-length phase.** A rocket with a single rail button has |
| 234 | + :math:`\ell_1 = \ell_2`, and the phase is skipped. |
| 235 | +* **Singular system.** Should the geometry make :math:`\mathbf{J}` singular, the |
| 236 | + step falls back to the unconstrained dynamics and warns. |
| 237 | + |
| 238 | +Expected behaviour |
| 239 | +------------------ |
| 240 | + |
| 241 | +The phase reproduces the two effects tip-off is modelled for. With no wind, the |
| 242 | +center of mass sits ahead of the button that the rocket now pivots about, so |
| 243 | +gravity pitches the nose down by a fraction of a degree. With a crosswind, the |
| 244 | +aerodynamic moment turns the rocket into the wind before it is fully free --- |
| 245 | +the weathercock effect --- and the rocket therefore leaves the rail with a small |
| 246 | +angular rate rather than none. |
| 247 | + |
| 248 | +Reading the results |
| 249 | +------------------- |
| 250 | + |
| 251 | +The window itself is recorded on the :class:`rocketpy.Flight` object, so a |
| 252 | +dispersion study does not have to recover it from the raw solution: |
| 253 | + |
| 254 | +.. list-table:: |
| 255 | + :header-rows: 1 |
| 256 | + :widths: 30 70 |
| 257 | + |
| 258 | + * - Attribute |
| 259 | + - Meaning |
| 260 | + * - ``out_of_rail_time`` |
| 261 | + - Time the *upper* button leaves the rail, starting the window. |
| 262 | + * - ``between_rails_time`` |
| 263 | + - Time the *lower* button leaves the rail, ending the window. |
| 264 | + * - ``between_rails_velocity`` |
| 265 | + - Speed at that moment, the true rail-departure velocity. |
| 266 | + * - ``between_rails_state`` |
| 267 | + - Full state vector handed to the free-flight phase. |
| 268 | + * - ``tip_off_duration`` |
| 269 | + - Length of the window, zero when the phase is disabled. |
| 270 | + |
| 271 | +``Flight.info()`` prints these under a *Tip-Off State* heading whenever the |
| 272 | +phase ran, and the attitude plots shade the window so the change in attitude |
| 273 | +during tip-off can be read off directly. |
| 274 | + |
| 275 | +References |
| 276 | +---------- |
| 277 | + |
| 278 | +The tip-off phase and its effect on the initial conditions of free flight are |
| 279 | +treated in the launcher dynamics literature: [Chou]_ studies a vehicle moving |
| 280 | +along an inclined guideway with dynamic interactions, and [Hosken]_ analyses |
| 281 | +tip-off effects in rail launchers. |
0 commit comments