Skip to content
LIBRARY
PlanarMechanics.SlipBasedWheelJoint.md

PlanarMechanics.SlipBasedWheelJoint

Slip-based wheel joint with slip-dependent friction characteristics.

Models the behavior of a wheel rolling on an x,y-plane whose contact patch has slip-dependent friction. The driving direction (at phi=0) is given by parameter r.

The slip is decomposed into lateral and longitudinal components. For low rolling velocity, a dry-friction model is used. The friction force is computed using MultibodyComponents.limit_S_triple for smooth transitions between adhesion and sliding.

Connectors:

  • frame_a: 2D frame for steering on the plane

  • flange_a: 1D rotational flange for wheel rolling actuation

  • dynamicLoad: Input for dynamic component of normal load

This component extends from MultibodyComponents.Renderable

Usage

MultibodyComponents.PlanarMechanics.SlipBasedWheelJoint(render=true, color=[0.1, 0.1, 0.1, 1], specular_coefficient=0.7, r=[1, 0], N, vAdhesion_min, vSlide_min, sAdhesion, sSlide, mu_A, mu_S, radius=0.1, rim_diameter=0.1, wheel_width=0.06, z_position=0)

Parameters:

NameDescriptionUnitsDefault value
rendertrue
color[0.1, 0.1, 0.1, 1]
specular_coefficient0.7
rDriving direction of the wheel at angle phi = 0[1, 0]
NBase normal loadN
vAdhesion_minMinimum adhesion velocitym/s
vSlide_minMinimum sliding velocitym/s
sAdhesionAdhesion slippage
sSlideSliding slippage
mu_AFriction coefficient at adhesion
mu_SFriction coefficient at sliding
radiusRadius of the wheelm0.1
rim_diameterDiameter of the rim cylinders0.1
wheel_widthWidth of the wheel0.06
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)

  • flange_a - This connector represents a rotational spline with angle and torque as the potential and flow variables, respectively. (Spline)

  • dynamicLoad - This connector represents a real signal as an input to a component (RealInput)

Variables

NameDescriptionUnits
e0Unit vector in direction of r resolved w.r.t. inertial frame
phi_rollwheel anglerad
w_rollRoll velocity of wheelrad/s
v_vecvelocitym/s
v_latVelocity in lateral directionm/s
v_longVelocity in longitudinal directionm/s
v_slip_longSlip velocity in longitudinal directionm/s
v_slip_latSlip velocity in lateral directionm/s
v_slipSlip velocity, norm of component slip velocitiesm/s
fTotal traction forceN
f_latLateral forceN
f_longLongitudinal forceN
fNBase normal loadN
vAdhesionAdhesion velocitym/s
vSlideSliding velocitym/s

Behavior

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

Source

dyad
"""
Slip-based wheel joint with slip-dependent friction characteristics.

Models the behavior of a wheel rolling on an x,y-plane whose contact patch has
slip-dependent friction. The driving direction (at phi=0) is given by parameter `r`.

The slip is decomposed into lateral and longitudinal components. For low rolling
velocity, a dry-friction model is used. The friction force is computed using
`MultibodyComponents.limit_S_triple` for smooth transitions between adhesion and sliding.

Connectors:
- `frame_a`: 2D frame for steering on the plane
- `flange_a`: 1D rotational flange for wheel rolling actuation
- `dynamicLoad`: Input for dynamic component of normal load
"""
component SlipBasedWheelJoint
  extends MultibodyComponents.Renderable(color = [0.1, 0.1, 0.1, 1])
  frame_a = Frame2D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 50, "x2": 550, "y2": 150, "rot": 0}
      },
      "tags": []
    }
  }
  flange_a = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 950, "y1": 450, "x2": 1050, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  dynamicLoad = RealInput() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Tire shape (main cylinder)"
  tire_shape = MultibodyComponents.CylinderShape(render = render, color = [0.1, 0.1, 0.1, 1.0])
  "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])
  "Driving direction of the wheel at angle phi = 0"
  parameter r::Real[2] = [1, 0]
  "Base normal load"
  parameter N::Dyad.Force
  "Minimum adhesion velocity"
  parameter vAdhesion_min::Velocity
  "Minimum sliding velocity"
  parameter vSlide_min::Velocity
  "Adhesion slippage"
  parameter sAdhesion::Real
  "Sliding slippage"
  parameter sSlide::Real
  "Friction coefficient at adhesion"
  parameter mu_A::Real
  "Friction coefficient at sliding"
  parameter mu_S::Real
  "Radius of the wheel"
  parameter radius::Length = 0.1
  "Diameter of the rim cylinders"
  parameter rim_diameter::Real = 0.1
  "Width of the wheel"
  parameter wheel_width::Real = 0.06
  "z-position of the wheel in animations"
  parameter z_position::Real = 0
  "Unit vector in direction of r resolved w.r.t. inertial frame"
  variable e0::Real[2]
  "wheel angle"
  variable phi_roll::Angle
  "Roll velocity of wheel"
  variable w_roll::AngularVelocity
  "velocity"
  variable v_vec::Velocity[2]
  "Velocity in lateral direction"
  variable v_lat::Velocity
  "Velocity in longitudinal direction"
  variable v_long::Velocity
  "Slip velocity in longitudinal direction"
  variable v_slip_long::Velocity
  "Slip velocity in lateral direction"
  variable v_slip_lat::Velocity
  "Slip velocity, norm of component slip velocities"
  variable v_slip::Velocity
  "Total traction force"
  variable f::Dyad.Force
  "Lateral force"
  variable f_lat::Dyad.Force
  "Longitudinal force"
  variable f_long::Dyad.Force
  "Base normal load"
  variable fN::Dyad.Force
  "Adhesion velocity"
  variable vAdhesion::Velocity
  "Sliding velocity"
  variable vSlide::Velocity
