Spherical
Spherical joint: free rotation in all three directions (ball joint). Provides 3 rotational degrees of freedom at a single point. Extends PartialOrientation to support Euler angle, quaternion, or stateless modes via the orientation_state parameter:
Euler(): Euler angle state (3 angles)Quaternion(): Quaternion stateNone(): No state, orientation provided by connected components (default)
When orientation_state != None, the joint acts as root of the orientation tree. No torque is transmitted through the joint.
This component extends from PartialOrientation This component extends from Renderable
Usage
MultibodyComponents.Spherical(k=0.1, render=true, color=world_default_joint_color(), specular_coefficient=1.5, radius=world_default_joint_width())
Parameters:
| Name | Description | Units | Default value |
|---|---|---|---|
orientation_state | – | OrientationState.Euler() | |
sequence | – | [1, 2, 3] | |
statePriority | – | 10 | |
w_rel_a_fixed | – | false | |
z_rel_a_fixed | – | false | |
k | – | 0.1 | |
render | – | true | |
color | – | world_defau...int_color() | |
specular_coefficient | – | 1.5 | |
radius | Radius of the sphere in animations | – | world_defau...int_width() |
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 |
|---|---|---|
w_a | Absolute angular velocity of frame_a resolved in frame_a | rad/s |
z_a | Absolute angular acceleration of frame_a resolved in frame_a | rad/s2 |
Q | Unit quaternion with [w,i,j,k] | – |
Q_hat | Non-unit quaternion with [w,i,j,k] | – |
Q_hat_d | – | |
n_q | – | |
c_q | – | |
phi | Euler angles | rad |
phid | rad/s | |
phidd | rad/s2 |
Behavior
Dict{MIME{Symbol("text/plain")}, String} with 1 entry: MIME type text/plain => "Error displaying result"
Source
"""
Spherical joint: free rotation in all three directions (ball joint).
Provides 3 rotational degrees of freedom at a single point. Extends
`PartialOrientation` to support Euler angle, quaternion, or stateless modes
via the `orientation_state` parameter:
- `Euler()`: Euler angle state (3 angles)
- `Quaternion()`: Quaternion state
- `None()`: No state, orientation provided by connected components (default)
When `orientation_state != None`, the joint acts as root of the orientation tree.
No torque is transmitted through the joint.
"""
component Spherical
extends PartialOrientation(orientation_state = OrientationState.Euler())
extends Renderable(color = world_default_joint_color())
frame_b = Frame3D() {}
# Visualization shape
shape = SphereShape(render = render, color = color, r = frame_a.r_0, R = transpose(frame_a.R), length = 2 * radius, width = 2 * radius, height = 2 * radius)
structural parameter w_rel_a_fixed::Boolean = false
structural parameter z_rel_a_fixed::Boolean = false
"Radius of the sphere in animations"
parameter radius::Real = world_default_joint_width()
relations
# Position constraint: frames coincide
frame_b.r_0 = frame_a.r_0
# Torque: free rotation (zero torque transmitted)
frame_a.tau = [0, 0, 0]
frame_b.tau = [0, 0, 0]
# w_a inherited from PartialOrientation is the relative angular velocity (w_rel) here
switch orientation_state
case None
# No state: pure constraint
frame_a.f = -resolve_relative(frame_b.f, frame_b, frame_a)
if w_rel_a_fixed or z_rel_a_fixed
w_a = angular_velocity2(ori(frame_b)) - resolve2(frame_b, angular_velocity1(ori(frame_a)))
else
w_a = zeros(3)
end
case Euler
# Joint has state: frame_b is frame_a composed with the relative rotation.
# Rrel from axes_rotations already carries the relative angular velocity.
ori(frame_b) = absolute_rotation(ori(frame_a), Rrel)
frame_a.f = -resolve1(Rrel, frame_b.f)
case Quaternion
# from_Q(Q) is only the relative rotation matrix; pair it with the
# relative angular velocity w_a to form a full rotation object.
ori(frame_b) = absolute_rotation(ori(frame_a), RM(from_Q(Q), w_a))
frame_a.f = -resolve1(RM(from_Q(Q), w_a), frame_b.f)
end
endFlattened Source
"""
Spherical joint: free rotation in all three directions (ball joint).
Provides 3 rotational degrees of freedom at a single point. Extends
`PartialOrientation` to support Euler angle, quaternion, or stateless modes
via the `orientation_state` parameter:
- `Euler()`: Euler angle state (3 angles)
- `Quaternion()`: Quaternion state
- `None()`: No state, orientation provided by connected components (default)
When `orientation_state != None`, the joint acts as root of the orientation tree.
No torque is transmitted through the joint.
"""
component Spherical
frame_a = Frame3D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 0, "y1": 450, "x2": 100, "y2": 550, "rot": 0}
},
"tags": []
}
}
structural parameter orientation_state::OrientationState = OrientationState.None()
structural parameter sequence::Integer[3] = [1, 2, 3]
structural parameter statePriority::Integer = 10
"Absolute angular velocity of frame_a resolved in frame_a"
variable w_a::AngularVelocity(statePriority = case(orientation_state, OrientationState.Quaternion) ? 10 : 0, initial = case(orientation_state, OrientationState.Quaternion) ? [0.0, 0, 0] : missing)[3]
"Absolute angular acceleration of frame_a resolved in frame_a"
variable z_a::AngularAcceleration[3]
"Unit quaternion with [w,i,j,k]"
variable Q::Real[4] if case(orientation_state, OrientationState.Quaternion)
"Non-unit quaternion with [w,i,j,k]"
variable Q_hat::Real(statePriority = statePriority, initial = [1.0, 0, 0, 0])[4] if case(orientation_state, OrientationState.Quaternion)
variable Q_hat_d::Real[4] if case(orientation_state, OrientationState.Quaternion)
variable n_q::Real if case(orientation_state, OrientationState.Quaternion)
variable c_q::Real if case(orientation_state, OrientationState.Quaternion)
parameter k::Real = 0.1 if case(orientation_state, OrientationState.Quaternion)
"Euler angles"
variable phi::Angle(statePriority = statePriority, initial = [0, 0, 0])[3] if case(orientation_state, OrientationState.Euler)
variable phid::AngularVelocity(statePriority = statePriority, initial = [0, 0, 0])[3] if case(orientation_state, OrientationState.Euler)
variable phidd::AngularAcceleration[3] if case(orientation_state, OrientationState.Euler)
structural variable Rrel::Native = case(orientation_state, OrientationState.Euler) ? axes_rotations(sequence, phi, phid) : (case(orientation_state, OrientationState.Quaternion) ? from_Q(Q) : nullrotation())
parameter render::Boolean = true
parameter color::Real[4] = [0.5, 0.5, 0.5, 1.0]
parameter specular_coefficient::Real = 1.5
frame_b = Frame3D() {}
# Visualization shape
shape = SphereShape(render = render, color = color, r = frame_a.r_0, R = transpose(frame_a.R), length = 2 * radius, width = 2 * radius, height = 2 * radius)
structural parameter w_rel_a_fixed::Boolean = false
structural parameter z_rel_a_fixed::Boolean = false
"Radius of the sphere in animations"
parameter radius::Real = world_default_joint_width()
relations
z_a = der(w_a)
switch orientation_state
case Quaternion
# guess Q_hat = Q # TODO: Ideally it should be possible to provide this guess, but due to dyad codegen to initial equations the guess propagation is not working correctly and ODEProblem gets stuck. Once the initial condition for Q codegens to __initial_conditions, we can start providing this guess again.
n_q = dot(Q_hat, Q_hat)
c_q = k * (1 - n_q)
der(Q_hat) = Q_hat_d
Q_hat_d = omega_matrix(w_a) * Q_hat / 2 + c_q * Q_hat
Q = Q_hat / sqrt(n_q)
case Euler
phid = der(phi)
phidd = der(phid)
w_a = angular_velocity2(Rrel)
case None
end
# Position constraint: frames coincide
frame_b.r_0 = frame_a.r_0
# Torque: free rotation (zero torque transmitted)
frame_a.tau = [0, 0, 0]
frame_b.tau = [0, 0, 0]
# w_a inherited from PartialOrientation is the relative angular velocity (w_rel) here
switch orientation_state
case None
# No state: pure constraint
frame_a.f = -resolve_relative(frame_b.f, frame_b, frame_a)
if w_rel_a_fixed or z_rel_a_fixed
w_a = angular_velocity2(ori(frame_b)) - resolve2(frame_b, angular_velocity1(ori(frame_a)))
else
w_a = zeros(3)
end
case Euler
# Joint has state: frame_b is frame_a composed with the relative rotation.
# Rrel from axes_rotations already carries the relative angular velocity.
ori(frame_b) = absolute_rotation(ori(frame_a), Rrel)
frame_a.f = -resolve1(Rrel, frame_b.f)
case Quaternion
# from_Q(Q) is only the relative rotation matrix; pair it with the
# relative angular velocity w_a to form a full rotation object.
ori(frame_b) = absolute_rotation(ori(frame_a), RM(from_Q(Q), w_a))
frame_a.f = -resolve1(RM(from_Q(Q), w_a), frame_b.f)
end
metadata {}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses