LIBRARY
tests.Sensors3DTest
3D Sensors Test
A pendulum that exercises all six 3D multibody sensors. A revolute joint about the world z-axis connects the world to a rigid bar carrying a body. Released from rest in the horizontal position, the pendulum swings under gravity.
The inline CutForce, CutTorque and Power sensors sit in the load path between the bar and the body, while AbsoluteAngles, RelativeAngles and RelativePosition read the body pose without exerting forces. Because the rotation is purely about z, the absolute and relative angle sequences reduce to [0, 0, phi], and the relative position traces the bar tip at unit radius.
Usage
MultibodyComponents.tests.Sensors3DTest()
Behavior
Source
dyad
"""
# 3D Sensors Test
A pendulum that exercises all six 3D multibody sensors. A revolute joint about
the world z-axis connects the world to a rigid bar carrying a body. Released
from rest in the horizontal position, the pendulum swings under gravity.
The inline `CutForce`, `CutTorque` and `Power` sensors sit in the load path
between the bar and the body, while `AbsoluteAngles`, `RelativeAngles` and
`RelativePosition` read the body pose without exerting forces. Because the
rotation is purely about z, the absolute and relative angle sequences reduce to
`[0, 0, phi]`, and the relative position traces the bar tip at unit radius.
"""
example component Sensors3DTest
world = MultibodyComponents.World() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 10, "y1": 190, "x2": 110, "y2": 290, "rot": 0}
},
"tags": []
}
}
revolute = MultibodyComponents.Revolute(n = [0, 0, 1], phi(initial = 0), w(initial = 0)) {
"Dyad": {
"placement": {
"diagram": {
"iconName": "default",
"x1": 150.5,
"y1": 443,
"x2": 250.5,
"y2": 543,
"rot": 0
}
},
"tags": []
}
}
bar = MultibodyComponents.FixedTranslation(r = [1, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 276, "y1": 443, "x2": 376, "y2": 543, "rot": 0}
},
"tags": []
}
}
cut_force = MultibodyComponents.CutForce(resolve_in_frame = ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 401, "y1": 443, "x2": 501, "y2": 543, "rot": 0}
},
"tags": []
}
}
cut_torque = MultibodyComponents.CutTorque(resolve_in_frame = ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 531, "y1": 443, "x2": 631, "y2": 543, "rot": 0}
},
"tags": []
}
}
power = MultibodyComponents.Power() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 661, "y1": 443, "x2": 761, "y2": 543, "rot": 0}
},
"tags": []
}
}
body = MultibodyComponents.Body(m = 1, r_cm = [0, 0, 0], I_11 = 0.1, I_22 = 0.1, I_33 = 0.1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 276, "y1": 190, "x2": 376, "y2": 290, "rot": 0}
},
"tags": []
}
}
abs_angles = MultibodyComponents.AbsoluteAngles() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 310, "y1": 10, "x2": 410, "y2": 110, "rot": 0}
},
"tags": []
}
}
rel_angles = MultibodyComponents.RelativeAngles() {
"Dyad": {
"placement": {
"diagram": {
"iconName": "default",
"x1": 150.5,
"y1": 190,
"x2": 250.5,
"y2": 290,
"rot": 0
}
},
"tags": []
}
}
rel_pos = MultibodyComponents.RelativePosition(resolve_in_frame = ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {
"iconName": "default",
"x1": 150.5,
"y1": 317,
"x2": 250.5,
"y2": 417,
"rot": 0
}
},
"tags": []
}
}
relations
# Load path: world -> revolute -> bar -> cut_force -> cut_torque -> power -> body
connect(world.frame_b, revolute.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [], "E": -1}, {"S": -1, "M": [{"x": 135, "y": 493}], "E": 2}],
"junctions": [{"x": 135, "y": 240}],
"renderStyle": "standard"
}
}
connect(revolute.frame_b, bar.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(bar.frame_b, cut_force.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force.frame_b, cut_torque.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_torque.frame_b, power.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(power.frame_b, body.frame_a) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 776, "y": 493}, {"x": 776, "y": 140}], "E": -1},
{"S": -1, "M": [{"x": 266, "y": 240}], "E": 2}
],
"junctions": [{"x": 266, "y": 140}],
"renderStyle": "standard"
}
}
# Read-only sensors on the body
connect(body.frame_a, abs_angles.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [], "E": -1}, {"S": -1, "M": [{"x": 266, "y": 60}], "E": 2}],
"junctions": [{"x": 266, "y": 240}],
"renderStyle": "standard"
}
}
connect(world.frame_b, rel_angles.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(body.frame_a, rel_angles.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(world.frame_b, rel_pos.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 135, "y": 240}], "E": -1}, {"S": -1, "M": [], "E": 2}],
"junctions": [{"x": 135, "y": 367}],
"renderStyle": "standard"
}
}
connect(body.frame_a, rel_pos.frame_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 266, "y": 240}, {"x": 266, "y": 367}], "E": 2}],
"renderStyle": "standard"
}
}
metadata {"Dyad": {"tests": {"case1": {"stop": 2}}}}
endFlattened Source
dyad
"""
# 3D Sensors Test
A pendulum that exercises all six 3D multibody sensors. A revolute joint about
the world z-axis connects the world to a rigid bar carrying a body. Released
from rest in the horizontal position, the pendulum swings under gravity.
The inline `CutForce`, `CutTorque` and `Power` sensors sit in the load path
between the bar and the body, while `AbsoluteAngles`, `RelativeAngles` and
`RelativePosition` read the body pose without exerting forces. Because the
rotation is purely about z, the absolute and relative angle sequences reduce to
`[0, 0, phi]`, and the relative position traces the bar tip at unit radius.
"""
example component Sensors3DTest
world = MultibodyComponents.World() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 10, "y1": 190, "x2": 110, "y2": 290, "rot": 0}
},
"tags": []
}
}
revolute = MultibodyComponents.Revolute(n = [0, 0, 1], phi(initial = 0), w(initial = 0)) {
"Dyad": {
"placement": {
"diagram": {
"iconName": "default",
"x1": 150.5,
"y1": 443,
"x2": 250.5,
"y2": 543,
"rot": 0
}
},
"tags": []
}
}
bar = MultibodyComponents.FixedTranslation(r = [1, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 276, "y1": 443, "x2": 376, "y2": 543, "rot": 0}
},
"tags": []
}
}
cut_force = MultibodyComponents.CutForce(resolve_in_frame = ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 401, "y1": 443, "x2": 501, "y2": 543, "rot": 0}
},
"tags": []
}
}
cut_torque = MultibodyComponents.CutTorque(resolve_in_frame = ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 531, "y1": 443, "x2": 631, "y2": 543, "rot": 0}
},
"tags": []
}
}
power = MultibodyComponents.Power() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 661, "y1": 443, "x2": 761, "y2": 543, "rot": 0}
},
"tags": []
}
}
body = MultibodyComponents.Body(m = 1, r_cm = [0, 0, 0], I_11 = 0.1, I_22 = 0.1, I_33 = 0.1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 276, "y1": 190, "x2": 376, "y2": 290, "rot": 0}
},
"tags": []
}
}
abs_angles = MultibodyComponents.AbsoluteAngles() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 310, "y1": 10, "x2": 410, "y2": 110, "rot": 0}
},
"tags": []
}
}
rel_angles = MultibodyComponents.RelativeAngles() {
"Dyad": {
"placement": {
"diagram": {
"iconName": "default",
"x1": 150.5,
"y1": 190,
"x2": 250.5,
"y2": 290,
"rot": 0
}
},
"tags": []
}
}
rel_pos = MultibodyComponents.RelativePosition(resolve_in_frame = ResolveInFrame.World()) {
"Dyad": {
"placement": {
"diagram": {
"iconName": "default",
"x1": 150.5,
"y1": 317,
"x2": 250.5,
"y2": 417,
"rot": 0
}
},
"tags": []
}
}
relations
# Load path: world -> revolute -> bar -> cut_force -> cut_torque -> power -> body
connect(world.frame_b, revolute.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [], "E": -1}, {"S": -1, "M": [{"x": 135, "y": 493}], "E": 2}],
"junctions": [{"x": 135, "y": 240}],
"renderStyle": "standard"
}
}
connect(revolute.frame_b, bar.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(bar.frame_b, cut_force.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_force.frame_b, cut_torque.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(cut_torque.frame_b, power.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(power.frame_b, body.frame_a) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 776, "y": 493}, {"x": 776, "y": 140}], "E": -1},
{"S": -1, "M": [{"x": 266, "y": 240}], "E": 2}
],
"junctions": [{"x": 266, "y": 140}],
"renderStyle": "standard"
}
}
# Read-only sensors on the body
connect(body.frame_a, abs_angles.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [], "E": -1}, {"S": -1, "M": [{"x": 266, "y": 60}], "E": 2}],
"junctions": [{"x": 266, "y": 240}],
"renderStyle": "standard"
}
}
connect(world.frame_b, rel_angles.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(body.frame_a, rel_angles.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(world.frame_b, rel_pos.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 135, "y": 240}], "E": -1}, {"S": -1, "M": [], "E": 2}],
"junctions": [{"x": 135, "y": 367}],
"renderStyle": "standard"
}
}
connect(body.frame_a, rel_pos.frame_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 266, "y": 240}, {"x": 266, "y": 367}], "E": 2}],
"renderStyle": "standard"
}
}
metadata {"Dyad": {"tests": {"case1": {"stop": 2}}}}
endTest Cases
Test Case case1
Related
Examples
Experiments
Analyses