Skip to content
LIBRARY
PlanarMechanics.OneDOFRollingWheelJoint.md

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:

NameDescriptionUnitsDefault value
rendertrue
color[0.1, 0.1, 0.1, 1]
specular_coefficient0.7
radiusRadius of the wheelm0.1
x0x position at zero roll anglem0
rim_diameterDiameter of the rim cylindersradius / 3
wheel_widthWidth of the wheelradius / 4
z_positionz-position of the wheel in animations0

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

NameDescriptionUnits
xPosition x of the bodym
vVelocity x of the bodym/s
phi_rollWheel rolling anglerad
w_rollWheel rolling velocityrad/s

Behavior

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

Source

dyad
"""
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"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
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"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.