6. Symbolics using SymPy

This example is also available as a Jupyter notebook that can be run locally The notebook can be found in the examples directory of the package. If the notebooks are missing, you may need to run using Pkg; Pkg.build().


using RigidBodyDynamics
using StaticArrays
using SymPy
 Activating environment at `~/work/RigidBodyDynamics.jl/RigidBodyDynamics.jl/examples/6. Symbolics using SymPy/Project.toml`
[ Info: Installing sympy via the Conda sympy package...
[ Info: Running `conda install -q -y sympy` in root environment
Collecting package metadata (current_repodata.json): ...working... done
Solving environment: ...working... done

## Package Plan ##

  environment location: /home/runner/.julia/conda/3

  added / updated specs:
    - sympy

The following packages will be downloaded:

    package                    |            build
    gmp-6.2.1                  |       h2531618_2         539 KB
    gmpy2-2.0.8                |   py38hd5f6e3b_3         162 KB
    mpc-1.1.0                  |       h10f8cd9_1          90 KB
    mpfr-4.0.2                 |       hb69a4c5_1         487 KB
    mpmath-1.2.1               |   py38h06a4308_0         766 KB
    sympy-1.8                  |   py38h06a4308_0         9.1 MB
                                           Total:        11.1 MB

The following NEW packages will be INSTALLED:

  gmp                pkgs/main/linux-64::gmp-6.2.1-h2531618_2
  gmpy2              pkgs/main/linux-64::gmpy2-2.0.8-py38hd5f6e3b_3
  mpc                pkgs/main/linux-64::mpc-1.1.0-h10f8cd9_1
  mpfr               pkgs/main/linux-64::mpfr-4.0.2-hb69a4c5_1
  mpmath             pkgs/main/linux-64::mpmath-1.2.1-py38h06a4308_0
  sympy              pkgs/main/linux-64::sympy-1.8-py38h06a4308_0

Preparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done

Create symbolic parameters

  • Masses: $m_1, m_2$
  • Mass moments of inertia (about center of mass): $I_1, I_2$
  • Link lengths: $l_1, l_2$
  • Center of mass locations (w.r.t. preceding joint axis): $c_1, c_2$
  • Gravitational acceleration: $g$
inertias = @syms m_1 m_2 I_1 I_2 positive = true
lengths = @syms l_1 l_2 c_1 c_2 real = true
gravitational_acceleration = @syms g real = true
params = [inertias..., lengths..., gravitational_acceleration...]

\[\left[ \begin{array}{rrrrrrrrr}m_{1}&m_{2}&I_{1}&I_{2}&l_{1}&l_{2}&c_{1}&c_{2}&g\end{array}\right]\]

Create double pendulum Mechanism

A Mechanism contains the joint layout and inertia parameters, but no state information.

T = Sym # the 'scalar type' of the Mechanism we'll construct
axis = SVector(zero(T), one(T), zero(T)) # axis of rotation for each of the joints
double_pendulum = Mechanism(RigidBody{T}("world"); gravity = SVector(zero(T), zero(T), g))
world = root_body(double_pendulum) # the fixed 'world' rigid body
RigidBody: "world"

Attach the first (upper) link to the world via a revolute joint named 'shoulder'

inertia1 = SpatialInertia(CartesianFrame3D("upper_link"),
    moment=I_1 * axis * transpose(axis),
    com=SVector(zero(T), zero(T), c_1),
body1 = RigidBody(inertia1)
joint1 = Joint("shoulder", Revolute(axis))
joint1_to_world = one(Transform3D{T}, frame_before(joint1), default_frame(world));
attach!(double_pendulum, world, body1, joint1,
    joint_pose = joint1_to_world);

Attach the second (lower) link to the world via a revolute joint named 'elbow'

inertia2 = SpatialInertia(CartesianFrame3D("lower_link"),
    moment=I_2 * axis * transpose(axis),
    com=SVector(zero(T), zero(T), c_2),
body2 = RigidBody(inertia2)
joint2 = Joint("elbow", Revolute(axis))
joint2_to_body1 = Transform3D(
    frame_before(joint2), default_frame(body1), SVector(zero(T), zero(T), l_1))
attach!(double_pendulum, body1, body2, joint2,
    joint_pose = joint2_to_body1)
Spanning tree:
Vertex: world (root)
  Vertex: upper_link, Edge: shoulder
    Vertex: lower_link, Edge: elbow
No non-tree joints.

Create MechanismState associated with the double pendulum Mechanism

A MechanismState stores all state-dependent information associated with a Mechanism.

x = MechanismState(double_pendulum);

Set the joint configuration vector of the MechanismState to a new vector of symbolic variables

q = configuration(x)
for i in eachindex(q)
    q[i] = symbols("q_$i", real = true)

Set the joint velocity vector of the MechanismState to a new vector of symbolic variables

v = velocity(x)
for i in eachindex(v)
    v[i] = symbols("v_$i", real = true)

Compute dynamical quantities in symbolic form

Mass matrix


\[\left[ \begin{array}{rr}I_{1} + I_{2} + 2 c_{2} l_{1} m_{2} \cos{\left(q_{2} \right)} + l_{1}^{2} m_{2}&I_{2} + c_{2} l_{1} m_{2} \cos{\left(q_{2} \right)}\\I_{2} + c_{2} l_{1} m_{2} \cos{\left(q_{2} \right)}&I_{2}\end{array}\right]\]

Kinetic energy


\[\begin{equation*}\frac{I_{1} v_{1}^{2}}{2} + \frac{I_{2} v_{1}^{2}}{2} + I_{2} v_{1} v_{2} + \frac{I_{2} v_{2}^{2}}{2} + c_{2} l_{1} m_{2} v_{1}^{2} \cos{\left(q_{2} \right)} + c_{2} l_{1} m_{2} v_{1} v_{2} \cos{\left(q_{2} \right)} + \frac{l_{1}^{2} m_{2} v_{1}^{2}}{2}\end{equation*}\]

Potential energy


\[\begin{equation*}- g \left(c_{1} m_{1} \cos{\left(q_{1} \right)} + c_{2} m_{2} \cos{\left(q_{1} + q_{2} \right)} + l_{1} m_{2} \cos{\left(q_{1} \right)}\right)\end{equation*}\]

This page was generated using Literate.jl.