Skip to content
LIBRARY
Bushing.md

Bushing

Compliant mount (bushing): roots one frame from the other through its own relative-motion state variables and applies a linear spring-damper, transmitting no kinematic constraint so it decouples the two connected sides into separate algebraic blocks (e.g. to break the single coupled inline-linear SCC of a free-floating multi-wheel car into per-corner blocks).

Linear and angular compliance are independently optional. A compliant direction contributes relative-motion state variables and a spring-damper reaction; a rigid direction instead locks the relative motion and transmits the reaction as an unknown. Disabling angular compliance (angular_compliance = false) lowers the added state dimension by 6 (linear-only) and transmits orientation rigidly.

rooted selects which frame is the propagation root (as on Revolute): the kinematics and reaction terms are written in the direction the recursive Newton-Euler ordering needs, keeping the emitted inline linear systems no larger than required. The relative rotation is carried by a rotation matrix (the Revolute form) rather than an Euler orientation object, so it does not chain through the orientation-graph cycle of SciML/ModelingToolkit.jl#4608.

This component extends from PartialTwoFrames This component extends from CutJoint

Usage

MultibodyComponents.Bushing(c_t=1000000, d_t=10000, c_r=100000, d_r=1000)

Parameters:

NameDescriptionUnitsDefault value
iscutfalse
residualzeros(3)
rootedPropagation root for the relative kinematics / reactions (RNE equation direction).MultibodyCo...me.FrameA()
linear_complianceTranslational (linear) compliance: relative translation is a spring-damped state.true
angular_complianceRotational (angular) compliance: relative rotation is a spring-damped state. When false, orientation is transmitted rigidly (no relative-rotation state variables).true
sequenceEuler-angle sequence for the relative orientation.[1, 2, 3]
c_tTranslational stiffness [N/m]1000000
d_tTranslational damping [N*s/m]10000
c_rRotational stiffness [N*m/rad]100000
d_rRotational damping [N_m_s/rad]1000

Connectors

  • frame_a - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

  • frame_b - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

Variables

NameDescriptionUnits
Rleaf
Rroot
r_relRelative position frame_a -> frame_b, resolved in frame_a (spring-damped state if linear_compliance, else locked to 0)m
phiRelative Cardan angles frame_a -> frame_b (spring-damped state if angular_compliance, else 0)rad
wRelative angular velocity = der(phi)rad/s
f_aForce on frame_b from the mount, resolved in frame_a (spring-damper if linear_compliance, else the rigid reaction)
t_aTorque on frame_b from the mount, resolved in frame_a (spring-damper if angular_compliance, else the rigid reaction)
R_relRelative rotation matrix frame_a -> frame_b (carries the relative angular velocity)

Behavior

Dict{MIME{Symbol("text/plain")}, String} with 1 entry: MIME type text/plain => "Error displaying result"

Source

dyad
"""
Compliant mount (bushing): roots one frame from the other through its own
relative-motion state variables and applies a linear spring-damper, transmitting
no kinematic constraint so it decouples the two connected sides into separate
algebraic blocks (e.g. to break the single coupled inline-linear SCC of a
free-floating multi-wheel car into per-corner blocks).

Linear and angular compliance are independently optional. A compliant direction
contributes relative-motion state variables and a spring-damper reaction; a rigid
direction instead locks the relative motion and transmits the reaction as an
unknown. Disabling angular compliance (`angular_compliance = false`) lowers the
added state dimension by 6 (linear-only) and transmits orientation rigidly.

`rooted` selects which frame is the propagation root (as on `Revolute`): the
kinematics and reaction terms are written in the direction the recursive
Newton-Euler ordering needs, keeping the emitted inline linear systems no larger
than required. The relative rotation is carried by a rotation matrix (the
`Revolute` form) rather than an Euler orientation object, so it does not chain
through the orientation-graph cycle of SciML/ModelingToolkit.jl#4608.
"""
component Bushing
  extends PartialTwoFrames()
  extends CutJoint()
  "Propagation root for the relative kinematics / reactions (RNE equation direction)."
  structural parameter rooted::RootedFrame = MultibodyComponents.RootedFrame.FrameA()
  "Translational (linear) compliance: relative translation is a spring-damped state."
  structural parameter linear_compliance::Boolean = true
  """
  Rotational (angular) compliance: relative rotation is a spring-damped state. When
    false, orientation is transmitted rigidly (no relative-rotation state variables).
  """
  structural parameter angular_compliance::Boolean = true
  "Euler-angle sequence for the relative orientation."
  structural parameter sequence::Integer[3] = [1, 2, 3]
  "Translational stiffness [N/m]"
  parameter c_t::Real = 1000000
  "Translational damping [N*s/m]"
  parameter d_t::Real = 10000
  "Rotational stiffness [N*m/rad]"
  parameter c_r::Real = 100000
  "Rotational damping [N*m*s/rad]"
  parameter d_r::Real = 1000
  "Relative position frame_a -> frame_b, resolved in frame_a (spring-damped state if linear_compliance, else locked to 0)"
  variable r_rel::Position(statePriority = 50)[3]
  "Relative Cardan angles frame_a -> frame_b (spring-damped state if angular_compliance, else 0)"
  variable phi::Angle(statePriority = 50)[3]
  "Relative angular velocity = der(phi)"
  variable w::AngularVelocity[3]
  "Force on frame_b from the mount, resolved in frame_a (spring-damper if linear_compliance, else the rigid reaction)"
  variable f_a::Real[3]
  "Torque on frame_b from the mount, resolved in frame_a (spring-damper if angular_compliance, else the rigid reaction)"
  variable t_a::Real[3]
  "Relative rotation matrix frame_a -> frame_b (carries the relative angular velocity)"
  variable R_rel::Real[3, 3]
relations
  # Relative rotation matrix. With angular_compliance=false, phi/w are pinned to 0
  # so R_rel is the identity and orientation is transmitted rigidly.
  R_rel = RR(axes_rotations(sequence, phi, w))
  # Translational wrench. Compliant: f_a is an explicit spring-damper source applied to
  # both frames (action-reaction), so it is direction-agnostic. Rigid: relative translation
  # is locked and f_a is a reaction unknown, so the transmission is written in the rooted
  # (RNE) direction - the root frame's force is computed from the leaf frame's (cf. Revolute).
  if linear_compliance
    guess r_rel = [0, 0, 0]
    f_a = c_t * r_rel + d_t * der(r_rel)
    frame_a.f = f_a
    frame_b.f = -resolve_relative(f_a, frame_a.R, frame_b.R)
  else
    r_rel = [0, 0, 0]
    f_a = frame_a.f
    switch rooted
      case FrameA
        frame_a.f = -resolve_relative(frame_b.f, frame_b.R, frame_a.R)
      case FrameB
        frame_b.f = -resolve_relative(frame_a.f, frame_a.R, frame_b.R)
    end
  end
  # Rotational wrench (moment arm cross(r_rel, f_a) taken about frame_a). Compliant: t_a is
  # an explicit spring-damper source (direction-agnostic). Rigid: relative rotation is locked
  # and t_a is a reaction unknown, transmitted in the rooted (RNE) direction.
  if angular_compliance
    guess phi = [0, 0, 0]
    w = der(phi)
    t_a = c_r * phi + d_r * w
    frame_a.tau = t_a + cross(r_rel, f_a)
    frame_b.tau = -resolve_relative(t_a, frame_a.R, frame_b.R)
  else
    phi = [0, 0, 0]
    w = [0, 0, 0]
    switch rooted
      case FrameA
        frame_a.tau = -resolve_relative(frame_b.tau, frame_b.R, frame_a.R) + cross(r_rel, f_a)
      case FrameB
        frame_b.tau = resolve_relative(cross(r_rel, f_a) - frame_a.tau, frame_a.R, frame_b.R)
    end
    t_a = frame_a.tau - cross(r_rel, f_a)
  end
  # Orientation + position written in the rooted (RNE) propagation direction.
  switch rooted
    case FrameA
      Rleaf = frame_b.R
      Rroot = R_rel * frame_a.R
      frame_b.r_0 = frame_a.r_0 + resolve1(frame_a.R, r_rel)
    case FrameB
      Rleaf = frame_a.R
      Rroot = transpose(R_rel) * frame_b.R
      frame_a.r_0 = frame_b.r_0 - resolve1(frame_a.R, r_rel)
  end
metadata {"Dyad": {"icons": {"default": "dyad://MultibodyComponents/Bushing.svg"}}}
end
Flattened Source
dyad
"""
Compliant mount (bushing): roots one frame from the other through its own
relative-motion state variables and applies a linear spring-damper, transmitting
no kinematic constraint so it decouples the two connected sides into separate
algebraic blocks (e.g. to break the single coupled inline-linear SCC of a
free-floating multi-wheel car into per-corner blocks).

Linear and angular compliance are independently optional. A compliant direction
contributes relative-motion state variables and a spring-damper reaction; a rigid
direction instead locks the relative motion and transmits the reaction as an
unknown. Disabling angular compliance (`angular_compliance = false`) lowers the
added state dimension by 6 (linear-only) and transmits orientation rigidly.

`rooted` selects which frame is the propagation root (as on `Revolute`): the
kinematics and reaction terms are written in the direction the recursive
Newton-Euler ordering needs, keeping the emitted inline linear systems no larger
than required. The relative rotation is carried by a rotation matrix (the
`Revolute` form) rather than an Euler orientation object, so it does not chain
through the orientation-graph cycle of SciML/ModelingToolkit.jl#4608.
"""
component Bushing
  frame_a = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  frame_b = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 950, "y1": 450, "x2": 1050, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter iscut::Boolean = false
  final structural parameter residual::Real[3] = zeros(3) if iscut
  variable Rleaf::Real[3, 3]
  variable Rroot::Real[3, 3]
  "Propagation root for the relative kinematics / reactions (RNE equation direction)."
  structural parameter rooted::RootedFrame = MultibodyComponents.RootedFrame.FrameA()
  "Translational (linear) compliance: relative translation is a spring-damped state."
  structural parameter linear_compliance::Boolean = true
  """
  Rotational (angular) compliance: relative rotation is a spring-damped state. When
    false, orientation is transmitted rigidly (no relative-rotation state variables).
  """
  structural parameter angular_compliance::Boolean = true
  "Euler-angle sequence for the relative orientation."
  structural parameter sequence::Integer[3] = [1, 2, 3]
  "Translational stiffness [N/m]"
  parameter c_t::Real = 1000000
  "Translational damping [N*s/m]"
  parameter d_t::Real = 10000
  "Rotational stiffness [N*m/rad]"
  parameter c_r::Real = 100000
  "Rotational damping [N*m*s/rad]"
  parameter d_r::Real = 1000
  "Relative position frame_a -> frame_b, resolved in frame_a (spring-damped state if linear_compliance, else locked to 0)"
  variable r_rel::Position(statePriority = 50)[3]
  "Relative Cardan angles frame_a -> frame_b (spring-damped state if angular_compliance, else 0)"
  variable phi::Angle(statePriority = 50)[3]
  "Relative angular velocity = der(phi)"
  variable w::AngularVelocity[3]
  "Force on frame_b from the mount, resolved in frame_a (spring-damper if linear_compliance, else the rigid reaction)"
  variable f_a::Real[3]
  "Torque on frame_b from the mount, resolved in frame_a (spring-damper if angular_compliance, else the rigid reaction)"
  variable t_a::Real[3]
  "Relative rotation matrix frame_a -> frame_b (carries the relative angular velocity)"
  variable R_rel::Real[3, 3]
relations
  if iscut
    residue(Rleaf, Rroot) = residual
  else
    Rleaf = Rroot
  end
  # Relative rotation matrix. With angular_compliance=false, phi/w are pinned to 0
  # so R_rel is the identity and orientation is transmitted rigidly.
  R_rel = RR(axes_rotations(sequence, phi, w))
  # Translational wrench. Compliant: f_a is an explicit spring-damper source applied to
  # both frames (action-reaction), so it is direction-agnostic. Rigid: relative translation
  # is locked and f_a is a reaction unknown, so the transmission is written in the rooted
  # (RNE) direction - the root frame's force is computed from the leaf frame's (cf. Revolute).
  if linear_compliance
    guess r_rel = [0, 0, 0]
    f_a = c_t * r_rel + d_t * der(r_rel)
    frame_a.f = f_a
    frame_b.f = -resolve_relative(f_a, frame_a.R, frame_b.R)
  else
    r_rel = [0, 0, 0]
    f_a = frame_a.f
    switch rooted
      case FrameA
        frame_a.f = -resolve_relative(frame_b.f, frame_b.R, frame_a.R)
      case FrameB
        frame_b.f = -resolve_relative(frame_a.f, frame_a.R, frame_b.R)
    end
  end
  # Rotational wrench (moment arm cross(r_rel, f_a) taken about frame_a). Compliant: t_a is
  # an explicit spring-damper source (direction-agnostic). Rigid: relative rotation is locked
  # and t_a is a reaction unknown, transmitted in the rooted (RNE) direction.
  if angular_compliance
    guess phi = [0, 0, 0]
    w = der(phi)
    t_a = c_r * phi + d_r * w
    frame_a.tau = t_a + cross(r_rel, f_a)
    frame_b.tau = -resolve_relative(t_a, frame_a.R, frame_b.R)
  else
    phi = [0, 0, 0]
    w = [0, 0, 0]
    switch rooted
      case FrameA
        frame_a.tau = -resolve_relative(frame_b.tau, frame_b.R, frame_a.R) + cross(r_rel, f_a)
      case FrameB
        frame_b.tau = resolve_relative(cross(r_rel, f_a) - frame_a.tau, frame_a.R, frame_b.R)
    end
    t_a = frame_a.tau - cross(r_rel, f_a)
  end
  # Orientation + position written in the rooted (RNE) propagation direction.
  switch rooted
    case FrameA
      Rleaf = frame_b.R
      Rroot = R_rel * frame_a.R
      frame_b.r_0 = frame_a.r_0 + resolve1(frame_a.R, r_rel)
    case FrameB
      Rleaf = frame_a.R
      Rroot = transpose(R_rel) * frame_b.R
      frame_a.r_0 = frame_b.r_0 - resolve1(frame_a.R, r_rel)
  end
metadata {"Dyad": {"icons": {"default": "dyad://MultibodyComponents/Bushing.svg"}}}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses