@@ -55,25 +55,29 @@ Introduction
5555In chapters, :ref: `Holonomic Constraints ` and :ref: `Nonholonomic Constraints `,
5656I introduced two types of constraints: holonomic (configuration) constraints
5757and nonholonomic (motion) constraints. Holonomic constraints are nonlinear
58- constraints in the coordinates [# ]_. Nonholonomic constraints are linear in the
59- generalized speeds, by definition. We will address the nonholonomic equations
60- of motion first, as they are slightly easier to deal with.
58+ constraints in the coordinates [# ]_. Nonholonomic constraints are linear
59+ constraints in the generalized speeds, by definition. We will address the
60+ nonholonomic equations of motion first, as they are slightly easier to deal
61+ with due to their linearity.
6162
6263.. [# ] They can be linear in the coordinates, but then there is little reason
63- not to solve for the depedendent coordinates and eliminate them.
64+ not to solve for the depedendent coordinates explicitly and eliminate them.
6465
6566 Nonholonomic constraint equations are linear in both the independent and
6667dependent generalized speeds (see Sec. :ref: `Snakeboard `). We have shown that
6768you can explicitly solve for the dependent generalized speeds :math: `\bar {u}_r`
68- as a function of the independent generalized speeds :math: `\bar {u}_s`. This
69- means that number of dynamical differential equations can be reduced to
70- :math: `p` from :math: `n` with :math: `m` nonholonomic constraints. Recall that
71- the nonholonomic constraints take this form:
69+ as a function of the independent generalized speeds :math: `\bar {u}_s` as long
70+ as :math: `\mathbf {A}_r` is invertible. This implies that number of dynamical
71+ differential equations can be reduced to :math: `p` from :math: `n` with
72+ :math: `m` nonholonomic constraints. Recall that the nonholonomic constraints
73+ take this form:
7274
7375.. math ::
7476 :label: eq-nonholonomic-constraints
7577
76- \bar {f}_n(\bar {u}_s, \bar {u}_r, \bar {q}, t) = \mathbf {M}_n\bar {u}_r + \bar {g}_n = 0 \in \mathbb {R}^m
78+ \bar {f}_n(\bar {u}_s, \bar {u}_r, \bar {q}, t)
79+ = \mathbf {M}_n(\bar {q}, t)\bar {u}_r + \bar {g}_n(\bar {u}_s, \bar {q}, t)
80+ = 0 \in \mathbb {R}^m
7781
7882 and :math: `u_r` can be solved for as so:
7983
@@ -83,21 +87,60 @@ and :math:`u_r` can be solved for as so:
8387 \bar {u}_r = -\mathbf {M}_n(\bar {q}, t)^{-1 }\bar {g}_n(\bar {u}_s, \bar {q}, t)
8488
8589 which is the same as Eq. :math:numref: `eq-constraint-linear-form-solve ` we
86- originally developed:
90+ originally developed in Sec. :ref: ` Snakeboard ` :
8791
8892.. math ::
8993 :label: eq-dep-speeds-repeat
9094
91- \bar {u}_r = \mathbf {A}_n \bar {u}_s + \bar {b}_n\\
95+ \bar {u}_r = \mathbf {A}_n \bar {u}_s + \bar {b}_n \in \mathbb {R}^m
9296
93- Using Eq. :math:numref: `eq-dep-speeds-solve ` equation we can now write our
97+ If you partition the holonomic (unconstrained) dynamical differential equations
98+ into:
99+
100+ .. math ::
101+
102+ \bar {F}_r + \bar {F}_r^* =
103+ \bar {f}_d(\dot {\bar {u}}, \bar {u}, \bar {q}, t)
104+ =
105+ \begin {bmatrix}
106+ \bar {f}_{ds}(\dot {\bar {u}}, \bar {u}, \bar {q}, t) \\
107+ \bar {f}_{dr}(\dot {\bar {u}}, \bar {u}, \bar {q}, t) \\
108+ \end {bmatrix}
109+ = 0 \in \mathbb {R}^n
110+
111+ where :math: `\bar {f}_{ds}` and :math: `\bar {f}_{dr}` are the equations
112+ associated with the :math: `p` independent and :math: `m` dependent generalized
113+ speeds, respectively. Then using :math:numref: `eq-non-hol-fr ` and
114+ :math:numref: `eq-non-hol-frstar ` the :math: `p` nonholonomic (constrained)
115+ dynamical differential equations are:
116+
117+ .. math ::
118+
119+ \tilde {F}_r + \tilde {F}_r^* =
120+ \bar {f}_{ds}(\dot {\bar {u}}, \bar {u}, \bar {q}, t)
121+ + \mathbf {A}_n^T \bar {f}_{dr}(\dot {\bar {u}}, \bar {u}, \bar {q}, t)
122+ = 0 \in \mathbb {R}^p
123+
124+ and combined with Eq. :math:numref: `eq-dep-speeds-repeat ` give a set of
125+ :math: `n` differential algebraic equations of differentiation index 1.
126+
127+ You can time differentiate Eq. :math:numref: `eq-dep-speeds-repeat ` to get:
128+
129+ .. math ::
130+
131+ \dot {\bar {u}}_r = \dot {\mathbf {A}}_n \bar {u}_s + \mathbf {A}_n \dot {\bar {u}}_s + \dot {\bar {b}}_n \\
132+
133+ and the :math: `n` differential algebraic equations can be reduced fully to
134+ :math: `p` unique ordinary differential equations by substituting all
135+ :math: `\dot {\bar {u}}_r` and :math: `\bar {u}_r`. This lets you write the full
94136equations of motion as :math: `n` kinematical differential equations and
95- :math: `p` dynamical differential equations.
137+ :math: `p` dynamical differential equations, which are all ordinary differential
138+ equations.
96139
97140.. math ::
98141 :label: eq-nonholonomic-eom
99142
100- \bar {f}_k(\bar {u}_s , \dot { \ bar {q}} , \bar {q}, t) = \mathbf {M}_k\dot {\bar {q}} + \bar {g}_k = 0 \in \mathbb {R}^n \\
143+ \bar {f}_k(\dot { \ bar {q}} , \bar {u}_s , \bar {q}, t) = \mathbf {M}_k\dot {\bar {q}} + \bar {g}_k = 0 \in \mathbb {R}^n \\
101144 \bar {f}_d(\dot {\bar {u}}_s, \bar {u}_s, \bar {q}, t) = \mathbf {M}_d\dot {\bar {u}}_s + \bar {g}_d = 0 \in \mathbb {R}^p
102145
103146 and these can be written in explicit form:
@@ -128,8 +171,8 @@ inertia of the three bodies are the same.
128171
129172 Configuration diagram of a planar Snakeboard model.
130173
131- 1. Declare all the variables
132- ----------------------------
174+ Declare all the variables
175+ -------------------------
133176
134177First introduce the necessary variables; adding :math: `I` for the central
135178moment of inertia of each body and :math: `m` as the mass of each body. Then
@@ -177,8 +220,8 @@ expressions we create.
177220
178221 urd_zero, usd_zero
179222
180- 2. Establish the kinematics
181- ---------------------------
223+ Establish the kinematics
224+ ------------------------
182225
183226The following code sets up the orientations, positions, and velocities exactly
184227as done in the original example. All of the velocities are in terms of
@@ -212,8 +255,8 @@ as done in the original example. All of the velocities are in terms of
212255 Bo.v2pt_theory(Ao, N, A)
213256 Co.v2pt_theory(Ao, N, A);
214257
215- 3. Specify the kinematical differential equations
216- -------------------------------------------------
258+ Specify the kinematical differential equations
259+ ----------------------------------------------
217260
218261Now create the :math: `n=5 ` kinematical differential equations
219262:math: `\bar {f}_k`:
@@ -248,8 +291,8 @@ dictionary we can use for substitutions:
248291 qd_repl = dict(zip(qd, qd_sol))
249292 qd_repl
250293
251- 4. Establish the nonholonomic constraints
252- -----------------------------------------
294+ Establish the nonholonomic constraints
295+ --------------------------------------
253296
254297Create the :math: `m=2 ` nonholonomic constraints:
255298
@@ -270,14 +313,15 @@ and rewrite them in terms of the generalized speeds:
270313 me.find_dynamicsymbols(fn)
271314
272315With the nonholonomic constraint equations we choose :math: `\bar {u}_r=[u_1 \
273- u_2 ]^T` and symbolically for these dependent speeds.
316+ u_2 ]^T` and symbolically solve for these dependent speeds.
274317
275318.. jupyter-execute ::
276319
277320 Mn = fn.jacobian(ur)
278321 gn = fn.xreplace(ur_zero)
279322 ur_sol = Mn.LUsolve(-gn)
280323 ur_repl = dict(zip(ur, ur_sol))
324+ ur_repl
281325
282326In our case, the dependent generalized speeds are only a function of one
283327independent generalized speed, :math: `u_3 `.
@@ -301,8 +345,11 @@ later use in our numerical functions.
301345
302346 me.find_dynamicsymbols(gk)
303347
304- 5. Rewrite velocities in terms of independent speeds
305- ----------------------------------------------------
348+ Approach 1: Substitute dependent generalized speeds first
349+ =========================================================
350+
351+ Rewrite velocities in terms of independent speeds
352+ -------------------------------------------------
306353
307354The snakeboard model, as described, has no generalized active forces because
308355there are no contributing external forces acting on the system, so we only need
@@ -325,8 +372,8 @@ speeds.
325372 for vel in vels:
326373 print(me.find_dynamicsymbols(vel, reference_frame=N))
327374
328- 6. Compute the partial velocities
329- ---------------------------------
375+ Compute the partial velocities
376+ ------------------------------
330377
331378With the velocities only in terms of the independent generalized speeds, we can
332379calculate the :math: `p` nonholonomic partial velocities:
@@ -335,8 +382,8 @@ calculate the :math:`p` nonholonomic partial velocities:
335382
336383 w_A, w_B, w_C, v_Ao, v_Bo, v_Co = me.partial_velocity(vels, us, N)
337384
338- 7. Rewrite the accelerations in terms of the independent generalized speeds
339- ---------------------------------------------------------------------------
385+ Rewrite the accelerations in terms of the independent generalized speeds
386+ ------------------------------------------------------------------------
340387
341388We can also write the accelerations in terms of only the independent
342389generalized speeds, their time derivatives, and the generalized coordinates. To
@@ -376,8 +423,8 @@ dependent generalized speeds in :math:`\bar{g}_{nd}` instead of
376423
377424 me.find_dynamicsymbols(urd_sol)
378425
379- 8. Create the generalized forces
380- --------------------------------
426+ Create the generalized forces
427+ -----------------------------
381428
382429Now we can form the inertia forces and inertia torques. First check what
383430derivatives appear in the accelerations.
@@ -454,8 +501,8 @@ and eliminate the dependent generalized accelerations:
454501 me.find_dynamicsymbols(Ts_B, reference_frame=N) |
455502 me.find_dynamicsymbols(Ts_C, reference_frame=N))
456503
457- 9. Formulate the dynamical differential equations
458- -------------------------------------------------
504+ Formulate the dynamical differential equations
505+ ----------------------------------------------
459506
460507All of the components are present to formulate the nonholonomic generalized
461508inertia forces. After we form them, make sure they are only a function of the
@@ -502,7 +549,127 @@ coordinates.
502549We now have :math: `\mathbf {M}_k, \bar {g}_k, \mathbf {M}_d` and :math: `\bar {g}_d`
503550and can proceed to numerical evaluation.
504551
505- .. todo :: Also show how Fr and Frs can be formed using An.
552+ Approach 2: Use :math: `\mathbf {A}_n` and substitute dependent generalized speeds last
553+ =====================================================================================
554+
555+ Write all important velocity vectors in terms of all of the generalized speeds
556+ (as opposed to only the independent generalized speeds shown in Approach 1).
557+
558+ .. jupyter-execute ::
559+
560+ N_w_A = A.ang_vel_in(N).xreplace(qd_repl)
561+ N_w_B = B.ang_vel_in(N).xreplace(qd_repl)
562+ N_w_C = C.ang_vel_in(N).xreplace(qd_repl)
563+ N_v_Ao = Ao.vel(N).xreplace(qd_repl)
564+ N_v_Bo = Bo.vel(N).xreplace(qd_repl)
565+ N_v_Co = Co.vel(N).xreplace(qd_repl)
566+
567+ vels = (N_w_A, N_w_B, N_w_C, N_v_Ao, N_v_Bo, N_v_Co)
568+
569+ for vel in vels:
570+ print(me.find_dynamicsymbols(vel, reference_frame=N))
571+
572+ Treat the system as an unconstrained system (holonomic) and calculate all
573+ :math: `n` partial velocities for each important velocity:
574+
575+ .. jupyter-execute ::
576+
577+ w_A, w_B, w_C, v_Ao, v_Bo, v_Co = me.partial_velocity(vels, u, N)
578+
579+ Formulate the holonomic dynamical differential equations
580+ --------------------------------------------------------
581+
582+ Write all accelerations in terms of all of the generalized speeds and their
583+ derivatives.
584+
585+ .. jupyter-execute ::
586+
587+ qdd_repl = {k.diff(t): v.diff(t).xreplace(qd_repl) for k, v in qd_repl.items()}
588+ qdd_repl
589+
590+ .. jupyter-execute ::
591+
592+ Rs_Ao = -m*Ao.acc(N).xreplace(qdd_repl)
593+ Rs_Bo = -m*Bo.acc(N).xreplace(qdd_repl)
594+ Rs_Co = -m*Co.acc(N).xreplace(qdd_repl)
595+ Ts_A = -A.ang_acc_in(N).dot(I_A_Ao).xreplace(qdd_repl)
596+ Ts_B = -B.ang_acc_in(N).dot(I_B_Bo).xreplace(qdd_repl)
597+ Ts_C = -C.ang_acc_in(N).dot(I_C_Co).xreplace(qdd_repl)
598+
599+ Write the holonomic :math: `\bar {F}_r^*` with :math: `n=5 ` elements that are a
600+ function of all generalized speeds and their time derivatives.
601+
602+ .. jupyter-execute ::
603+
604+ Frs = []
605+ for i in range(len(u)):
606+ Frs.append(v_Ao[i].dot(Rs_Ao) + v_Bo[i].dot(Rs_Bo) + v_Co[i].dot(Rs_Co) +
607+ w_A[i].dot(Ts_A) + w_B[i].dot(Ts_B) + w_C[i].dot(Ts_C))
608+ Frs = sm.Matrix(Frs)
609+
610+ Frs.shape, me.find_dynamicsymbols(Frs)
611+
612+ Formulate the nonholonomic dynamical differential equations
613+ -----------------------------------------------------------
614+
615+ Calculate :math: `\mathbf {A}_n` from the nonholonomic constraints.
616+
617+ .. jupyter-execute ::
618+
619+ An = sm.trigsimp(fn.jacobian(ur).LUsolve(-fn.jacobian(us)))
620+ An
621+
622+ Now partition :math: `\bar {F}_r^*` and form :math: `\tilde {F}_r^*` noting it has
623+ :math: `p=3 ` elements that are still functions of all generalized speeds and their
624+ time derivatives.
625+
626+ .. jupyter-execute ::
627+
628+ fdr = Frs[:2, 0]
629+ fds = Frs[2:, 0]
630+
631+ Frs_tilde = fds + An.transpose()*fdr
632+
633+ Frs_tilde.shape, me.find_dynamicsymbols(Frs_tilde)
634+
635+ Combined with :math: `\bar {f}_n`, the dynamical differential algebraic
636+ equations of index 1, :math: `\bar {f}_d(\dot {\bar {u}}, \bar {u}, \bar {q}, t)`,
637+ are formed:
638+
639+ .. jupyter-execute ::
640+
641+ fd = Frs_tilde.col_join(fn)
642+ sm.trigsimp(fd)
643+
644+ These are a function of all the generalized speeds.
645+
646+ .. jupyter-execute ::
647+
648+ me.find_dynamicsymbols(fd)
649+
650+ To reduce to a set of :math: `p` ordinary differential equations, substitute to
651+ remove the dependent speeds and their derivatives.
652+
653+ .. jupyter-execute ::
654+
655+ fd = Frs_tilde.xreplace(urd_repl).xreplace(ur_repl)
656+ me.find_dynamicsymbols(fd)
657+
658+ Now :math: `\mathbf {M}_d` and :math: `\mathbf {g}_d` are identical to the those
659+ found in Approach 1.
660+
661+ .. jupyter-execute ::
662+
663+ Md = fd.jacobian(usd)
664+ gd = fd.xreplace(usd_zero)
665+
666+ .. jupyter-execute ::
667+
668+ me.find_dynamicsymbols(Md)
669+
670+ .. jupyter-execute ::
671+
672+ me.find_dynamicsymbols(gd)
506673
507674Simulate the Snakeboard
508675=======================
0 commit comments