LIBRARY
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:
| Name | Description | Units | Default value |
|---|---|---|---|
positive_branch | Assembly branch (elbow up/down) of the suspension's analytic loop closure | – | true |
spring | – | true | |
mirror | – | false | |
iscut | 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. | – | true |
angular_state | 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. | – | true |
elastic_contact | Use 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_mount | 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. | – | false |
rod_radius | Radius of the rods | – | 0.02 |
amplitude | Amplitude of the road-height excitation [m] | – | 0.02 |
freq | Frequency of the road-height excitation [Hz] | Hz | 2 |
Connectors
chassis_frame- Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or severalFrame
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"}}
}
endFlattened 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"}}
}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses