How can I animate this double pendulum?

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}


• 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. Mar 7, 2021 at 13:40

(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}

\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]{%
\immediate\openin#1=#2%
}
% reads a line from file stream and splits at <sep char> into \list[1], \list[2], ...
\setsepchar{#1}%
\ifeof#2
\immediate\closein#2%
\ifdefined\multiframebreak\multiframebreak\fi%
\else%
\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}%
\multiframe{100000}{}{
\begin{tikzpicture}%
\useasboundingbox (-4.2,-4.2) rectangle (4.2,4.2);
\node[anchor=north west, inner sep=0pt] at (-4.2,4.2) {\strut$t=\qty{\fpeval{trunc(\table[1])}}{\second}$};