Lagrange’s Method in Physics/Mechanics

sympy.physics.mechanics provides functionality for deriving equations of motion using Lagrange’s method. This document will describe Lagrange’s method as used in this module, but not how the equations are actually derived.

Structure of Equations

In sympy.physics.mechanics we are assuming there are 3 basic sets of equations needed to describe a system; the constraint equations, the time differentiated constraint equations and the dynamic equations.

\[\begin{split}\mathbf{m_{c}}(q, t) \dot{q} + \mathbf{f_{c}}(q, t) &= 0\\ \mathbf{m_{dc}}(\dot{q}, q, t) \ddot{q} + \mathbf{f_{dc}}(\dot{q}, q, t) &= 0\\ \mathbf{m_d}(\dot{q}, q, t) \ddot{q} + \mathbf{\Lambda_c}(q, t) \lambda + \mathbf{f_d}(\dot{q}, q, t) &= 0\\\end{split}\]

In this module, the expressions formed by using Lagrange’s equations of the second kind are rearranged into the following form:

\(\mathbf{M}(q, t) x = \mathbf{f}(q, \dot{q}, t)\)

where in the case of a system without constraints:

\(x = \ddot{q}\)

For a constrained system with \(n\) generalized speeds and \(m\) constraints, we will get n - m equations. The mass-matrix/forcing equations are then augmented in the following fashion:

\[\begin{split}x = \begin{bmatrix} \ddot{q} \\ \lambda \end{bmatrix} \\ \mathbf{M}(q, t) &= \begin{bmatrix} \mathbf{m_d}(q, t) & \mathbf{\Lambda_c}(q, t) \end{bmatrix}\\ \mathbf{F}(\dot{q}, q, t) &= \begin{bmatrix} \mathbf{f_d}(q, \dot{q}, t) \end{bmatrix}\\\end{split}\]

Lagrange’s Method in Physics/Mechanics

The formulation of the equations of motion in sympy.physics.mechanics using Lagrange’s Method starts with the creation of generalized coordinates and a Lagrangian. The Lagrangian can either be created with the Lagrangian function or can be a user supplied function. In this case we will supply the Lagrangian.

>>> from sympy.physics.mechanics import *
>>> q1, q2 = dynamicsymbols('q1 q2')
>>> q1d, q2d = dynamicsymbols('q1 q2', 1)
>>> L = q1d**2 + q2d**2

To formulate the equations of motion we create a LagrangesMethod object. The Lagrangian and generalized coordinates need to be supplied upon initialization.

>>> LM = LagrangesMethod(L, [q1, q2])

With that the equations of motion can be formed.

>>> mechanics_printing(pretty_print=False)
>>> LM.form_lagranges_equations()
Matrix([
[2*q1''],
[2*q2'']])

It is possible to obtain the mass matrix and the forcing vector.

>>> LM.mass_matrix
Matrix([
[2, 0],
[0, 2]])

>>> LM.forcing
Matrix([
[0],
[0]])

If there are any holonomic or non-holonomic constraints, they must be supplied as keyword arguments (hol_coneqs and nonhol_coneqs respectively) in a list of expressions which are equal to zero. Modifying the example above, the equations of motion can then be generated:

>>> LM = LagrangesMethod(L, [q1, q2], hol_coneqs=[q1 - q2])

When the equations of motion are generated in this case, the Lagrange multipliers are introduced; they are represented by lam1 in this case. In general, there will be as many multipliers as there are constraint equations.

>>> LM.form_lagranges_equations()
Matrix([
[ lam1 + 2*q1''],
[-lam1 + 2*q2'']])

Also in the case of systems with constraints, the ‘full’ mass matrix is augmented by the \(k_{dc}(q, t)\) matrix, and the forcing vector by the \(f_{dc}(q, \dot{q}, t)\) vector. The ‘full’ mass matrix is of size (2n + o) x (2n + o), i.e. it’s a square matrix.

>>> LM.mass_matrix_full
Matrix([
[1, 0, 0,  0,  0],
[0, 1, 0,  0,  0],
[0, 0, 2,  0, -1],
[0, 0, 0,  2,  1],
[0, 0, 1, -1,  0]])
>>> LM.forcing_full
Matrix([
[q1'],
[q2'],
[  0],
[  0],
[  0]])

If there are any non-conservative forces or moments acting on the system, they must also be supplied as keyword arguments in a list of 2-tuples of the form (Point, Vector) or (ReferenceFrame, Vector) where the Vector represents the non-conservative forces and torques. Along with this 2-tuple, the inertial frame must also be specified as a keyword argument. This is shown below by modifying the example above:

>>> N = ReferenceFrame('N')
>>> P = Point('P')
>>> P.set_vel(N, q1d * N.x)
>>> FL = [(P, 7 * N.x)]
>>> LM = LagrangesMethod(L, [q1, q2], forcelist=FL, frame=N)
>>> LM.form_lagranges_equations()
Matrix([
[2*q1'' - 7],
[    2*q2'']])

Exploration of the provided examples is encouraged in order to gain more understanding of the LagrangesMethod object.