Triple Pendulum
Acrobatics of a simple physical model
Original code and equations by Peter Tenisheff (tenishefff@yandex.ru)
This Demonstration simulates the motion of a free moving triple pendulum using basic numerics of Wolfram.
Download original notebookEquations of Motion
The equations of motion for a triple pendulum system can be more compactly written using notations :
where:
and is the acceleration due to gravity, are the masses, are the lengths of the pendulums, and are the angles with the vertical.
Here is corresponding system rewritten using WL:
ClearAll[g, m, l, timeMax, \[Theta]1, \[Theta]2, \[Theta]3]; g = 9.81; (*SbB[*)Subscript[m(*|*),(*|*)1](*]SbB*) = 1; (*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) = 1; (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) = 1; (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) = 1; (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) = 1; (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) = 1; timeMax = 10; eqns = { ((*SbB[*)Subscript[m(*|*),(*|*)1](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SpB[*)Power[(*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*)(*|*),(*|*)2](*]SpB*) \[Theta]1''[t] + ((*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) \[Theta]2''[t] Cos[\[Theta]1[t] - \[Theta]2[t]] + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) \[Theta]3''[t] Cos[\[Theta]1[t] - \[Theta]3[t]] + ((*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) (*SpB[*)Power[\[Theta]2'[t](*|*),(*|*)2](*]SpB*) Sin[\[Theta]1[t] - \[Theta]2[t]] + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) (*SpB[*)Power[\[Theta]3'[t](*|*),(*|*)2](*]SpB*) Sin[\[Theta]1[t] - \[Theta]3[t]] + g ((*SbB[*)Subscript[m(*|*),(*|*)1](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) Sin[\[Theta]1[t]] == 0, ((*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SpB[*)Power[(*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*)(*|*),(*|*)2](*]SpB*) \[Theta]2''[t] + ((*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) \[Theta]1''[t] Cos[\[Theta]1[t] - \[Theta]2[t]] + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) \[Theta]3''[t] Cos[\[Theta]2[t] - \[Theta]3[t]] - ((*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) \[Theta]1'[t]^2 Sin[\[Theta]1[t] - \[Theta]2[t]] + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) (*SpB[*)Power[\[Theta]3'[t](*|*),(*|*)2](*]SpB*) Sin[\[Theta]2[t] - \[Theta]3[t]] + g ((*SbB[*)Subscript[m(*|*),(*|*)2](*]SbB*) + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*)) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) Sin[\[Theta]2[t]] == 0, (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SpB[*)Power[(*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*)(*|*),(*|*)2](*]SpB*) \[Theta]3''[t] + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) \[Theta]1''[t] Cos[\[Theta]1[t] - \[Theta]3[t]] + (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) \[Theta]2''[t] Cos[\[Theta]2[t] - \[Theta]3[t]] - (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) (*SpB[*)Power[\[Theta]1'[t](*|*),(*|*)2](*]SpB*) Sin[\[Theta]1[t] - \[Theta]3[t]] - (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) (*SpB[*)Power[\[Theta]2'[t](*|*),(*|*)2](*]SpB*) Sin[\[Theta]2[t] - \[Theta]3[t]] + g (*SbB[*)Subscript[m(*|*),(*|*)3](*]SbB*) (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) Sin[\[Theta]3[t]] == 0 }; initCond = { \[Theta]1[0] == (*FB[*)((\[Pi])(*,*)/(*,*)(2))(*]FB*) - 0.1, \[Theta]2[0] == \[Pi], \[Theta]3[0] == \[Pi], \[Theta]1'[0] == 0, \[Theta]2'[0] == 0, \[Theta]3'[0] == 0 };
Now let's solve it using numerical methods:
sol = NDSolve[{eqns, initCond}, {\[Theta]1, \[Theta]2, \[Theta]3}, {t, 0, timeMax}] // First
Some shorthand notations:
ClearAll[xC, yC]; With[{ \[Phi]1 = \[Theta]1 /. sol, \[Phi]2 = \[Theta]2 /. sol, \[Phi]3 = \[Theta]3 /. sol }, xC[t_, 1] := (*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) Sin[\[Phi]1[t]]; yC[t_, 1] := -(*SbB[*)Subscript[l(*|*),(*|*)1](*]SbB*) Cos[\[Phi]1[t]]; xC[t_, 2] := xC[t, 1] + (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) Sin[\[Phi]2[t]]; yC[t_, 2] := yC[t, 1] - (*SbB[*)Subscript[l(*|*),(*|*)2](*]SbB*) Cos[\[Phi]2[t]]; xC[t_, 3] := xC[t, 2] + (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) Sin[\[Phi]3[t]]; yC[t_, 3] := yC[t, 2] - (*SbB[*)Subscript[l(*|*),(*|*)3](*]SbB*) Cos[\[Phi]3[t]]; ]; trajectories = Table[Table[{xC[t, i], yC[t, i]}, {i, 3}], {t, 0, timeMax, 0.05}]; trajectories = trajectories // Transpose;
Animation
Let's animate the motion of our triple pendulum. Initially, we will use points for the joints of the pendulum connected by a black line. Here, we use a custom UpdateFunction for Animate to avoid costly reevaluation of the entire plot:
Module[{points, tracks}, Animate[ Graphics[ { { Directive[TransitionType->None], {Gray, Opacity[0.25], Line[tracks[[3]] // Offload ]}, {Red, Opacity[0.15], Line[tracks[[2]] // Offload ]}, {Blue, Opacity[0.15], Line[tracks[[1]] // Offload ]} }, Black, Line[{{0, 0}, points[[1]], points[[2]], points[[3]]} // Offload], Blue, PointSize[0.03], Point[points[[1]] // Offload], Red, PointSize[0.03], Point[points[[2]] // Offload], Green, PointSize[0.04], Point[points[[3]] // Offload] }, PlotRange -> {{-3, 3}, {-3, 3}}, Prolog->{Line[{{-3,0}, {3,0}}]}, Axes -> True, Frame->True, Background -> White, ImageSizeRaw -> {450,450} ], {t, 0, timeMax, 0.05}, AnimationRate -> 30, "UpdateFunction" -> Function[t, tracks = trajectories[[All, ;; Floor[t / 0.05] + 1]]; points = Table[{xC[t, i], yC[t, i]}, {i, 3}]; False ] ] ]
(*VB[*)(FrontEndRef["9b7a3593-b78b-4d80-b84f-b4d42c41192c"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKWyaZJxqbWhrrJplbJOmapFgY6CZZmKTpJpmkmBglmxgaWholAwCCLxV4"*)(*]VB*)
By default, Graphics smooths the motion of lines and points, which might lead to some artifacts for continuous lines representing the full trajectory of each joint. Therefore, we explicitly disable it in Directive for them.
Extras
Here is another version of it with pictures placed on a graph instead of basic points:
Module[{points}, Animate[ Graphics[ { Brown, {AbsoluteThickness[4], Line[{{0, 0}, points[[1]], points[[2]], points[[3]]} // Offload]}, Inset[ColorNegate[(*VB[*)(FrontEndRef["8b049d7d-d9ab-4a67-a50c-19a72ab7f93c"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKWyQZmFimmKfoplgmJumaJJqZ6yaaGiTrGlommhslJpmnWRonAwCK1hYH"*)(*]VB*)], {0,0}], Blue, PointSize[0.03], Inset[(*VB[*)(FrontEndRef["8b049d7d-d9ab-4a67-a50c-19a72ab7f93c"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKWyQZmFimmKfoplgmJumaJJqZ6yaaGiTrGlommhslJpmnWRonAwCK1hYH"*)(*]VB*), points[[1]] // Offload], Red, PointSize[0.03], Inset[(*VB[*)(FrontEndRef["8b049d7d-d9ab-4a67-a50c-19a72ab7f93c"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKWyQZmFimmKfoplgmJumaJJqZ6yaaGiTrGlommhslJpmnWRonAwCK1hYH"*)(*]VB*), points[[2]] // Offload], Green, PointSize[0.04], Inset[(*VB[*)(FrontEndRef["8b049d7d-d9ab-4a67-a50c-19a72ab7f93c"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKWyQZmFimmKfoplgmJumaJJqZ6yaaGiTrGlommhslJpmnWRonAwCK1hYH"*)(*]VB*), points[[3]] // Offload] }, PlotRange -> {{-3, 3}, {-3, 3}}, Prolog->{Line[{{-3,0}, {3,0}}]}, Axes -> True, Frame->True, Background -> White, TransitionType->None, ImageSizeRaw -> {450,450} ], {t, 0, timeMax, 0.05}, AnimationRate -> 30, "UpdateFunction" -> Function[t, points = Table[{xC[t, i], yC[t, i]}, {i, 3}]; False ] ] ]
(*VB[*)(FrontEndRef["8564d026-49fc-4c29-b787-b26363dff908"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKW5iamaQYGJnpmlimJeuaJBtZ6iaZW5jrJhmZGZsZp6SlWRpYAAB4WhUt"*)(*]VB*)
Click on a play above button to run the animation