Skip to content
LIBRARY
examples.suspension.ExcitedWheelAssembly.md

examples.suspension.ExcitedWheelAssembly

Quarter-car suspension carrying a slipping wheel, excited by a time-varying road.

Wraps a QuarterCarSuspension, attaches a Revolute wheel spin axis at the suspension's wheel_frame, and a SlippingWheel (slip-dependent tire friction) running on a flat road whose height oscillates in time, y = amplitude*sin(2π*freq*t), supplied through the wheel's surface_frame. Rotational losses on the spin axis are modelled by a rotational Damper. The chassis is exposed via chassis_frame.

Usage

MultibodyComponents.examples.suspension.ExcitedWheelAssembly(rod_radius=0.02, amplitude=0.02, freq=2, dir=ifelse(mirror, -1.0, 1.0), n_wheel=[0, 0, dir])

Parameters:

NameDescriptionUnitsDefault value
positive_branchAssembly branch (elbow up/down) of the suspension's analytic loop closuretrue
springtrue
mirrorfalse
iscutCut the wheel's orientation loop with the (rooted) suspension axis. Required when the wheel is mounted on an axis whose orientation is already determined.true
angular_stateInclude the wheel's angular state. Set false (and iscut false) to drop the wheel orientation loop entirely — needed for free-floating multi-wheel cars where the cut-force distribution would otherwise be redundant.true
elastic_contactUse a compliant (elastic) tire contact (see SlipWheelJoint). Decouples the wheel-ground contact so f_n and the contact accelerations leave the coupled block.false
elastic_mountMount the suspension to the chassis through a compliant 6-DOF Bushing instead of a rigid connection. Decouples this corner from the chassis so the four corners no longer share one coupled inline-linear block.false
rod_radiusRadius of the rods0.02
amplitudeAmplitude of the road-height excitation [m]0.02
freqFrequency of the road-height excitation [Hz]Hz2

Connectors

  • chassis_frame - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

Behavior

Source

dyad
"""
Quarter-car suspension carrying a slipping wheel, excited by a time-varying road.

Wraps a `QuarterCarSuspension`, attaches a `Revolute` wheel spin axis at the
suspension's `wheel_frame`, and a `SlippingWheel` (slip-dependent tire friction)
running on a flat road whose height oscillates in time,
`y = amplitude*sin(2π*freq*t)`, supplied through the wheel's `surface_frame`.
Rotational losses on the spin axis are modelled by a rotational `Damper`. The
chassis is exposed via `chassis_frame`.
"""
component ExcitedWheelAssembly
  "Frame rigidly attached to the chassis"
  chassis_frame = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  suspension = QuarterCarSuspension(spring = spring, mirror = mirror, rod_radius = rod_radius, positive_branch = positive_branch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 330, "y1": 530, "x2": 430, "y2": 630, "rot": 0}
      },
      "tags": []
    }
  }
  # High state priority: the wheel-spin DOF must be represented by this joint's
  # coordinate (phi, w). Otherwise the tearing may match the spin rate to contact
  # -frame derivative equations whose spin coefficient is identically zero for the
  # axis-aligned wheel axis (StateSelection.jl#98 diagnosis).
  wheel_rotation = MultibodyComponents.Revolute(n = n_wheel, n_nonzero = [false, false, true], statePriority = 100) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 390, "y1": 730, "x2": 490, "y2": 830, "rot": 0}
      },
      "tags": []
    }
  }
  rotational_losses = RotationalComponents.Components.Damper(d = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 860, "x2": 310, "y2": 960, "rot": 0}
      },
      "tags": []
    }
  }
  wheel = MultibodyComponents.SlippingWheel(radius = 0.2, m = 15, I_axis = 0.8, I_long = 0.8, iscut = iscut, angular_state = angular_state, elastic_contact = elastic_contact, surface = true) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 480, "y1": 810, "x2": 580, "y2": 910, "rot": 0}
      },
      "tags": []
    }
  }
  mount = MultibodyComponents.Bushing() if elastic_mount {}
  "Assembly branch (elbow up/down) of the suspension's analytic loop closure"
  structural parameter positive_branch::Boolean = true
  structural parameter spring::Boolean = true
  structural parameter mirror::Boolean = false
  """
  Cut the wheel's orientation loop with the (rooted) suspension axis. Required
   when the wheel is mounted on an axis whose orientation is already determined.
  """
  structural parameter iscut::Boolean = true
  """
  Include the wheel's angular state. Set false (and iscut false) to drop the
   wheel orientation loop entirely — needed for free-floating multi-wheel cars
   where the cut-force distribution would otherwise be redundant.
  """
  structural parameter angular_state::Boolean = true
  """
  Use a compliant (elastic) tire contact (see SlipWheelJoint). Decouples the
    wheel-ground contact so f_n and the contact accelerations leave the coupled block.
  """
  structural parameter elastic_contact::Boolean = false
  """
  Mount the suspension to the chassis through a compliant 6-DOF Bushing instead
    of a rigid connection. Decouples this corner from the chassis so the four
    corners no longer share one coupled inline-linear block.
  """
  structural parameter elastic_mount::Boolean = false
  "Radius of the rods"
  parameter rod_radius::Real = 0.02
  "Amplitude of the road-height excitation [m]"
  parameter amplitude::Real = 0.02
  "Frequency of the road-height excitation [Hz]"
  parameter freq::Frequency = 2
  final parameter dir::Real = ifelse(mirror, -1.0, 1.0)
  final parameter n_wheel::Real[3] = [0, 0, dir]
relations
  # Road excitation: a flat road whose height oscillates in time. The road is
  # flat (height independent of x,z), so the contact normal stays vertical (R = I);
  # x,z are left free so the contact patch tracks the wheel.
  wheel.surface_frame.r_0[2] = amplitude * sin(2 * π * freq * time)
  wheel.surface_frame.R = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
  connect(wheel.frame_a, wheel_rotation.frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 490, "y": 860}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rotational_losses.spline_a, wheel_rotation.axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 440, "y": 910}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rotational_losses.spline_b, wheel_rotation.support) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 250, "y": 910}, {"x": 250, "y": 820}, {"x": 405, "y": 820}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  if elastic_mount
    connect(mount.frame_a, chassis_frame)
    connect(mount.frame_b, suspension.chassis_frame)
  else
    connect(suspension.chassis_frame, chassis_frame)
  end
  connect(wheel_rotation.frame_a, suspension.wheel_frame) {
    "Dyad": {
      "renderStyle": "standard",
      "edges": [{"S": 1, "M": [{"x": 380, "y": 780}], "E": 2}]
    }
  }
metadata {
  "Dyad": {"icons": {"default": "dyad://MultibodyComponents/ExcitedWheelAssembly.svg"}}
}
end
Flattened Source
dyad
"""
Quarter-car suspension carrying a slipping wheel, excited by a time-varying road.

Wraps a `QuarterCarSuspension`, attaches a `Revolute` wheel spin axis at the
suspension's `wheel_frame`, and a `SlippingWheel` (slip-dependent tire friction)
running on a flat road whose height oscillates in time,
`y = amplitude*sin(2π*freq*t)`, supplied through the wheel's `surface_frame`.
Rotational losses on the spin axis are modelled by a rotational `Damper`. The
chassis is exposed via `chassis_frame`.
"""
component ExcitedWheelAssembly
  "Frame rigidly attached to the chassis"
  chassis_frame = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  suspension = QuarterCarSuspension(spring = spring, mirror = mirror, rod_radius = rod_radius, positive_branch = positive_branch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 330, "y1": 530, "x2": 430, "y2": 630, "rot": 0}
      },
      "tags": []
    }
  }
  # High state priority: the wheel-spin DOF must be represented by this joint's
  # coordinate (phi, w). Otherwise the tearing may match the spin rate to contact
  # -frame derivative equations whose spin coefficient is identically zero for the
  # axis-aligned wheel axis (StateSelection.jl#98 diagnosis).
  wheel_rotation = MultibodyComponents.Revolute(n = n_wheel, n_nonzero = [false, false, true], statePriority = 100) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 390, "y1": 730, "x2": 490, "y2": 830, "rot": 0}
      },
      "tags": []
    }
  }
  rotational_losses = RotationalComponents.Components.Damper(d = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 860, "x2": 310, "y2": 960, "rot": 0}
      },
      "tags": []
    }
  }
  wheel = MultibodyComponents.SlippingWheel(radius = 0.2, m = 15, I_axis = 0.8, I_long = 0.8, iscut = iscut, angular_state = angular_state, elastic_contact = elastic_contact, surface = true) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 480, "y1": 810, "x2": 580, "y2": 910, "rot": 0}
      },
      "tags": []
    }
  }
  mount = MultibodyComponents.Bushing() if elastic_mount {}
  "Assembly branch (elbow up/down) of the suspension's analytic loop closure"
  structural parameter positive_branch::Boolean = true
  structural parameter spring::Boolean = true
  structural parameter mirror::Boolean = false
  """
  Cut the wheel's orientation loop with the (rooted) suspension axis. Required
   when the wheel is mounted on an axis whose orientation is already determined.
  """
  structural parameter iscut::Boolean = true
  """
  Include the wheel's angular state. Set false (and iscut false) to drop the
   wheel orientation loop entirely — needed for free-floating multi-wheel cars
   where the cut-force distribution would otherwise be redundant.
  """
  structural parameter angular_state::Boolean = true
  """
  Use a compliant (elastic) tire contact (see SlipWheelJoint). Decouples the
    wheel-ground contact so f_n and the contact accelerations leave the coupled block.
  """
  structural parameter elastic_contact::Boolean = false
  """
  Mount the suspension to the chassis through a compliant 6-DOF Bushing instead
    of a rigid connection. Decouples this corner from the chassis so the four
    corners no longer share one coupled inline-linear block.
  """
  structural parameter elastic_mount::Boolean = false
  "Radius of the rods"
  parameter rod_radius::Real = 0.02
  "Amplitude of the road-height excitation [m]"
  parameter amplitude::Real = 0.02
  "Frequency of the road-height excitation [Hz]"
  parameter freq::Frequency = 2
  final parameter dir::Real = ifelse(mirror, -1.0, 1.0)
  final parameter n_wheel::Real[3] = [0, 0, dir]
relations
  # Road excitation: a flat road whose height oscillates in time. The road is
  # flat (height independent of x,z), so the contact normal stays vertical (R = I);
  # x,z are left free so the contact patch tracks the wheel.
  wheel.surface_frame.r_0[2] = amplitude * sin(2 * π * freq * time)
  wheel.surface_frame.R = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
  connect(wheel.frame_a, wheel_rotation.frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 490, "y": 860}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rotational_losses.spline_a, wheel_rotation.axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 440, "y": 910}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rotational_losses.spline_b, wheel_rotation.support) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 250, "y": 910}, {"x": 250, "y": 820}, {"x": 405, "y": 820}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  if elastic_mount
    connect(mount.frame_a, chassis_frame)
    connect(mount.frame_b, suspension.chassis_frame)
  else
    connect(suspension.chassis_frame, chassis_frame)
  end
  connect(wheel_rotation.frame_a, suspension.wheel_frame) {
    "Dyad": {
      "renderStyle": "standard",
      "edges": [{"S": 1, "M": [{"x": 380, "y": 780}], "E": 2}]
    }
  }
metadata {
  "Dyad": {"icons": {"default": "dyad://MultibodyComponents/ExcitedWheelAssembly.svg"}}
}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses