Py.Cafe

jackparmer/

3d-double-pendulum

Street Fighter画像パッケージ

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import numpy as np
from scipy.integrate import solve_ivp

# Initialize the Dash app
app = dash.Dash(__name__)

# Physical constants
g = 9.81  # Acceleration due to gravity
L1 = 1.0  # Length of first pendulum
L2 = 1.0  # Length of second pendulum
m1 = 1.0  # Mass of first pendulum
m2 = 1.0  # Mass of second pendulum

# Initial conditions: [theta1, omega1, theta2, omega2]
initial_conditions = [np.pi / 4, 0, np.pi / 2, 0]

# Time array
t = np.linspace(0, 20, 800)

# Differential equations of motion
def equations(t, y):
    theta1, omega1, theta2, omega2 = y

    delta = theta2 - theta1

    denominator1 = (m1 + m2) * L1 - m2 * L1 * np.cos(delta) * np.cos(delta)
    denominator2 = (L2 / L1) * denominator1

    dydt = np.zeros_like(y)
    dydt[0] = omega1
    dydt[1] = (m2 * L1 * omega1 * omega1 * np.sin(delta) * np.cos(delta) +
               m2 * g * np.sin(theta2) * np.cos(delta) +
               m2 * L2 * omega2 * omega2 * np.sin(delta) -
               (m1 + m2) * g * np.sin(theta1)) / denominator1
    dydt[2] = omega2
    dydt[3] = (-m2 * L2 * omega2 * omega2 * np.sin(delta) * np.cos(delta) +
               (m1 + m2) * g * np.sin(theta1) * np.cos(delta) -
               (m1 + m2) * L1 * omega1 * omega1 * np.sin(delta) -
               (m1 + m2) * g * np.sin(theta2)) / denominator2
    return dydt

# Solve the differential equations
sol = solve_ivp(equations, [0, t[-1]], initial_conditions, t_eval=t, method='RK45')

theta1 = sol.y[0]
theta2 = sol.y[2]

# Convert angles to Cartesian coordinates
x1 = L1 * np.sin(theta1)
y1 = -L1 * np.cos(theta1)
z1 = np.zeros_like(x1)
x2 = x1 + L2 * np.sin(theta2)
y2 = y1 - L2 * np.cos(theta2)
z2 = np.zeros_like(x2)

# Define the layout of the Dash app
app.layout = html.Div([
    html.H1("3D Double Pendulum Simulation", style={'color': 'black', 'textAlign': 'center'}),
    dcc.Graph(id='pendulum-graph'),
    dcc.Interval(id='interval-component', interval=50, n_intervals=0)
], style={'backgroundColor': 'white', 'padding': '20px'})

# Define the callback to update the pendulum positions
@app.callback(
    Output('pendulum-graph', 'figure'),
    [Input('interval-component', 'n_intervals')]
)
def update_pendulum(n):
    index = n % len(t)

    fig = go.Figure()

    # Add the first pendulum arm
    fig.add_trace(go.Scatter3d(
        x=[0, x1[index]], y=[0, y1[index]], z=[0, z1[index]],
        mode='lines+markers',
        line=dict(color='blue', width=3),
        marker=dict(size=5, color='blue')
    ))

    # Add the second pendulum arm
    fig.add_trace(go.Scatter3d(
        x=[x1[index], x2[index]], y=[y1[index], y2[index]], z=[z1[index], z2[index]],
        mode='lines+markers',
        line=dict(color='red', width=3),
        marker=dict(size=5, color='red')
    ))

    fig.update_layout(
        scene=dict(
            xaxis=dict(range=[-2, 2], autorange=False),
            yaxis=dict(range=[-2, 2], autorange=False),
            zaxis=dict(range=[-2, 2], autorange=False),
            aspectratio=dict(x=1, y=1, z=1)
        ),
        margin=dict(l=0, r=0, t=0, b=0)
    )

    return fig

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True)