PlanarMechanics.OneDOFRollingWheelJoint
An ideal rolling wheel joint constrained to move only along the x-axis without slip.
Enforces a perfect rolling constraint: x = radius * phi_roll + x0. The y-position is constrained to equal the wheel radius (ground contact). Suitable for simplified models where tire slip can be neglected.
This component extends from MultibodyComponents.Renderable
Usage
MultibodyComponents.PlanarMechanics.OneDOFRollingWheelJoint(render=true, color=[0.1, 0.1, 0.1, 1], specular_coefficient=0.7, radius=0.1, x0=0, rim_diameter=radius / 3, wheel_width=radius / 4, z_position=0)
Parameters:
| Name | Description | Units | Default value |
|---|---|---|---|
render | – | true | |
color | – | [0.1, 0.1, 0.1, 1] | |
specular_coefficient | – | 0.7 | |
radius | Radius of the wheel | m | 0.1 |
x0 | x position at zero roll angle | m | 0 |
rim_diameter | Diameter of the rim cylinders | – | radius / 3 |
wheel_width | Width of the wheel | – | radius / 4 |
z_position | z-position of the wheel in animations | – | 0 |
Connectors
frame_a- Coordinate system (2-dim.) fixed to the component with one cut-force and cut-torque.
All variables are resolved in the planar world frame. (Frame2D)
Variables
| Name | Description | Units |
|---|---|---|
x | Position x of the body | m |
v | Velocity x of the body | m/s |
phi_roll | Wheel rolling angle | rad |
w_roll | Wheel rolling velocity | rad/s |
Behavior
Dict{MIME{Symbol("text/plain")}, String} with 1 entry: MIME type text/plain => "Error displaying result"
Source
"""
An ideal rolling wheel joint constrained to move only along the x-axis without slip.
Enforces a perfect rolling constraint: `x = radius * phi_roll + x0`.
The y-position is constrained to equal the wheel radius (ground contact).
Suitable for simplified models where tire slip can be neglected.
"""
component OneDOFRollingWheelJoint
extends MultibodyComponents.Renderable(color = [0.1, 0.1, 0.1, 1])
frame_a = Frame2D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 150, "x2": 550, "y2": 250, "rot": 0}
},
"tags": []
}
}
"Tire shape (main cylinder)"
tire_shape = MultibodyComponents.CylinderShape(render = render, color = color)
"Rim shape 1 (cross cylinder showing rotation)"
rim1_shape = MultibodyComponents.CylinderShape(render = render, color = [0.8, 0.8, 0.8, 1.0])
"Rim shape 2 (cross cylinder at 90 degrees)"
rim2_shape = MultibodyComponents.CylinderShape(render = render, color = [0.8, 0.8, 0.8, 1.0])
"Radius of the wheel"
parameter radius::Length = 0.1
"x position at zero roll angle"
parameter x0::Length = 0
"Diameter of the rim cylinders"
parameter rim_diameter::Real = radius / 3
"Width of the wheel"
parameter wheel_width::Real = radius / 4
"z-position of the wheel in animations"
parameter z_position::Real = 0
"Position x of the body"
variable x::Dyad.Position
"Velocity x of the body"
variable v::Velocity
"Wheel rolling angle"
variable phi_roll::Angle
"Wheel rolling velocity"
variable w_roll::AngularVelocity
relations
# Wheel angle coupling
phi_roll = -frame_a.phi
w_roll = der(phi_roll)
x = frame_a.x
v = der(x)
# Ideal rolling constraint: ground velocity = wheel surface velocity
x = radius * phi_roll + x0
# Force/torque relationship (from constraint)
frame_a.tau = radius * frame_a.fx
# 1-DOF constraints
frame_a.y = radius # Wheel center at ground level + radius
# Tire shape: cylinder along the axle
tire_shape.r = [frame_a.x, frame_a.y, z_position]
tire_shape.R = MultibodyComponents.RR(MultibodyComponents.nullrotation())
tire_shape.r_shape = [0, 0, -wheel_width / 2]
tire_shape.length_direction = [0, 0, 1]
tire_shape.width_direction = [0, 1, 0]
tire_shape.length = wheel_width
tire_shape.width = radius * 2
tire_shape.height = radius * 2
# Rim 1: cross cylinder that rotates with the wheel around the axle
rim1_shape.r = [frame_a.x, frame_a.y, z_position]
rim1_shape.R = MultibodyComponents.planar_rotation([0, 0, 1], phi_roll, w_roll)
rim1_shape.r_shape = [-radius, 0, 0]
rim1_shape.length_direction = [1, 0, 0]
rim1_shape.width_direction = [0, 1, 0]
rim1_shape.length = radius * 2
rim1_shape.width = rim_diameter
rim1_shape.height = rim_diameter
# Rim 2: same but offset by 90 degrees
rim2_shape.r = [frame_a.x, frame_a.y, z_position]
rim2_shape.R = MultibodyComponents.planar_rotation([0, 0, 1], phi_roll + 3.14159265358979 / 2, w_roll)
rim2_shape.r_shape = [-radius, 0, 0]
rim2_shape.length_direction = [1, 0, 0]
rim2_shape.width_direction = [0, 1, 0]
rim2_shape.length = radius * 2
rim2_shape.width = rim_diameter
rim2_shape.height = rim_diameter
metadata {
"Dyad": {
"icons": {"default": "dyad://MultibodyComponents/OneDOFRollingWheelJoint.svg"},
"labels": [
{
"label": "$(instance)",
"x": 500,
"y": 900,
"rot": 0,
"attrs": {"font-size": "160"}
}
]
}
}
endFlattened Source
"""
An ideal rolling wheel joint constrained to move only along the x-axis without slip.
Enforces a perfect rolling constraint: `x = radius * phi_roll + x0`.
The y-position is constrained to equal the wheel radius (ground contact).
Suitable for simplified models where tire slip can be neglected.
"""
component OneDOFRollingWheelJoint
parameter render::Boolean = true
parameter color::Real[4] = [0.5, 0.5, 0.5, 1.0]
parameter specular_coefficient::Real = 0.7
frame_a = Frame2D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 150, "x2": 550, "y2": 250, "rot": 0}
},
"tags": []
}
}
"Tire shape (main cylinder)"
tire_shape = MultibodyComponents.CylinderShape(render = render, color = color)
"Rim shape 1 (cross cylinder showing rotation)"
rim1_shape = MultibodyComponents.CylinderShape(render = render, color = [0.8, 0.8, 0.8, 1.0])
"Rim shape 2 (cross cylinder at 90 degrees)"
rim2_shape = MultibodyComponents.CylinderShape(render = render, color = [0.8, 0.8, 0.8, 1.0])
"Radius of the wheel"
parameter radius::Length = 0.1
"x position at zero roll angle"
parameter x0::Length = 0
"Diameter of the rim cylinders"
parameter rim_diameter::Real = radius / 3
"Width of the wheel"
parameter wheel_width::Real = radius / 4
"z-position of the wheel in animations"
parameter z_position::Real = 0
"Position x of the body"
variable x::Dyad.Position
"Velocity x of the body"
variable v::Velocity
"Wheel rolling angle"
variable phi_roll::Angle
"Wheel rolling velocity"
variable w_roll::AngularVelocity
relations
# Wheel angle coupling
phi_roll = -frame_a.phi
w_roll = der(phi_roll)
x = frame_a.x
v = der(x)
# Ideal rolling constraint: ground velocity = wheel surface velocity
x = radius * phi_roll + x0
# Force/torque relationship (from constraint)
frame_a.tau = radius * frame_a.fx
# 1-DOF constraints
frame_a.y = radius # Wheel center at ground level + radius
# Tire shape: cylinder along the axle
tire_shape.r = [frame_a.x, frame_a.y, z_position]
tire_shape.R = MultibodyComponents.RR(MultibodyComponents.nullrotation())
tire_shape.r_shape = [0, 0, -wheel_width / 2]
tire_shape.length_direction = [0, 0, 1]
tire_shape.width_direction = [0, 1, 0]
tire_shape.length = wheel_width
tire_shape.width = radius * 2
tire_shape.height = radius * 2
# Rim 1: cross cylinder that rotates with the wheel around the axle
rim1_shape.r = [frame_a.x, frame_a.y, z_position]
rim1_shape.R = MultibodyComponents.planar_rotation([0, 0, 1], phi_roll, w_roll)
rim1_shape.r_shape = [-radius, 0, 0]
rim1_shape.length_direction = [1, 0, 0]
rim1_shape.width_direction = [0, 1, 0]
rim1_shape.length = radius * 2
rim1_shape.width = rim_diameter
rim1_shape.height = rim_diameter
# Rim 2: same but offset by 90 degrees
rim2_shape.r = [frame_a.x, frame_a.y, z_position]
rim2_shape.R = MultibodyComponents.planar_rotation([0, 0, 1], phi_roll + 3.14159265358979 / 2, w_roll)
rim2_shape.r_shape = [-radius, 0, 0]
rim2_shape.length_direction = [1, 0, 0]
rim2_shape.width_direction = [0, 1, 0]
rim2_shape.length = radius * 2
rim2_shape.width = rim_diameter
rim2_shape.height = rim_diameter
metadata {
"Dyad": {
"icons": {"default": "dyad://MultibodyComponents/OneDOFRollingWheelJoint.svg"},
"labels": [
{
"label": "$(instance)",
"x": 500,
"y": 900,
"rot": 0,
"attrs": {"font-size": "160"}
}
]
}
}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses
Tests