9

I want to visualize an animation of a double pendulum, but I don't know how to do it, since I'm new to the animate package, here's the code of the double pendulum (tikz) :

    \documentclass[tikz,border=8mm]{standalone}
\usetikzlibrary{backgrounds,angles,quotes}
\begin{document}

\begin{tikzpicture}[%
angle eccentricity=1.2,
ball/.style={circle, inner sep=0pt, minimum size=2mm, fill=blue, draw=blue, label=right:$m$},
background rectangle/.style={fill=black},
show background rectangle]

\draw[thick, white] (-2,0) --(2,0);
\draw[white] (0,0) coordinate (b0) foreach \i [count=\ni] in {-70,-55} {--++(\i:2cm) node[midway,auto]{$l$} node[ball] (b\ni) {}};

\foreach \i [count=\auxi] in {b0,b1}{
    \draw[dashed, white] (\i)--++(-90:1.8cm) coordinate[pos=.75] (aux\auxi);
} 

\draw pic["$\theta_1$", draw, white, angle radius=1.2cm] {angle=aux1--b0--b1};
\draw pic["$\theta_2$", draw, white, angle radius=1.2cm] {angle=aux2--b1--b2};

\end{tikzpicture}

\end{document}

tik

1
  • 1
    You would have to solve the equation of motion (ordinary diff equation) to calculate theta_1 and theta_2 as a function of time. You could do this within LaTeX with pkg pst-ode and draw the animation frames with PSTricks.
    – AlexG
    Mar 7, 2021 at 13:40

1 Answer 1

14

(Plotting animation frames with TikZ)

To animate the double pendulum, we have to solve the equation of motion, which is a set of Ordinary Differential Equations (ODE). For the friction-less double-pendulum of two different point masses, the differential equations for the swing angles θ1 and θ2 are given at the end of section 1 in this french Wikipedia article:

https://fr.wikipedia.org/wiki/Pendule_double#Mise_en_%C3%A9quation_utilisant_l'approche_lagrangienne

Both equations (1) & (2) are implicit and coupled in the angular accelerations. To make the first one explicit, Eq. (2) is substituted into (1) and (1) is resolved for \ddot{θ1}.

To solve the system of ODEs within LaTeX, we can use package pst-ode (method: RKF45). It is a PSTricks package, but thanks to luapstricks, a PostScript interpreter by Marcel Krüger, the example below can be typeset directly with lualatex; ps2pdf (Ghostscript) is no longer needed.

The file timeTheta1Theta2.dat written during the first run is read line by line to get time and the angles at each step. The animation frames are finally plotted with TikZ.

These are the parameters you may want to play with:

/tEnd 70 def                                % time span to be simulated [s]
/m1 1 def                                   % mass1 [kg]
/m2 1 def                                   % mass2 [kg]
/l1 2 def                                   % pendulum1 length [m]
/l2 2 def                                   % pendulum2 length [m]
/G 9.81 def                                 % acceleration [m/s^2]
/theta1zero 179 Pi mul 180 div def          % theta1_0=179°
/theta2zero 180 Pi mul 180 div def          % theta2_0=180°

Realtime animation over 70 s. Click to run animation (If Firefox is too slow, try a Chromium-based browser instead.)

Typeset three times with lualatex:

%\PassOptionsToPackage{dvisvgm}{animate} % dvilualatex <file> ; dvisvgm --zoom=-1 --font-format=woff2 --bbox=papersize <file>.dvi 
\documentclass[margin=1mm,varwidth]{standalone} 
 
\usepackage{pst-ode} 
\usepackage[controls,autoplay]{animate} 
\usepackage{tikz} 
\usepackage{listofitems} % read space separated items 
\usepackage{siunitx} 
\usepackage{xfp} 
\usepackage[T1]{fontenc} 
 
% adjustable parameters & definitions 
\pstVerb{ 
  tx@Dict begin 
  /tEnd 70 def                                % time span to be simulated [s] 
  /m1 1 def                                   % mass1 [kg] 
  /m2 1 def                                   % mass2 [kg] 
  /l1 2 def                                   % pendulum1 length [m] 
  /l2 2 def                                   % pendulum2 length [m] 
  /G 9.81 def                                 % acceleration [m/s^2] 
  /theta1zero 179 Pi mul 180 div def          % theta1_0=179° 
  /theta2zero 180 Pi mul 180 div def          % theta2_0=180° 
  /N (cvi(tEnd*25+1)) AlgParser cvx exec def  % (integer) number of time steps (for 25 frames per s) + 1 
  % 
  /M2 (m2/(m1+m2)) AlgParser cvx exec def     % some constants 
  /rM2 (1/M2) AlgParser cvx exec def 
  /l12 (l1/l2) AlgParser cvx exec def 
  /l21 (l2/l1) AlgParser cvx exec def 
  /G1 (G/l1) AlgParser cvx exec def 
  /G2 (G/l2) AlgParser cvx exec def 
  /G1M2 (G1/M2) AlgParser cvx exec def 
  % 
  /theta1Dot (x[2]) AlgParser cvx def         % 1st order ODE system 
  /theta2Dot (x[3]) AlgParser cvx def 
  /omega1Dot (((G1*sin(x[1])-x[2]^2*sin(x[0]-x[1]))*cos(x[0]-x[1])-l21*x[3]^2*sin(x[0]-x[1])-G1M2*sin(x[0])) 
    /(rM2-cos(x[0]-x[1])^2)) AlgParser cvx def 
  /omega2Dot (-l12*(omega1Dot*cos(x[0]-x[1])-x[2]^2*sin(x[0]-x[1]))-G2*sin(x[1])) AlgParser cvx def 
  end 
} 
 
% solve equations of motion 
\pstODEsolve[algebraicAll,saveData]{timeTheta1Theta2}{% PS variable that takes result list 
  t | x[0]*180/Pi-90 | x[1]*180/Pi-90 % table format of data to be saved in timeTheta1Theta2 
}{0}{tEnd}{N}{                        % t_0, t_end, number of  time steps + 1 
  theta1zero | theta2zero | 0 | 0     % initial conditions 
}{ 
  theta1Dot | theta2Dot | omega1Dot | omega2Dot  % ODE system's RHS 
} 
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
% \fileopenr{<file stream>}{<file name>}, opens file for reading 
\newcommand\fileopenr[2]{% 
  \newread#1% 
  \immediate\openin#1=#2% 
} 
% \readtolist[<sep char>]{<file stream>}{\list} 
% reads a line from file stream and splits at <sep char> into \list[1], \list[2], ... 
\newcommand\readtolist[3][,]{{% 
  \setsepchar{#1}% 
  \immediate\read#2 to \inputline% 
    \ifeof#2 
      \immediate\closein#2% 
      \ifdefined\multiframebreak\multiframebreak\fi% 
    \else% 
      \greadlist*#3\inputline% 
    \fi% 
}} 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 
\begin{document} 
 
$l_1=l_2=\qty{2}{\metre}$; $m_1=m_2=\qty{1}{\kilogram}$\\ 
\IfFileExists{timeTheta1Theta2.dat}{}{\end{document}}% 
\begin{animateinline}{25} 
  \fileopenr{\data}{timeTheta1Theta2.dat}% 
  \readtolist[ ]{\data}{\table}% 
  \multiframe{100000}{}{ 
    \begin{tikzpicture}% 
      \useasboundingbox (-4.2,-4.2) rectangle (4.2,4.2); 
      \filldraw (0,0) -- ++(\table[2]:2) circle[radius=1mm] -- ++(\table[3]:2) circle[radius=1mm]; 
      \filldraw [fill=white] (0,0) circle [radius=1pt]; 
      \node[anchor=north west, inner sep=0pt] at (-4.2,4.2) {\strut$t=\qty{\fpeval{trunc(\table[1])}}{\second}$}; 
    \end{tikzpicture}% 
    \readtolist[ ]{\data}{\table}% 
  } 
\end{animateinline} 
 
\end{document} 
10
  • +1: Amazing! Do you have an mechanical engineering background? Mar 7, 2021 at 23:13
  • 1
    Chemical engineering, and a lot of procrastination for whatelse is needed.
    – AlexG
    Mar 7, 2021 at 23:15
  • The equations to be solved I simply copied, without understanding, from the Wikipedia article.
    – AlexG
    Mar 7, 2021 at 23:18
  • I see! Cool that this is within the capability of TeX and friends. Mar 7, 2021 at 23:19
  • 1
    On pstricks.blogspot.com, search for "pst-ode animate". Very nice examples will be shown!
    – AlexG
    Mar 7, 2021 at 23:37

You must log in to answer this question.