LIBRARY
PlanarMechanics.CutForceTest
Test for CutForce sensor: a damped pendulum with three CutForce sensors measuring reaction forces at different points in the chain, each resolved in a different frame.
Topology: World → CutForce(frame_a) → Revolute → CutForce(world) → FixedTranslation → CutForce(frame_b) → Body A rotational damper stabilizes the revolute joint via its flange.
Translated from PlanarMechanicsTest.Sensors.CutForces (line 633).
Usage
MultibodyComponents.PlanarMechanics.CutForceTest()
Behavior
julia
using MultibodyComponents #hide
using ModelingToolkit #hide
@named sys = MultibodyComponents.PlanarMechanics.CutForceTest() #hide
full_equations(sys) #hide<< @example-block not executed in draft mode >>Source
dyad
"""
Test for CutForce sensor: a damped pendulum with three CutForce sensors
measuring reaction forces at different points in the chain, each resolved
in a different frame.
Topology: World → CutForce(frame_a) → Revolute → CutForce(world) → FixedTranslation → CutForce(frame_b) → Body
A rotational damper stabilizes the revolute joint via its flange.
Translated from PlanarMechanicsTest.Sensors.CutForces (line 633).
"""
test component CutForceTest
world = World() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
},
"tags": []
}
}
revolute = Revolute() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 280, "y1": 20, "x2": 380, "y2": 120, "rot": 0}
},
"tags": []
}
}
rod = FixedTranslation(r = [1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 521, "y1": 20, "x2": 621, "y2": 120, "rot": 0}
},
"tags": []
}
}
body = Body(m = 1, I = 0.1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 767, "y1": 20, "x2": 867, "y2": 120, "rot": 0}
},
"tags": []
}
}
damper = RotationalComponents.Components.Damper(d = 0.1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 280, "y1": 190, "x2": 380, "y2": 290, "rot": 270}
},
"tags": []
}
}
fixed = RotationalComponents.Components.Fixed() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 280, "y1": 340, "x2": 380, "y2": 440, "rot": 0}
},
"tags": []
}
}
"CutForce resolved in frame_a (between world and revolute)"
cut_force_frame_a = CutForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.FrameA()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 150, "y1": 20, "x2": 250, "y2": 120, "rot": 0}
},
"tags": []
}
}
"CutForce resolved in world frame (between revolute and rod)"
cut_force_world = CutForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 395, "y1": 20, "x2": 495, "y2": 120, "rot": 0}
},
"tags": []
}
}
"CutForce resolved in frame_b (between rod and body)"
cut_force_frame_b = CutForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.FrameB()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 641, "y1": 20, "x2": 741, "y2": 120, "rot": 0}
},
"tags": []
}
}
relations
initial revolute.phi = 0
initial revolute.w = 0
# Main chain: World → CutForce(A) → Revolute → CutForce(W) → Rod → CutForce(B) → Body
connect(world.frame_b, cut_force_frame_a.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force_frame_a.frame_b, revolute.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(revolute.frame_b, cut_force_world.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force_world.frame_b, rod.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(rod.frame_b, cut_force_frame_b.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force_frame_b.frame_b, body.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
# Rotational damper on revolute flange
connect(damper.spline_b, revolute.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(damper.spline_a, fixed.spline) {"Dyad": {"renderStyle": "standard", "edges": [{"S": 1, "E": 2, "M": []}]}}
metadata {"Dyad": {"tests": {"case1": {"stop": 3}}}}
endFlattened Source
dyad
"""
Test for CutForce sensor: a damped pendulum with three CutForce sensors
measuring reaction forces at different points in the chain, each resolved
in a different frame.
Topology: World → CutForce(frame_a) → Revolute → CutForce(world) → FixedTranslation → CutForce(frame_b) → Body
A rotational damper stabilizes the revolute joint via its flange.
Translated from PlanarMechanicsTest.Sensors.CutForces (line 633).
"""
test component CutForceTest
world = World() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
},
"tags": []
}
}
revolute = Revolute() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 280, "y1": 20, "x2": 380, "y2": 120, "rot": 0}
},
"tags": []
}
}
rod = FixedTranslation(r = [1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 521, "y1": 20, "x2": 621, "y2": 120, "rot": 0}
},
"tags": []
}
}
body = Body(m = 1, I = 0.1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 767, "y1": 20, "x2": 867, "y2": 120, "rot": 0}
},
"tags": []
}
}
damper = RotationalComponents.Components.Damper(d = 0.1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 280, "y1": 190, "x2": 380, "y2": 290, "rot": 270}
},
"tags": []
}
}
fixed = RotationalComponents.Components.Fixed() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 280, "y1": 340, "x2": 380, "y2": 440, "rot": 0}
},
"tags": []
}
}
"CutForce resolved in frame_a (between world and revolute)"
cut_force_frame_a = CutForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.FrameA()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 150, "y1": 20, "x2": 250, "y2": 120, "rot": 0}
},
"tags": []
}
}
"CutForce resolved in world frame (between revolute and rod)"
cut_force_world = CutForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 395, "y1": 20, "x2": 495, "y2": 120, "rot": 0}
},
"tags": []
}
}
"CutForce resolved in frame_b (between rod and body)"
cut_force_frame_b = CutForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.FrameB()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 641, "y1": 20, "x2": 741, "y2": 120, "rot": 0}
},
"tags": []
}
}
relations
initial revolute.phi = 0
initial revolute.w = 0
# Main chain: World → CutForce(A) → Revolute → CutForce(W) → Rod → CutForce(B) → Body
connect(world.frame_b, cut_force_frame_a.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force_frame_a.frame_b, revolute.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(revolute.frame_b, cut_force_world.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force_world.frame_b, rod.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(rod.frame_b, cut_force_frame_b.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force_frame_b.frame_b, body.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
# Rotational damper on revolute flange
connect(damper.spline_b, revolute.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(damper.spline_a, fixed.spline) {"Dyad": {"renderStyle": "standard", "edges": [{"S": 1, "E": 2, "M": []}]}}
metadata {"Dyad": {"tests": {"case1": {"stop": 3}}}}
endTest Cases
julia
using MultibodyComponents
using DyadInterface: TransientAnalysis, rebuild_sol, ODEAlg
using ModelingToolkit: toggle_namespacing, get_initial_conditions, @named
using CSV, DataFrames, Plots
snapshotsdir = joinpath(dirname(dirname(pathof(MultibodyComponents))), "test", "snapshots")<< @setup-block not executed in draft mode >>Test Case case1
julia
@named model_case1 = MultibodyComponents.PlanarMechanics.CutForceTest()
model_case1 = toggle_namespacing(model_case1, false)
model_case1 = toggle_namespacing(model_case1, true)
result_case1 = TransientAnalysis(; model = model_case1, alg = ODEAlg.Auto(), start = 0e+0, stop = 3e+0, abstol=1e-6, reltol=1e-6)
sol_case1 = rebuild_sol(result_case1)<< @setup-block not executed in draft mode >>