relations
  # Unit vector in driving direction resolved in world frame
  e0 = [[cos(frame_a.phi), -sin(frame_a.phi)], [sin(frame_a.phi), cos(frame_a.phi)]] * (r / sqrt(adjoint(r) * r))
  # Velocity of the wheel center
  v_vec = [der(frame_a.x), der(frame_a.y)]
  # Wheel angle coupling
  phi_roll = flange_a.phi
  w_roll = der(phi_roll)
  # Decompose velocity into longitudinal and lateral
  v_long = dot(v_vec, e0)
  v_lat = -v_vec[1] * e0[2] + v_vec[2] * e0[1]
  # Slip velocities
  v_slip_lat = v_lat
  v_slip_long = v_long - radius * w_roll
  v_slip = sqrt(v_slip_long ^ 2 + v_slip_lat ^ 2) + 0.0001
  # Flange torque from longitudinal force
  0 = flange_a.tau + f_long * radius
  # No torque on the 2D frame
  frame_a.tau = 0
  # Velocity-dependent adhesion/slide thresholds
  vAdhesion = max(vAdhesion_min, sAdhesion * abs(radius * w_roll))
  vSlide = max(vSlide_min, sSlide * abs(radius * w_roll))
  # Normal force (base + dynamic load, clamped to non-negative)
  fN = max(0, N + dynamicLoad)
  # Total friction force from slip curve
  f = fN * MultibodyComponents.limit_S_triple(vAdhesion, vSlide, mu_A, mu_S, v_slip)
  # Distribute friction force proportionally to slip components
  f_long = f * v_slip_long / v_slip
  f_lat = f * v_slip_lat / v_slip
  # Frame force equations: project onto world axes via e0
  f_long = dot([frame_a.fx, frame_a.fy], e0)
  f_lat = dot([frame_a.fy, -frame_a.fx], e0)
  # Tire shape: cylinder along the axle (perpendicular to driving direction e0)
  tire_shape.r = [frame_a.x, frame_a.y, z_position]
  tire_shape.R = MultibodyComponents.RR(MultibodyComponents.nullrotation())
  tire_shape.r_shape = -0.03 * [-e0[2], e0[1], 0]
  tire_shape.length_direction = [-e0[2], e0[1], 0]
  tire_shape.width_direction = [0, 0, 1]
  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([-e0[2], e0[1], 0], -phi_roll, -w_roll)
  rim1_shape.r_shape = [0, 0, -radius]
  rim1_shape.length_direction = [0, 0, 1]
  rim1_shape.width_direction = [1, 0, 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([-e0[2], e0[1], 0], -phi_roll + 3.14159265358979 / 2, -w_roll)
  rim2_shape.r_shape = [0, 0, -radius]
  rim2_shape.length_direction = [0, 0, 1]
  rim2_shape.width_direction = [1, 0, 0]
  rim2_shape.length = radius * 2
  rim2_shape.width = rim_diameter
  rim2_shape.height = rim_diameter
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/SlipBasedWheelJoint.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 900,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
Slip-based wheel joint with slip-dependent friction characteristics.

Models the behavior of a wheel rolling on an x,y-plane whose contact patch has
slip-dependent friction. The driving direction (at phi=0) is given by parameter `r`.

The slip is decomposed into lateral and longitudinal components. For low rolling
velocity, a dry-friction model is used. The friction force is computed using
`MultibodyComponents.limit_S_triple` for smooth transitions between adhesion and sliding.

Connectors:
- `frame_a`: 2D frame for steering on the plane
- `flange_a`: 1D rotational flange for wheel rolling actuation
- `dynamicLoad`: Input for dynamic component of normal load
"""
component SlipBasedWheelJoint
  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": 50, "x2": 550, "y2": 150, "rot": 0}
      },
      "tags": []
    }
  }
  flange_a = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 950, "y1": 450, "x2": 1050, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  dynamicLoad = RealInput() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Tire shape (main cylinder)"
  tire_shape = MultibodyComponents.CylinderShape(render = render, color = [0.1, 0.1, 0.1, 1.0])
  "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])
  "Driving direction of the wheel at angle phi = 0"
  parameter r::Real[2] = [1, 0]
  "Base normal load"
  parameter N::Dyad.Force
  "Minimum adhesion velocity"
  parameter vAdhesion_min::Velocity
  "Minimum sliding velocity"
  parameter vSlide_min::Velocity
  "Adhesion slippage"
  parameter sAdhesion::Real
  "Sliding slippage"
  parameter sSlide::Real
  "Friction coefficient at adhesion"
  parameter mu_A::Real
  "Friction coefficient at sliding"
  parameter mu_S::Real
  "Radius of the wheel"
  parameter radius::Length = 0.1
  "Diameter of the rim cylinders"
  parameter rim_diameter::Real = 0.1
  "Width of the wheel"
  parameter wheel_width::Real = 0.06
  "z-position of the wheel in animations"
  parameter z_position::Real = 0
  "Unit vector in direction of r resolved w.r.t. inertial frame"
  variable e0::Real[2]
  "wheel angle"
  variable phi_roll::Angle
  "Roll velocity of wheel"
  variable w_roll::AngularVelocity
  "velocity"
  variable v_vec::Velocity[2]
  "Velocity in lateral direction"
  variable v_lat::Velocity
  "Velocity in longitudinal direction"
  variable v_long::Velocity
  "Slip velocity in longitudinal direction"
  variable v_slip_long::Velocity
  "Slip velocity in lateral direction"
  variable v_slip_lat::Velocity
  "Slip velocity, norm of component slip velocities"
  variable v_slip::Velocity
  "Total traction force"
  variable f::Dyad.Force
  "Lateral force"
  variable f_lat::Dyad.Force
  "Longitudinal force"
  variable f_long::Dyad.Force
  "Base normal load"
  variable fN::Dyad.Force
  "Adhesion velocity"
  variable vAdhesion::Velocity
  "Sliding velocity"
  variable vSlide::Velocity
relations
  # Unit vector in driving direction resolved in world frame
  e0 = [[cos(frame_a.phi), -sin(frame_a.phi)], [sin(frame_a.phi), cos(frame_a.phi)]] * (r / sqrt(adjoint(r) * r))
  # Velocity of the wheel center
  v_vec = [der(frame_a.x), der(frame_a.y)]
  # Wheel angle coupling
  phi_roll = flange_a.phi
  w_roll = der(phi_roll)
  # Decompose velocity into longitudinal and lateral
  v_long = dot(v_vec, e0)
  v_lat = -v_vec[1] * e0[2] + v_vec[2] * e0[1]
  # Slip velocities
  v_slip_lat = v_lat
  v_slip_long = v_long - radius * w_roll
  v_slip = sqrt(v_slip_long ^ 2 + v_slip_lat ^ 2) + 0.0001
  # Flange torque from longitudinal force
  0 = flange_a.tau + f_long * radius
  # No torque on the 2D frame
  frame_a.tau = 0
  # Velocity-dependent adhesion/slide thresholds
  vAdhesion = max(vAdhesion_min, sAdhesion * abs(radius * w_roll))
  vSlide = max(vSlide_min, sSlide * abs(radius * w_roll))
  # Normal force (base + dynamic load, clamped to non-negative)
  fN = max(0, N + dynamicLoad)
  # Total friction force from slip curve
  f = fN * MultibodyComponents.limit_S_triple(vAdhesion, vSlide, mu_A, mu_S, v_slip)
  # Distribute friction force proportionally to slip components
  f_long = f * v_slip_long / v_slip
  f_lat = f * v_slip_lat / v_slip
  # Frame force equations: project onto world axes via e0
  f_long = dot([frame_a.fx, frame_a.fy], e0)
  f_lat = dot([frame_a.fy, -frame_a.fx], e0)
  # Tire shape: cylinder along the axle (perpendicular to driving direction e0)
  tire_shape.r = [frame_a.x, frame_a.y, z_position]
  tire_shape.R = MultibodyComponents.RR(MultibodyComponents.nullrotation())
  tire_shape.r_shape = -0.03 * [-e0[2], e0[1], 0]
  tire_shape.length_direction = [-e0[2], e0[1], 0]
  tire_shape.width_direction = [0, 0, 1]
  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([-e0[2], e0[1], 0], -phi_roll, -w_roll)
  rim1_shape.r_shape = [0, 0, -radius]
  rim1_shape.length_direction = [0, 0, 1]
  rim1_shape.width_direction = [1, 0, 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([-e0[2], e0[1], 0], -phi_roll + 3.14159265358979 / 2, -w_roll)
  rim2_shape.r_shape = [0, 0, -radius]
  rim2_shape.length_direction = [0, 0, 1]
  rim2_shape.width_direction = [1, 0, 0]
  rim2_shape.length = radius * 2
  rim2_shape.width = rim_diameter
  rim2_shape.height = rim_diameter
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/SlipBasedWheelJoint.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 900,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses