Skip to content
LIBRARY

Orientations and coordinate conventions

MultibodyComponents models mechanical systems as networks of frames (coordinate systems) attached to bodies and connected through joints. Understanding how frames relate to each other is essential for correctly setting up models, interpreting results and specifying initial conditions.

Planar mechanics (2D)

In 2D planar mechanics, all motion is confined to the xy-plane. Orientation is described by a single scalar angle ϕ, measuring rotation about the z-axis (out of plane).

The Frame2D connector

Every planar component communicates through Frame2D connectors. A Frame2D carries six variables, all resolved in the world frame:

VariableKindDescription
x, yPotentialPosition of the frame origin
phiPotentialOrientation angle (rad)
fx, fyFlowCut-force components
tauFlowCut-torque about the z-axis

The World component

Every planar model must contain exactly one World component. It defines:

  • The origin of the inertial reference frame at (0,0) with ϕ=0.

  • Gravity, specified by a direction vector n (default [0, -1], i.e. pointing downward) and a magnitude g (default 9.80665 m/s²). All Body components automatically use the resulting gravitational acceleration gn.

The 2D rotation matrix

The standard 2D rotation matrix for an angle ϕ is

R(ϕ)=[cosϕsinϕsinϕcosϕ]

Two functions are available for working with this matrix:

  • ori_2d(phi) returns RFW=R(ϕ), which transforms a vector from the world frame to the local frame: pF=RFWpW.

  • get_rot(sol, frame, t) returns RWF=R(ϕ), which transforms a vector from the local frame to the world frame: pW=RWFpF.

How joints affect orientation

Orientations are additive through joints. When two frames are connected by a joint, the relation between their orientation angles is

ϕb=ϕa+ϕjoint

This applies to:

  • Revolute: ϕb=ϕa+ϕ, where ϕ is the (variable) joint coordinate. Positions are rigidly connected: xa=xb, ya=yb.

  • FixedRotation: ϕb=ϕa+α, where α is a fixed parameter. Also rigidly connects positions.

When a joint is at its zero coordinate (ϕ=0 or α=0), frame_a and frame_b coincide in both position and orientation.

Vectors in local vs. world frames

Some components specify vectors in the body-fixed (local) frame. For example, FixedTranslation(r = [1, 0]) specifies a displacement of 1 unit along the local x-axis. To find where frame_b ends up in the world frame, this vector is rotated by the current orientation of frame_a:

rworld=RWFrlocal=R(ϕa)r

The Body component's position and velocity state variables (r, v, phi, w) are all expressed directly in the world frame, so no transformation is needed when reading them from a solution.

Example: a simple pendulum

The PendulumTest example connects a World, a Revolute joint, a FixedTranslation rod and a Body:

World.frame_b ─→ Revolute.frame_a
                  Revolute.frame_b ─→ FixedTranslation.frame_a
                                       FixedTranslation.frame_b ─→ Body.frame_a

We can instantiate, simplify and simulate this model in Julia:

@example
using ModelingToolkit, OrdinaryDiffEq
using MultibodyComponents
using MultibodyComponents: multibody

@named model = MultibodyComponents.PlanarMechanics.examples.PendulumTest()
ssys = multibody(model)
prob = ODEProblem(ssys, [], (0.0, 3.0))
sol = solve(prob, Tsit5())

import GLMakie
render(model, sol; filename = "pendulum.gif") # Use "pendulum.mp4" for a video file

The revolute joint angle tells us the pendulum's orientation relative to the world. At t=0 the joint coordinate revolute.phi is zero, so the rod extends horizontally (along the world x-axis, matching r = [1, 0]). As the pendulum swings under gravity, the joint angle evolves:

julia
sol(1.0, idxs = ssys.revolute.phi)
-2.881411948155995

The body's world-frame position is available directly:

julia
sol(1.0, idxs = ssys.body.r)
2-element Vector{Float64}:
 -0.9663435065036469
 -0.25725517961400923

We can also extract a rotation matrix from any frame using get_rot:

julia
R = get_rot(sol, ssys.rod.frame_b, 1.0)
2×2 RotMatrix2{Float64} with indices SOneTo(2)×SOneTo(2):
 -0.966344  -0.257255
  0.257255  -0.966344

This R is RWF, so multiplying a vector expressed in the rod's local frame by R yields the same vector in world coordinates.