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:
| Name | Description | Units | Default value |
|---|---|---|---|
iscut | – | false | |
residual | – | zeros(3) | |
rooted | Propagation root for the relative kinematics / reactions (RNE equation direction). | – | MultibodyCo...me.FrameA() |
linear_compliance | Translational (linear) compliance: relative translation is a spring-damped state. | – | true |
angular_compliance | Rotational (angular) compliance: relative rotation is a spring-damped state. When false, orientation is transmitted rigidly (no relative-rotation state variables). | – | true |
sequence | Euler-angle sequence for the relative orientation. | – | [1, 2, 3] |
c_t | Translational stiffness [N/m] | – | 1000000 |
d_t | Translational damping [N*s/m] | – | 10000 |
c_r | Rotational stiffness [N*m/rad] | – | 100000 |
d_r | Rotational damping [N_m_s/rad] | – | 1000 |
Connectors
frame_a- Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or severalFrame
connectors that can be connected together (Frame3D)
frame_b- Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or severalFrame
connectors that can be connected together (Frame3D)
Variables
| Name | Description | Units |
|---|---|---|
Rleaf | – | |
Rroot | – | |
r_rel | Relative position frame_a -> frame_b, resolved in frame_a (spring-damped state if linear_compliance, else locked to 0) | m |
phi | Relative Cardan angles frame_a -> frame_b (spring-damped state if angular_compliance, else 0) | rad |
w | Relative angular velocity = der(phi) | rad/s |
f_a | Force on frame_b from the mount, resolved in frame_a (spring-damper if linear_compliance, else the rigid reaction) | – |
t_a | Torque on frame_b from the mount, resolved in frame_a (spring-damper if angular_compliance, else the rigid reaction) | – |
R_rel | Relative 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
"""
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"}}}
endFlattened Source
"""
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"}}}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses