examples.suspension.QuarterCarSuspension
Double-wishbone quarter-car suspension linkage.
A planar four-bar linkage built from a JointRRR (three parallel-axis revolute joints, r123), a fourth Revolute (r2) and two FixedTranslation rods (b1, chassis). An optional spring-damper acts between the lower link and the chassis. The chassis attachment is exposed via chassis_frame, and the point where a wheel / excitation rod attaches is exposed via wheel_frame (= r123.frame_ib).
Set mirror = true for the opposite (left) side of the car.
Usage
MultibodyComponents.examples.suspension.QuarterCarSuspension(cs=4000, ks=44000, rod_radius=0.02, jr=0.03, jc=[0.5, 0.5, 0.5, 0.7], n=[1, 0, 0], dir=ifelse(mirror, -1.0, 1.0), ndir=n * dir, AB=146.5 / 1000, BC=233.84 / 1000, CD=228.60 / 1000, DA=221.43 / 1000, t5=19.84 * π / 180, d_rod1=[0, -0.1, 0.2 * dir], d_rod2=[0, 0.2, 0], d_b1=[0, -0.1, 0.3 * dir], d_chassis=[0, 0.2, 0.2 * sin(t5) * dir], rRod1_ia=AB * d_rod1 / MultibodyComponents.norm_(d_rod1), rRod2_ib=BC * d_rod2 / MultibodyComponents.norm_(d_rod2), r_b1=CD * d_b1 / MultibodyComponents.norm_(d_b1), r_chassis=DA * d_chassis / MultibodyComponents.norm_(d_chassis), r_mount_F=0.7 * r_b1, r_mount_E=1.3 * r_chassis)
Parameters:
| Name | Description | Units | Default value |
|---|---|---|---|
positive_branch | Assembly branch (elbow up/down) of the analytic JointRRR loop closure | – | true |
spring | – | true | |
mirror | – | false | |
n_nonzero | Structural sparsity mask for the revolute axis (set consistently with n; threaded to r2 and the JointRRR so axis*axis' has literal zeros). | – | [true, false, false] |
cs | Damping constant [Ns/m] | – | 4000 |
ks | Spring constant [N/m] | – | 44000 |
rod_radius | Radius of the rods | – | 0.02 |
jr | Radius of the revolute joints | – | 0.03 |
jc | RGBA color of the joints / rods | – | [0.5, 0.5, 0.5, 0.7] |
n | – | [1, 0, 0] | |
AB | – | 146.5 / 1000 | |
BC | – | 233.84 / 1000 | |
CD | – | 228.60 / 1000 | |
DA | – | 221.43 / 1000 | |
t5 | – | 19.84 * π / 180 |
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)
wheel_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
"""
Double-wishbone quarter-car suspension linkage.
A planar four-bar linkage built from a `JointRRR` (three parallel-axis revolute
joints, `r123`), a fourth `Revolute` (`r2`) and two `FixedTranslation` rods
(`b1`, `chassis`). An optional spring-damper acts between the lower link and the
chassis. The chassis attachment is exposed via `chassis_frame`, and the point
where a wheel / excitation rod attaches is exposed via `wheel_frame`
(= `r123.frame_ib`).
Set `mirror = true` for the opposite (left) side of the car.
"""
component QuarterCarSuspension
"Frame rigidly attached to the chassis (= chassis link frame_a)"
chassis_frame = Frame3D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": -50, "x2": 550, "y2": 50, "rot": 0}
},
"tags": []
}
}
"Frame where the wheel / excitation rod attaches (= r123.frame_ib)"
wheel_frame = Frame3D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 950, "x2": 550, "y2": 1050, "rot": 0}
},
"tags": []
}
}
r123 = MultibodyComponents.JointRRR(n_a = ndir, n_b = ndir, n_b_nonzero = n_nonzero, rRod1_ia = rRod1_ia, rRod2_ib = rRod2_ib, positive_branch = positive_branch, rod_radius = 0.018, rod_color = jc) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 330, "x2": 550, "y2": 430, "rot": 90}
},
"tags": []
}
}
# High state priority: the four-bar's single DOF must be represented by this
# joint's coordinate (phi, w). If state selection instead picks rotation-matrix
# derivative chains, the torn velocity-level block is numerically singular at
# axis-aligned joint parameters (StateSelection.jl#98 diagnosis).
r2 = MultibodyComponents.Revolute(n = ndir, n_nonzero = n_nonzero, radius = jr, color = jc, statePriority = 100) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 190, "y1": 380, "x2": 290, "y2": 480, "rot": 0}
},
"tags": []
}
}
b1 = MultibodyComponents.FixedTranslation(r = r_b1, radius = rod_radius) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 320, "y1": 380, "x2": 420, "y2": 480, "rot": 0}
},
"tags": []
}
}
chassis = MultibodyComponents.FixedTranslation(r = r_chassis, render = false) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 140, "x2": 550, "y2": 240, "rot": 90}
},
"tags": []
}
}
springdamper = MultibodyComponents.SpringDamperParallel(c = ks, d = cs, s_unstretched = 1.3 * BC, radius = rod_radius, num_windings = 10) if spring {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 265, "y1": 20, "x2": 365, "y2": 120, "rot": 0}
},
"tags": []
}
}
spring_mount_F = MultibodyComponents.FixedTranslation(r = r_mount_F, render = false) if spring {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
},
"tags": []
}
}
spring_mount_E = MultibodyComponents.FixedTranslation(r = r_mount_E) if spring {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 140, "y1": 20, "x2": 240, "y2": 120, "rot": 0}
},
"tags": []
}
}
"Assembly branch (elbow up/down) of the analytic JointRRR loop closure"
structural parameter positive_branch::Boolean = true
structural parameter spring::Boolean = true
structural parameter mirror::Boolean = false
"Damping constant [Ns/m]"
parameter cs::Real = 4000
"Spring constant [N/m]"
parameter ks::Real = 44000
"Radius of the rods"
parameter rod_radius::Real = 0.02
"Radius of the revolute joints"
parameter jr::Real = 0.03
"RGBA color of the joints / rods"
parameter jc::Real[4] = [0.5, 0.5, 0.5, 0.7]
parameter n::Real[3] = [1, 0, 0]
"Structural sparsity mask for the revolute axis (set consistently with `n`; threaded to r2 and the JointRRR so axis*axis' has literal zeros)."
structural parameter n_nonzero::Boolean[3] = [true, false, false]
final parameter dir::Real = ifelse(mirror, -1.0, 1.0)
final parameter ndir::Real[3] = n * dir
parameter AB::Real = 146.5 / 1000
parameter BC::Real = 233.84 / 1000
parameter CD::Real = 228.60 / 1000
parameter DA::Real = 221.43 / 1000
parameter t5::Real = 19.84 * π / 180
final parameter d_rod1::Real[3] = [0, -0.1, 0.2 * dir]
final parameter d_rod2::Real[3] = [0, 0.2, 0]
final parameter d_b1::Real[3] = [0, -0.1, 0.3 * dir]
final parameter d_chassis::Real[3] = [0, 0.2, 0.2 * sin(t5) * dir]
final parameter rRod1_ia::Real[3] = AB * d_rod1 / MultibodyComponents.norm_(d_rod1)
final parameter rRod2_ib::Real[3] = BC * d_rod2 / MultibodyComponents.norm_(d_rod2)
final parameter r_b1::Length[3] = CD * d_b1 / MultibodyComponents.norm_(d_b1)
final parameter r_chassis::Length[3] = DA * d_chassis / MultibodyComponents.norm_(d_chassis)
final parameter r_mount_F::Length[3] = 0.7 * r_b1
final parameter r_mount_E::Length[3] = 1.3 * r_chassis
relations
# Main loop: chassis.frame_b -> r123 -> b1 -> r2 -> chassis.frame_a
connect(chassis.frame_b, r123.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(r123.frame_b, b1.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(b1.frame_a, r2.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
if spring
connect(springdamper.frame_b, spring_mount_E.frame_b)
connect(b1.frame_a, spring_mount_F.frame_a)
connect(chassis.frame_a, spring_mount_E.frame_a)
connect(springdamper.frame_a, spring_mount_F.frame_b)
end
connect(chassis_frame, chassis.frame_a, r2.frame_a) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [], "E": 2},
{"S": 3, "M": [{"x": 130, "y": 430}, {"x": 130, "y": 120}], "E": -1}
],
"junctions": [{"x": 500, "y": 120}],
"renderStyle": "standard"
}
}
connect(wheel_frame, r123.frame_ib) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [{"x": 500, "y": 960}, {"x": 600, "y": 960}, {"x": 600, "y": 398}],
"E": 2
}
],
"renderStyle": "standard"
}
}
metadata {
"Dyad": {"icons": {"default": "dyad://MultibodyComponents/QuarterCarSuspension.svg"}}
}
endFlattened Source
"""
Double-wishbone quarter-car suspension linkage.
A planar four-bar linkage built from a `JointRRR` (three parallel-axis revolute
joints, `r123`), a fourth `Revolute` (`r2`) and two `FixedTranslation` rods
(`b1`, `chassis`). An optional spring-damper acts between the lower link and the
chassis. The chassis attachment is exposed via `chassis_frame`, and the point
where a wheel / excitation rod attaches is exposed via `wheel_frame`
(= `r123.frame_ib`).
Set `mirror = true` for the opposite (left) side of the car.
"""
component QuarterCarSuspension
"Frame rigidly attached to the chassis (= chassis link frame_a)"
chassis_frame = Frame3D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": -50, "x2": 550, "y2": 50, "rot": 0}
},
"tags": []
}
}
"Frame where the wheel / excitation rod attaches (= r123.frame_ib)"
wheel_frame = Frame3D() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 950, "x2": 550, "y2": 1050, "rot": 0}
},
"tags": []
}
}
r123 = MultibodyComponents.JointRRR(n_a = ndir, n_b = ndir, n_b_nonzero = n_nonzero, rRod1_ia = rRod1_ia, rRod2_ib = rRod2_ib, positive_branch = positive_branch, rod_radius = 0.018, rod_color = jc) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 330, "x2": 550, "y2": 430, "rot": 90}
},
"tags": []
}
}
# High state priority: the four-bar's single DOF must be represented by this
# joint's coordinate (phi, w). If state selection instead picks rotation-matrix
# derivative chains, the torn velocity-level block is numerically singular at
# axis-aligned joint parameters (StateSelection.jl#98 diagnosis).
r2 = MultibodyComponents.Revolute(n = ndir, n_nonzero = n_nonzero, radius = jr, color = jc, statePriority = 100) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 190, "y1": 380, "x2": 290, "y2": 480, "rot": 0}
},
"tags": []
}
}
b1 = MultibodyComponents.FixedTranslation(r = r_b1, radius = rod_radius) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 320, "y1": 380, "x2": 420, "y2": 480, "rot": 0}
},
"tags": []
}
}
chassis = MultibodyComponents.FixedTranslation(r = r_chassis, render = false) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 140, "x2": 550, "y2": 240, "rot": 90}
},
"tags": []
}
}
springdamper = MultibodyComponents.SpringDamperParallel(c = ks, d = cs, s_unstretched = 1.3 * BC, radius = rod_radius, num_windings = 10) if spring {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 265, "y1": 20, "x2": 365, "y2": 120, "rot": 0}
},
"tags": []
}
}
spring_mount_F = MultibodyComponents.FixedTranslation(r = r_mount_F, render = false) if spring {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
},
"tags": []
}
}
spring_mount_E = MultibodyComponents.FixedTranslation(r = r_mount_E) if spring {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 140, "y1": 20, "x2": 240, "y2": 120, "rot": 0}
},
"tags": []
}
}
"Assembly branch (elbow up/down) of the analytic JointRRR loop closure"
structural parameter positive_branch::Boolean = true
structural parameter spring::Boolean = true
structural parameter mirror::Boolean = false
"Damping constant [Ns/m]"
parameter cs::Real = 4000
"Spring constant [N/m]"
parameter ks::Real = 44000
"Radius of the rods"
parameter rod_radius::Real = 0.02
"Radius of the revolute joints"
parameter jr::Real = 0.03
"RGBA color of the joints / rods"
parameter jc::Real[4] = [0.5, 0.5, 0.5, 0.7]
parameter n::Real[3] = [1, 0, 0]
"Structural sparsity mask for the revolute axis (set consistently with `n`; threaded to r2 and the JointRRR so axis*axis' has literal zeros)."
structural parameter n_nonzero::Boolean[3] = [true, false, false]
final parameter dir::Real = ifelse(mirror, -1.0, 1.0)
final parameter ndir::Real[3] = n * dir
parameter AB::Real = 146.5 / 1000
parameter BC::Real = 233.84 / 1000
parameter CD::Real = 228.60 / 1000
parameter DA::Real = 221.43 / 1000
parameter t5::Real = 19.84 * π / 180
final parameter d_rod1::Real[3] = [0, -0.1, 0.2 * dir]
final parameter d_rod2::Real[3] = [0, 0.2, 0]
final parameter d_b1::Real[3] = [0, -0.1, 0.3 * dir]
final parameter d_chassis::Real[3] = [0, 0.2, 0.2 * sin(t5) * dir]
final parameter rRod1_ia::Real[3] = AB * d_rod1 / MultibodyComponents.norm_(d_rod1)
final parameter rRod2_ib::Real[3] = BC * d_rod2 / MultibodyComponents.norm_(d_rod2)
final parameter r_b1::Length[3] = CD * d_b1 / MultibodyComponents.norm_(d_b1)
final parameter r_chassis::Length[3] = DA * d_chassis / MultibodyComponents.norm_(d_chassis)
final parameter r_mount_F::Length[3] = 0.7 * r_b1
final parameter r_mount_E::Length[3] = 1.3 * r_chassis
relations
# Main loop: chassis.frame_b -> r123 -> b1 -> r2 -> chassis.frame_a
connect(chassis.frame_b, r123.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(r123.frame_b, b1.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(b1.frame_a, r2.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
if spring
connect(springdamper.frame_b, spring_mount_E.frame_b)
connect(b1.frame_a, spring_mount_F.frame_a)
connect(chassis.frame_a, spring_mount_E.frame_a)
connect(springdamper.frame_a, spring_mount_F.frame_b)
end
connect(chassis_frame, chassis.frame_a, r2.frame_a) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [], "E": 2},
{"S": 3, "M": [{"x": 130, "y": 430}, {"x": 130, "y": 120}], "E": -1}
],
"junctions": [{"x": 500, "y": 120}],
"renderStyle": "standard"
}
}
connect(wheel_frame, r123.frame_ib) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [{"x": 500, "y": 960}, {"x": 600, "y": 960}, {"x": 600, "y": 398}],
"E": 2
}
],
"renderStyle": "standard"
}
}
metadata {
"Dyad": {"icons": {"default": "dyad://MultibodyComponents/QuarterCarSuspension.svg"}}
}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses