# Double Pendulum with Python package PyDy


```python
from __future__ import print_function, division
from sympy import symbols, simplify
from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame, Point
from sympy.physics.vector import init_vprinting
init_vprinting(use_latex='mathjax', pretty_print=False)
from sympy.physics.mechanics import inertia, RigidBody
from sympy import trigsimp
from sympy.physics.mechanics import KanesMethod
from numpy import deg2rad, rad2deg, array, zeros, linspace
from scipy.integrate import odeint
from pydy.codegen.ode_function_generators import generate_ode_function
import matplotlib.pyplot as plt
import ipywidgets as widgets
from ivisual import *
from IPython.display import display, clear_output
```


<div id="scene0"><div id="glowscript" class="glowscript"></div></div>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>



    <IPython.core.display.Javascript object>


## Reference frames


```python
inertial_frame = ReferenceFrame('I')

pendulum_frames = [ReferenceFrame('P0'),
                   ReferenceFrame('P1')]

```

    (MainThread) backend module://ipykernel.pylab.backend_inline version unknown


    ERROR! Session/line number was not unique in database. History logging moved to new session 556



```python
psis = [dynamicsymbols('psi0'), #Pendulum1 angle
        dynamicsymbols('psi1')] #Pendulum2 angle

```


```python
pendulum_frames[0].orient(inertial_frame, 'Axis', (psis[0], inertial_frame.z))
pendulum_frames[1].orient(pendulum_frames[0], 'Axis', (psis[1], pendulum_frames[0].z))

```


```python
pendulum_frames[0].dcm(inertial_frame)
```




$$\left[\begin{matrix}\operatorname{cos}\left(\psi_{0}\right) & \operatorname{sin}\left(\psi_{0}\right) & 0\\- \operatorname{sin}\left(\psi_{0}\right) & \operatorname{cos}\left(\psi_{0}\right) & 0\\0 & 0 & 1\end{matrix}\right]$$




```python
simplify(pendulum_frames[1].dcm(inertial_frame))
```




$$\left[\begin{matrix}\operatorname{cos}\left(\psi_{0} + \psi_{1}\right) & \operatorname{sin}\left(\psi_{0} + \psi_{1}\right) & 0\\- \operatorname{sin}\left(\psi_{0} + \psi_{1}\right) & \operatorname{cos}\left(\psi_{0} + \psi_{1}\right) & 0\\0 & 0 & 1\end{matrix}\right]$$



## Define some points


```python
attachment = Point('A')

Lcgs = [symbols('Lcg0'),
       symbols('Lcg1')]

#end_points = [symbols('end0'),
#              symbols('end1')]

pendulum_lengths = [symbols('L0'),
                    symbols('L1')]
    

pendulum_mass_centers = [Point('cg0'),
                        Point('cg1')]

pendulum_end_points = [Point('end0'),
                       Point('end1')]

pendulum_end_points[0].set_pos(attachment, pendulum_lengths[0]*pendulum_frames[0].y)
pendulum_end_points[1].set_pos(pendulum_end_points[0], pendulum_lengths[1]*pendulum_frames[1].y)

pendulum_mass_centers[0].set_pos(attachment, Lcgs[0]*pendulum_frames[0].y)
pendulum_mass_centers[1].set_pos(pendulum_end_points[0], Lcgs[1]*pendulum_frames[1].y)

```

## Kinematical Differential Equations


```python
rs = [dynamicsymbols('r0'), # Pendulum0 rate
      dynamicsymbols('r1')] # Pendulum1 rate
pendulum_end_point_velocities = [dynamicsymbols('pev0'),
                                dynamicsymbols('pev1')]
```


```python
kinematical_differential_equations = [rs[0] - psis[0].diff(),
                                      rs[1] - psis[1].diff()
                                     ]
kinematical_differential_equations
```




$$\left [ r_{0} - \dot{\psi}_{0}, \quad r_{1} - \dot{\psi}_{1}\right ]$$



## Angular Velocities


```python
pendulum_frames[0].set_ang_vel(inertial_frame,rs[0]*inertial_frame.z)
pendulum_frames[1].set_ang_vel(pendulum_frames[0],rs[1]*inertial_frame.z)

```


```python
pendulum_frames[0].ang_vel_in(inertial_frame)
```




$$r_{0}\mathbf{\hat{i}_z}$$




```python
pendulum_frames[1].ang_vel_in(inertial_frame)
```




$$(r_{0} + r_{1})\mathbf{\hat{i}_z}$$



## Linear Velocities


```python
attachment.set_vel(inertial_frame, 0)

```


```python
pendulum_mass_centers[0].v2pt_theory(attachment, inertial_frame, pendulum_frames[0])
pendulum_mass_centers[0].vel(inertial_frame)
```




$$-  Lcg_{0} r_{0}\mathbf{\hat{p0}_x}$$




```python
pendulum_end_points[0].v2pt_theory(attachment, inertial_frame, pendulum_frames[0])
pendulum_end_points[0].vel(inertial_frame)
```




$$-  L_{0} r_{0}\mathbf{\hat{p0}_x}$$




```python
pendulum_mass_centers[1].v2pt_theory(pendulum_end_points[0], inertial_frame, pendulum_frames[1])
pendulum_mass_centers[1].vel(inertial_frame)
```




$$-  L_{0} r_{0}\mathbf{\hat{p0}_x} -  Lcg_{1} \left(r_{0} + r_{1}\right)\mathbf{\hat{p1}_x}$$



## Mass


```python
pendulum_masses = [symbols('m_P0'),symbols('m_P1')]
```

## Inertia


```python
Izzs = [symbols('I_zz0'),symbols('I_zz1')]
```


```python
pendulum_dyadics = [inertia(pendulum_frames[0], 0, 0, Izzs[0]),
                   inertia(pendulum_frames[1], 0, 0, Izzs[1])]
```


```python
pendulum_dyadics[0]
```




$$I_{zz0}\mathbf{\hat{p0}_z}\otimes \mathbf{\hat{p0}_z}$$




```python
pendulum_dyadics[0].to_matrix(pendulum_frames[0])
```




$$\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & I_{zz0}\end{matrix}\right]$$




```python
pendulum_central_inertias = [(pendulum_dyadics[0], pendulum_mass_centers[0]),
                             (pendulum_dyadics[1], pendulum_mass_centers[1])]
                             
```


```python
pendulums = [RigidBody('Pendulum0', pendulum_mass_centers[0], pendulum_frames[0],pendulum_masses[0], 
                       pendulum_central_inertias[0]),
             RigidBody('Pendulum1', pendulum_mass_centers[1], pendulum_frames[1],pendulum_masses[1], 
                       pendulum_central_inertias[1])]
```

## Equations of Motion


```python
coordinates = psis
coordinates
```




$$\left [ \psi_{0}, \quad \psi_{1}\right ]$$




```python
speeds = rs
speeds
```




$$\left [ r_{0}, \quad r_{1}\right ]$$




```python
kane = KanesMethod(inertial_frame, coordinates, speeds, kinematical_differential_equations)
```


```python
g = symbols('g')
```


```python
pendulum_grav_force_vectors = [pendulum_masses[0] * g * inertial_frame.y,
                               pendulum_masses[1] * g * inertial_frame.y]
pendulum_grav_force_vectors
```




$$\left [ g m_{P0}\mathbf{\hat{i}_y}, \quad g m_{P1}\mathbf{\hat{i}_y}\right ]$$




```python
pendulum_grav_forces = [(pendulum_mass_centers[0], pendulum_grav_force_vectors[0]),
                        (pendulum_mass_centers[1], pendulum_grav_force_vectors[1])]
```


```python
attachement_torques = [dynamicsymbols('T_a0'),
                       dynamicsymbols('T_a1')]

pendulum_torque_vectors = [attachement_torques[0] * inertial_frame.z,
                           attachement_torques[1] * inertial_frame.z]
                           
pendulum_torque_vectors
```




$$\left [ T_{a0}\mathbf{\hat{i}_z}, \quad T_{a1}\mathbf{\hat{i}_z}\right ]$$




```python
pendulum_torques = [(pendulum_frames[0], pendulum_torque_vectors[0]),
                    (pendulum_frames[1], pendulum_torque_vectors[1])]
```


```python
#loads = [pendulum_grav_force,
#        pendulum_torque]
loads = pendulum_grav_forces

loads
```




    [(cg0, g*m_P0*I.y), (cg1, g*m_P1*I.y)]




```python
bodies = pendulums
```


```python
fr, frstar = kane.kanes_equations(bodies = bodies,loads = loads)
```


```python
trigsimp(fr + frstar)
```




$$\left[\begin{matrix}L_{0} Lcg_{1} m_{P1} \left(r_{0} + r_{1}\right)^{2} \operatorname{sin}\left(\psi_{1}\right) - L_{0} Lcg_{1} m_{P1} r^{2}_{0} \operatorname{sin}\left(\psi_{1}\right) - L_{0} g m_{P1} \operatorname{sin}\left(\psi_{0}\right) - Lcg_{0} g m_{P0} \operatorname{sin}\left(\psi_{0}\right) - Lcg_{1} g m_{P1} \operatorname{sin}\left(\psi_{0} + \psi_{1}\right) - \left(I_{zz1} + Lcg_{1} m_{P1} \left(L_{0} \operatorname{cos}\left(\psi_{1}\right) + Lcg_{1}\right)\right) \dot{r}_{1} - \left(I_{zz0} + I_{zz1} + Lcg_{0}^{2} m_{P0} + m_{P1} \left(L_{0}^{2} + 2 L_{0} Lcg_{1} \operatorname{cos}\left(\psi_{1}\right) + Lcg_{1}^{2}\right)\right) \dot{r}_{0}\\- L_{0} Lcg_{1} m_{P1} r^{2}_{0} \operatorname{sin}\left(\psi_{1}\right) - Lcg_{1} g m_{P1} \operatorname{sin}\left(\psi_{0} + \psi_{1}\right) - \left(I_{zz1} + Lcg_{1}^{2} m_{P1}\right) \dot{r}_{1} - \left(I_{zz1} + Lcg_{1} m_{P1} \left(L_{0} \operatorname{cos}\left(\psi_{1}\right) + Lcg_{1}\right)\right) \dot{r}_{0}\end{matrix}\right]$$




```python
mass_matrix = trigsimp(kane.mass_matrix_full)
mass_matrix
```




$$\left[\begin{matrix}1 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & I_{zz0} + I_{zz1} + Lcg_{0}^{2} m_{P0} + m_{P1} \left(L_{0}^{2} + 2 L_{0} Lcg_{1} \operatorname{cos}\left(\psi_{1}\right) + Lcg_{1}^{2}\right) & I_{zz1} + Lcg_{1} m_{P1} \left(L_{0} \operatorname{cos}\left(\psi_{1}\right) + Lcg_{1}\right)\\0 & 0 & I_{zz1} + Lcg_{1} m_{P1} \left(L_{0} \operatorname{cos}\left(\psi_{1}\right) + Lcg_{1}\right) & I_{zz1} + Lcg_{1}^{2} m_{P1}\end{matrix}\right]$$




```python
forcing_vector = trigsimp(kane.forcing_full)
forcing_vector
```




$$\left[\begin{matrix}r_{0}\\r_{1}\\2 L_{0} Lcg_{1} m_{P1} r_{0} r_{1} \operatorname{sin}\left(\psi_{1}\right) + L_{0} Lcg_{1} m_{P1} r^{2}_{1} \operatorname{sin}\left(\psi_{1}\right) - L_{0} g m_{P1} \operatorname{sin}\left(\psi_{0}\right) - Lcg_{0} g m_{P0} \operatorname{sin}\left(\psi_{0}\right) - Lcg_{1} g m_{P1} \operatorname{sin}\left(\psi_{0} + \psi_{1}\right)\\- Lcg_{1} m_{P1} \left(L_{0} r^{2}_{0} \operatorname{sin}\left(\psi_{1}\right) + g \operatorname{sin}\left(\psi_{0} + \psi_{1}\right)\right)\end{matrix}\right]$$



## Simulation


```python
constants = [Lcgs[0],
             pendulum_lengths[0],
             pendulum_masses[0],            
             Izzs[0],
             Lcgs[1],
             pendulum_masses[1],            
             Izzs[1],
             g]
```


```python
constants
```




$$\left [ Lcg_{0}, \quad L_{0}, \quad m_{P0}, \quad I_{zz0}, \quad Lcg_{1}, \quad m_{P1}, \quad I_{zz1}, \quad g\right ]$$




```python
coordinates = psis
coordinates
```




$$\left [ \psi_{0}, \quad \psi_{1}\right ]$$




```python
speeds = rs
speeds
```




$$\left [ r_{0}, \quad r_{1}\right ]$$




```python
#specified = [pendulum_torque]
specified = []


right_hand_side = generate_ode_function(forcing_vector, coordinates,
                                        speeds, constants,
                                        mass_matrix=mass_matrix,
                                        specifieds=specified)
```


```python
help(generate_ode_function)
```

    Help on function generate_ode_function in module pydy.codegen.ode_function_generators:
    
    generate_ode_function(*args, **kwargs)
        Generates a numerical function which can evaluate the right hand
        side of the first order ordinary differential equations from a
        system described by one of the following three symbolic forms:
        
            [1] x' = F(x, t, r, p)
        
            [2] M(x, p) x' = F(x, t, r, p)
        
            [3] M(q, p) u' = F(q, u, t, r, p)
                q' = G(q, u, t, r, p)
        
        where
        
            x : states, i.e. [q, u]
            t : time
            r : specified (exogenous) inputs
            p : constants
            q : generalized coordinates
            u : generalized speeds
            M : mass matrix (full or minimum)
            F : right hand side (full or minimum)
            G : right hand side of the kinematical differential equations
        
        The generated function is of the form F(x, t, p) or F(x, t, r, p)
        depending on whether the system has specified inputs or not.
        
        Parameters
        ==========
        right_hand_side : SymPy Matrix, shape(n, 1)
            A column vector containing the symbolic expressions for the
            right hand side of the ordinary differential equations. If the
            right hand side has been solved for symbolically then only F is
            required, see form [1]; if not then the mass matrix must also be
            supplied, see forms [2, 3].
        coordinates : sequence of SymPy Functions
            The generalized coordinates. These must be ordered in the same
            order as the rows in M, F, and/or G and be functions of time.
        speeds : sequence of SymPy Functions
            The generalized speeds. These must be ordered in the same order
            as the rows in M, F, and/or G and be functions of time.
        constants : sequence of SymPy Symbols
            All of the constants present in the equations of motion. The
            order does not matter.
        mass_matrix : sympy.Matrix, shape(n, n), optional
            This can be either the "full" mass matrix as in [2] or the
            "minimal" mass matrix as in [3]. The rows and columns must be
            ordered to match the order of the coordinates and speeds. In the
            case of the full mass matrix, the speeds should always be
            ordered before the speeds, i.e. x = [q, u].
        coordinate_derivatives : sympy.Matrix, shape(m, 1), optional
            If the "minimal" mass matrix, form [3], is supplied, then this
            column vector represents the right hand side of the kinematical
            differential equations.
        specifieds : sequence of SymPy Functions
            The specified exogenous inputs to the system. These should be
            functions of time and the order does not matter.
        linear_sys_solver : string or function
            Specify either `numpy` or `scipy` to use the linear solvers
            provided in each package or supply a function that solves a
            linear system Ax=b with the call signature x = solve(A, b). For
            example, if you need to use custom kwargs for the SciPy solver,
            pass in a lambda function that wraps the solver and sets them.
        constants_arg_type : string
            The generated function accepts two different types of arguments
            for the numerical values of the constants: either a ndarray of
            the constants values in the correct order or a dictionary
            mapping the constants symbols to the numerical values. If None,
            this is determined inside of the generated function and can
            cause a significant slow down for performance critical code. If
            you know apriori what arg types you need to support choose
            either ``array`` or ``dictionary``. Note that ``array`` is
            faster than ``dictionary``.
        specifieds_arg_type : string
            The generated function accepts three different types of
            arguments for the numerical values of the specifieds: either a
            ndarray of the specifieds values in the correct order, a
            function that generates the correctly ordered ndarray, or a
            dictionary mapping the specifieds symbols or tuples of thereof
            to floats, ndarrays, or functions. If None, this is determined
            inside of the generated function and can cause a significant
            slow down for performance critical code. If you know apriori
            what arg types you want to support choose either ``array``,
            ``function``, or ``dictionary``. The speed of each, from fast to
            slow, are ``array``, ``function``, ``dictionary``, None.
        
                generator : string or and ODEFunctionGenerator, optional
            The method used for generating the numeric right hand side. The
            string options are {'lambdify'|'theano'|'cython'} with
            'lambdify' being the default. You can also pass in a custom
            subclass of ODEFunctionGenerator.
        
        Returns
        =======
        rhs : function
            A function which evaluates the derivaties of the states. See the
            function's docstring for more details after generation.
    



```python
help(right_hand_side)
```

    Help on function rhs in module pydy.codegen.ode_function_generators:
    
    rhs(*args)
        Returns the derivatives of the states, i.e. numerically evaluates the right
        hand side of the first order differential equation.
        
        x' = f(x, t, r, p)
        
        Parameters
        ==========
        x : ndarray, shape(4,)
            The state vector is ordered as such:
                - psi0(t)
                - psi1(t)
                - r0(t)
                - r1(t)
        t : float
            The current time.
        r : dictionary; ndarray, shape(0,); function
        
            There are three options for this argument. (1) is more flexible but
            (2) and (3) are much more efficient.
        
            (1) A dictionary that maps the specified functions of time to floats,
            ndarrays, or functions that produce ndarrays. The keys can be a single
            specified symbolic function of time or a tuple of symbols. The total
            number of symbols must be equal to 0. If the value is a
            function it must be of the form g(x, t), where x is the current state
            vector ndarray and t is the current time float and it must return an
            ndarray of the correct shape. For example::
        
              r = {a: 1.0,
                   (d, b) : np.array([1.0, 2.0]),
                   (e, f) : lambda x, t: np.array(x[0], x[1]),
                   c: lambda x, t: np.array(x[2])}
        
            (2) A ndarray with the specified values in the correct order and of the
            correct shape.
        
            (3) A function that must be of the form g(x, t), where x is the current
            state vector and t is the current time and it must return an ndarray of
            the correct shape.
        
            The specified inputs are, in order:
                - 
        p : dictionary len(8) or ndarray shape(8,)
            Either a dictionary that maps the constants symbols to their numerical
            values or an array with the constants in the following order:
                - Lcg0
                - L0
                - m_P0
                - I_zz0
                - Lcg1
                - m_P1
                - I_zz1
                - g
        
        Returns
        =======
        dx : ndarray, shape(4,)
            The derivative of the state vector.
    


## Set the Initial Conditions, Parameter Values, and Time Array


```python
x0 = array([deg2rad(45),deg2rad(-45),0,0])
x0
```




    array([ 0.78539816, -0.78539816,  0.        ,  0.        ])




```python
Ls = [20,20]
numerical_constants =  np.array([Ls[0]/2,  # pendulum_length [m]
                                 Ls[0],
                         10,  # pendulum_mass [kg]
                        100,  # pendulum_inertia [kg*m^2]
                        Ls[1]/2,  # pendulum_length [m]
                        10,  # pendulum_mass [kg]
                        100,  # pendulum_inertia [kg*m^2]    
                        9.81])  # acceleration due to gravity [m/s^2]

```


```python
# %load exercise_solutions/n07_simulation_sim-setup.py
#numerical_specified = zeros(3)
#numerical_specified = {}
numerical_specified = {}
#numerical_specified['L0'] = 10
#numerical_specified['L'] = 10



args = {'constants': numerical_constants,
        'specified': numerical_specified}

frames_per_sec = 100
final_time = 15.0

t = linspace(0.0, final_time, final_time * frames_per_sec)
```

    /Users/martinalexandersson/Dev/ForceMan/venv/lib/python3.6/site-packages/ipykernel_launcher.py:16: DeprecationWarning: object of type <class 'float'> cannot be safely interpreted as an integer.
      app.launch_new_instance()



```python
right_hand_side(x0, 0.0, numerical_specified, numerical_constants)
```




    array([ 0.        ,  0.        , -0.63410437,  1.44933983])




```python
import inspect
inspect.getsourcelines(right_hand_side)
```




    (['            def rhs(*args):\n',
      '                # args: x, t, p\n',
      '                # or\n',
      '                # args: x, t, r, p\n',
      '\n',
      '                args = self._parse_all_args(*args)\n',
      '\n',
      '                q = args[0][:self.num_coordinates]\n',
      '                u = args[0][self.num_coordinates:]\n',
      '\n',
      '                xdot = self._base_rhs(q, u, *args[2:])\n',
      '\n',
      '                return xdot\n'],
     467)



## Integrate the Equations of Motion


```python
y = odeint(right_hand_side, x0, t, args=(numerical_specified, numerical_constants))
```


```python
fig,ax = plt.subplots()
fig.set_size_inches(15,5)

ax.plot(t,y[:,0])

```


```python

```


```python
fig,ax = plt.subplots()
fig.set_size_inches(15,5)

ax.plot(t,y[:,1])
```

## Visualization


```python
simplify(pendulum_end_points[0].pos_from(attachment).to_matrix(inertial_frame))
```




$$\left[\begin{matrix}- L_{0} \operatorname{sin}\left(\psi_{0}\right)\\L_{0} \operatorname{cos}\left(\psi_{0}\right)\\0\end{matrix}\right]$$




```python
simplify(pendulum_end_points[1].pos_from(attachment).to_matrix(inertial_frame))
```




$$\left[\begin{matrix}- L_{0} \operatorname{sin}\left(\psi_{0}\right) - L_{1} \operatorname{sin}\left(\psi_{0} + \psi_{1}\right)\\L_{0} \operatorname{cos}\left(\psi_{0}\right) + L_{1} \operatorname{cos}\left(\psi_{0} + \psi_{1}\right)\\0\end{matrix}\right]$$




```python
positions = [pendulum_end_points[0].pos_from(attachment),
             pendulum_end_points[1].pos_from(attachment)]

global_position_matrixes = []
for position in positions:
    global_position_matrixes.append(position.to_matrix(inertial_frame))
```


```python

def play(x):
    
    index = int((len(t)-1)*x/100)
    
    
    
    #for global_position_matrix,pendulum_cylinder,psi_now,L,pendulum_length,psi in zip(
    #    global_position_matrixes,pendulum_cylinders,psi_nows,Ls,pendulum_lengths,psis):
    #    
    #    a = global_position_matrix.evalf(subs = {pendulum_length:L,psi:psi_now})
    #    pendulum_cylinder.axis = np.array(a.transpose().tolist()).astype(np.float64)[0]

    psi_nows = y[index,0:len(global_position_matrixes)] 
    
    a = global_position_matrixes[0].evalf(subs = {pendulum_lengths[0]:Ls[0],psis[0]:psi_nows[0]})
    end_point = np.array(a.transpose().tolist()).astype(np.float64)[0]
    pendulum_cylinders[0].axis = end_point
      
    a = global_position_matrixes[1].evalf(subs = {pendulum_lengths[0]:Ls[0],
                                                  pendulum_lengths[1]:Ls[1],
                                                  psis[0]:psi_nows[0],
                                                  psis[1]:psi_nows[1]})
    
    pendulum_cylinders[1].axis = np.array(a.transpose().tolist()).astype(np.float64)[0] - pendulum_cylinders[0].axis
    pendulum_cylinders[1].pos = pendulum_cylinders[0].axis

def play2(change):

    #x = interactive_plot.children[0].value
    x = slider.value

    play(x = x)

def plot(x):
    
    index = int((len(t)-1)*x/100)
    fig,ax = plt.subplots()
    ax.plot(t,y[:,0])
    ax.plot(t[index],y[index,0],'ro')
    display(fig)
    clear_output(wait=True)
    
    
```


```python

#from ipywidgets import interactive
#
#
#interactive_plot = interactive(plot, x=(0.0,100.0))
#display(interactive_plot)
#
```


```python
scene2 = canvas(width = 1000,height = 500,up=vector(0,-1,0))
vscale = 3
varr = arrow(pos=vector(0,0,0), axis=vscale*vector(1,0,0), color=color.red,shaftwidth=vscale*0.1)
varr = arrow(pos=vector(0,0,0), axis=vscale*vector(0,1,0), color=color.green,shaftwidth=vscale*0.1)
varr = arrow(pos=vector(0,0,0), axis=vscale*vector(0,0,1), color=color.blue,shaftwidth=vscale*0.1)

pendulum_radius = 0.1

pendulum_cylinders = []
colors = [color.orange,color.magenta]
for L,the_color in zip(Ls,colors):
    pendulum_cylinders.append(cylinder(pos = (0,0,0),axis = (0,1,0),length = L,radius = pendulum_radius,color = the_color))
    
play_widget = widgets.Play(
    #interval=0.05,
    step = 1,
    value=0,
    min=0,
    max=100,
    description="Press play",
    disabled=False

)
slider = widgets.FloatSlider()
widgets.jslink((play_widget, 'value'), (slider, 'value'))
#widgets.jslink((play_widget, 'value'), (interactive_plot.children[0], 'value'))


play_widget.observe(play2, names='value')

scene2.visible = True
display(scene2)
#display(interactive_plot.children[1])

widgets.HBox([play_widget, slider])
#widgets.HBox([play_widget, interactive_plot.children[0]])

```


<div id="scene0"><div id="glowscript" class="glowscript"></div></div>



    <IPython.core.display.Javascript object>



```python
y
```


```python

```

267d2460761e20f580059d482226612ceda68f4f
ipynb
Jupyter Notebook
notebooks/01_dynamics_experiments/double_pendulum.ipynb
martinlarsalbert/ForceMan
b07541f1c04d0ed103d7a5f66256812ebca2824c
MIT
notebooks/01_dynamics_experiments/double_pendulum.ipynb
martinlarsalbert/ForceMan
b07541f1c04d0ed103d7a5f66256812ebca2824c
MIT
2019-12-15T17:23:21.000Z
2019-12-15T17:23:21.000Z
notebooks/01_dynamics_experiments/double_pendulum.ipynb
martinlarsalbert/ForceMan
b07541f1c04d0ed103d7a5f66256812ebca2824c
MIT
Qwen/Qwen-72B
1. YES
2. YES