Animation of the movement of a pendulum using Julia
This example shows the implementation of simulating the movement of a physical pendulum using differential equations and creating animations in the Julia programming language.
Introduction
A pendulum is the simplest physical system widely used to study periodic motion and oscillations. In this example, we consider the problem of modeling the motion of a simple pendulum using a system of second-order ordinary differential equations, which is then solved in the framework of a boundary value problem using the collocation method (MIRK). After finding a solution, it is visualized in GIF animation format using the Luxor.jl library based on Cairo.
The main goal is to demonstrate the capabilities of the Julia language in numerical solution of physical problems and generation of graphical visualization. Animation allows you to understand the dynamics of a pendulum's movement — how it moves through time, starting from a given position and ending at the opposite point after a certain time interval.
# Установка требуемых пакетов
import Pkg; Pkg.add("Luxor")
import Pkg; Pkg.add("Colors")
import Pkg; Pkg.add("BoundaryValueDiffEq")
Connecting libraries
using Luxor # для рисования анимации
using Colors # для управления цветами элементов анимации
using BoundaryValueDiffEq # для решения краевых задач обыкновенных дифференциальных уравнений
Defining constants and parameters for the model
Constants of the physical model and animation
const g = 9.81; # ускорение свободного падения (м/с²)
const L = 1.0; # длина нити маятника (метры)
const bobd = 0.10; # диаметр груза (bob) маятника (в метрах)
Animation Parameters
const framerate = 50.0; # частота кадров анимации (кадр/сек)
const t_0 = 0.0; # начальное время моделирования (сек)
const tf = 2.3; # конечное время моделирования (сек)
const dtframe = 1.0/framerate; # длительность 1 кадра в секундах
const tspan = LinRange(t_0, tf, Int(floor(tf*framerate))); # массив моментов времени для анимации
Colors and file names
const bgcolor = "black"; # цвет фона анимации
const leaderhue = (0.80, 0.70, 0.20); # светло-золотой цвет для рычага
const hslcolors = [HSL(col) for col in (distinguishable_colors(
Int(floor(tf*framerate)+3),[RGB(1,1,1)])[2:end])]; # набор цветов для элементов
const giffilename = "pendulum.gif"; # имя выходного файла GIF
Formulation of the problem and solution of the differential equation
Definition of a function for the equations of motion of a pendulum
function simplependulum(du, u, p, t)
θ = u[1] # угол отклонения
dθ = u[2] # скорость изменения угла (угловая скорость)
du[1] = dθ # производная угла = угловая скорость
du[2] = -(g/L) * sin(θ) # уравнение движения: θ'' = -(g/L) * sin(θ)
end
Setting boundary conditions
function bc2(residual, u, p, t)
residual[1] = u[end÷2][1] + pi/2 # значение угла в середине интервала равно π/2 (положение слева)
residual[2] = u[end][1] - pi/2 # значение угла в конце равно -π/2 (положение справа)
end
Formation and solution of the boundary value problem
bvp2 = BVProblem(simplependulum, bc2, [pi/2, pi/2], (tspan[1], tspan[end]));
sol2 = solve(bvp2, MIRK4(), dt=dtframe); # метод Рунге–Кутты 4-го порядка с коррекцией
Animation rendering functions
Background function for rendering a frame
function backdrop(scene, framenumber)
background(bgcolor) # установка черного фона
end
The main function of drawing each frame is
function anim_frame(scene, framenumber)
# Получаем текущие значения угла и угловой скорости
u1, u2 = sol2.u[framenumber]
# Вычисляем координаты центра боба по формулам тригонометрии
y = L * cos(u1)
x = L * sin(u1)
# Нарисовать рычаг (от точки подвеса до груза)
sethue(leaderhue)
poly([Point(-4.0, 0.0), Point(4.0, 0.0),
Point(160.0x, 160.0y)], :fill)
# Нарисовать груз (bob) маятника
sethue(Colors.HSV(framenumber*4.0, 1, 1)) # меняющийся цвет в зависимости от номера кадра
circle(Point(160.0x, 160.0y), 160*bobd, :fill)
# Напечатать информацию о текущем кадре
Luxor.text(string("frame $framenumber of $(scene.framerange.stop)"),
Point(0.0, -190.0), halign=:center)
end
Creating and playing animations
Creating an animation object with the specified window size
muv = Movie(400, 400, "Pendulum Demo", 1:length(tspan))
Adding two scenes: the background and the main one
Luxor.animate(muv, [
Luxor.Scene(muv, backdrop), # фоновая сцена
Luxor.Scene(muv, anim_frame, easingfunction=easeinoutcubic) # главная сцена с плавным переходом
], creategif=true, pathname=joinpath(@__DIR__, giffilename)) # создаём .gif и сохраняем его под именем "pendulum.gif"
Conclusion
We have reviewed a program in the Julia language that solves a boundary value problem for a pendulum motion model and builds a smooth animation in GIF format based on it. Key elements: physical model (equations of motion), numerical solution (MIRK4 method), and visualization (using Luxor). This approach is useful not only for educational purposes, but also for modeling more complex systems with constraints on initial or final conditions. This example illustrates the powerful scientific computing and graphical visualization tools in the Julia ecosystem.
The example was developed using materials from Rosetta Code
