Skip to content
LIBRARY
PlanarMechanics.CutTorqueTest.md

PlanarMechanics.CutTorqueTest

Test for CutTorque sensor: a damped pendulum with a CutTorque sensor, a WorldForce applying sinusoidal forces and torque to the body.

Topology: Fixed → CutTorque → FixedTranslation1(r=[0.5,0]) → Revolute → FixedTranslation(r=[1,0]) → Body ← WorldForce A rotational damper stabilizes the revolute joint via its flange.

Translated from PlanarMechanicsTest.Sensors.CutTorques.

Usage

MultibodyComponents.PlanarMechanics.CutTorqueTest()

Behavior

[connect(fixedframe+frame_b,cuttorque+frame_a)connect(cuttorque+frame_b,rod1+framea)connect(rod1+frameb,revolute+framea)connect(revolute+frameb,rod+framea)connect(rod+frameb,body+framea)connect(worldforce+frame_b,body+framea)connect(sinefx+y,worldforce+force_x)connect(sinefy+y,worldforce+force_y)connect(sinetau+y,worldforce+torque)connect(damper+splineb,revolute+flangea)connect(rotfixed+spline,damper+splinea)world.frameb.x(t)=0world.frameb.y(t)=0world.frameb.phi(t)=0connect(frameb,framevis+frame_a)world.framevis.phi(t)=world.framevis.frame_a.phi(t)world.framevis.x_shape.r(t)=arrayliteral([3],world.framevis.frame_a.x(t),world.framevis.frame_a.y(t),world.framevis.z_position)world.framevis.x_shape.R(t)=arrayliteral([33],cos(world.framevis.phi(t)),sin(world.framevis.phi(t)),0,sin(world.framevis.phi(t)),cos(world.framevis.phi(t)),0,0,0,1)world.framevis.x_shape.r_shape(t)=[000]world.framevis.x_shape.length_direction(t)=[100]world.framevis.x_shape.width_direction(t)=[001]world.framevis.x_shape.length(t)=world.framevis.axis_lengthworld.framevis.x_shape.width(t)=2world.framevis.axis_radiusworld.framevis.x_shape.height(t)=2world.framevis.axis_radiusworld.framevis.y_shape.r(t)=arrayliteral([3],world.framevis.frame_a.x(t),world.framevis.frame_a.y(t),world.framevis.z_position)world.framevis.y_shape.R(t)=arrayliteral([33],cos(world.framevis.phi(t)),sin(world.framevis.phi(t)),0,sin(world.framevis.phi(t)),cos(world.framevis.phi(t)),0,0,0,1)world.framevis.y_shape.r_shape(t)=[000]world.framevis.y_shape.length_direction(t)=[010]world.framevis.y_shape.width_direction(t)=[001]world.framevis.y_shape.length(t)=world.framevis.axis_lengthworld.framevis.y_shape.width(t)=2world.framevis.axis_radiusworld.framevis.y_shape.height(t)=2world.framevis.axis_radiusworld.framevis.z_shape.r(t)=arrayliteral([3],world.framevis.frame_a.x(t),world.framevis.frame_a.y(t),world.framevis.z_position)world.framevis.z_shape.R(t)=arrayliteral([33],cos(world.framevis.phi(t)),sin(world.framevis.phi(t)),0,sin(world.framevis.phi(t)),cos(world.framevis.phi(t)),0,0,0,1)world.framevis.z_shape.r_shape(t)=[000]world.framevis.z_shape.length_direction(t)=[001]world.framevis.z_shape.width_direction(t)=[100]world.framevis.z_shape.length(t)=world.framevis.axis_lengthworld.framevis.z_shape.width(t)=2world.framevis.axis_radiusworld.framevis.z_shape.height(t)=2world.framevis.axis_radiusarrayliteral([2],fixedframe.frame_b.x(t),fixedframe.frame_b.y(t))=fixedframe.rfixedframe.frame_b.phi(t)=fixedframe.phicuttorque.frame_a.x(t)=cuttorque.frame_b.x(t)cuttorque.frame_a.y(t)=cuttorque.frame_b.y(t)cuttorque.frame_a.phi(t)=cuttorque.frame_b.phi(t)cuttorque.frame_b.fx(t)+cuttorque.frame_a.fx(t)=0cuttorque.frame_b.fy(t)+cuttorque.frame_a.fy(t)=0cuttorque.frame_a.tau(t)+cuttorque.frame_b.tau(t)=0cuttorque.tau_signed(t)=ifelse(cuttorque.positive_sign,cuttorque.frame_a.tau(t),cuttorque.frame_a.tau(t))cuttorque.torque_out(t)=cuttorque.tau_signed(t)cuttorque.torque_arrow.r(t)=arrayliteral([3],cuttorque.frame_b.x(t),cuttorque.frame_b.y(t),cuttorque.z_position)cuttorque.torque_arrow.R(t)=arrayliteral([33],1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)cuttorque.torque_arrow.r_shape(t)=[000]cuttorque.torque_arrow.length_direction(t)=[001]cuttorque.torque_arrow.width_direction(t)=[100]cuttorque.torque_arrow.length(t)=cuttorque.scalecuttorque.tau_signed(t)cuttorque.torque_arrow.width(t)=cuttorque.arrow_diametercuttorque.torque_arrow.height(t)=cuttorque.arrow_diameterrod1.phi(t)=rod1.framea.phi(t)rod1.w(t)=drod1.phi(t)dtrod1.r0(t)=arrayliteral([22],cos(rod1.phi(t)),sin(rod1.phi(t)),sin(rod1.phi(t)),cos(rod1.phi(t)))rod1.rrod1.r0(t)=arrayliteral([2],rod1.framea.x(t)+rod1.frameb.x(t),rod1.frameb.y(t)rod1.framea.y(t))rod1.framea.phi(t)=rod1.frameb.phi(t)rod1.frameb.fx(t)+rod1.framea.fx(t)=0rod1.framea.fy(t)+rod1.frameb.fy(t)=0rod1.frameb.tau(t)+rod1.framea.tau(t)+rod1.r01(t)rod1.frameb.fy(t)rod1.r02(t)rod1.frameb.fx(t)=0rod1.shape.r(t)=arrayliteral([3],rod1.framea.x(t),rod1.framea.y(t),rod1.zposition)rod1.shape.R(t)=arrayliteral([33],1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)rod1.shape.rshape(t)=[000]rod1.shape.lengthdirection(t)=arrayliteral([3],rod1.r01(t)rod1.l,rod1.r02(t)rod1.l,0)rod1.shape.widthdirection(t)=[001]rod1.shape.length(t)=rod1.lrod1.shape.width(t)=2rod1.radiusrod1.shape.height(t)=2rod1.radiusrevolute.w(t)=drevolute.phi(t)dtrevolute.alpha(t)=drevolute.w(t)dtrevolute.framea.x(t)=revolute.frameb.x(t)revolute.framea.y(t)=revolute.frameb.y(t)revolute.framea.phi(t)+revolute.phi(t)=revolute.frameb.phi(t)revolute.frameb.fx(t)+revolute.framea.fx(t)=0revolute.framea.fy(t)+revolute.frameb.fy(t)=0revolute.frameb.tau(t)+revolute.framea.tau(t)=0revolute.framea.tau(t)=revolute.tau(t)revolute.flangea.phi(t)=revolute.phi(t)revolute.flangea.tau(t)=revolute.tau(t)revolute.shape.r(t)=arrayliteral([3],revolute.framea.x(t),revolute.framea.y(t),revolute.zposition)revolute.shape.R(t)=arrayliteral([33],cos(revolute.framea.phi(t)),sin(revolute.framea.phi(t)),0,sin(revolute.framea.phi(t)),cos(revolute.framea.phi(t)),0,0,0,1)revolute.shape.rshape(t)=arrayliteral([3],0,0,12revolute.cylinderlength)revolute.shape.lengthdirection(t)=[001]revolute.shape.widthdirection(t)=[100]revolute.shape.length(t)=revolute.cylinderlengthrevolute.shape.width(t)=2revolute.radiusrevolute.shape.height(t)=2revolute.radiusrod.phi(t)=rod.framea.phi(t)rod.w(t)=drod.phi(t)dtrod.r0(t)=arrayliteral([22],cos(rod.phi(t)),sin(rod.phi(t)),sin(rod.phi(t)),cos(rod.phi(t)))rod.rrod.r0(t)=arrayliteral([2],rod.framea.x(t)+rod.frameb.x(t),rod.frameb.y(t)rod.framea.y(t))rod.framea.phi(t)=rod.frameb.phi(t)rod.framea.fx(t)+rod.frameb.fx(t)=0rod.frameb.fy(t)+rod.framea.fy(t)=0rod.framea.tau(t)+rod.frameb.tau(t)+rod.r01(t)rod.frameb.fy(t)rod.r02(t)rod.frameb.fx(t)=0rod.shape.r(t)=arrayliteral([3],rod.framea.x(t),rod.framea.y(t),rod.zposition)rod.shape.R(t)=arrayliteral([33],1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)rod.shape.rshape(t)=[000]rod.shape.lengthdirection(t)=arrayliteral([3],rod.r01(t)rod.l,rod.r02(t)rod.l,0)rod.shape.widthdirection(t)=[001]rod.shape.length(t)=rod.lrod.shape.width(t)=2rod.radiusrod.shape.height(t)=2rod.radiusbody.r(t)=arrayliteral([2],body.framea.x(t),body.framea.y(t))body.v(t)=dbody.r(t)dtbody.phi(t)=body.framea.phi(t)body.w(t)=dbody.phi(t)dtbody.a(t)=dbody.v(t)dtbody.alpha(t)=dbody.w(t)dtbody.f(t)=arrayliteral([2],body.framea.fx(t),body.framea.fy(t))body.f(t)+arrayliteral([2],body.mgn2d1,body.mgn2d2)=body.mbody.a(t)body.Ibody.alpha(t)=body.framea.tau(t)body.shape.r(t)=arrayliteral([3],body.framea.x(t),body.framea.y(t),body.zposition)body.shape.R(t)=arrayliteral([33],cos(body.phi(t)),sin(body.phi(t)),0,sin(body.phi(t)),cos(body.phi(t)),0,0,0,1)body.shape.rshape(t)=[000]body.shape.lengthdirection(t)=[001]body.shape.widthdirection(t)=[100]body.shape.length(t)=2body.radiusbody.shape.width(t)=2body.radiusbody.shape.height(t)=2body.radiusdamper.phirel(t)=damper.splinea.phi(t)+damper.splineb.phi(t)damper.splineb.tau(t)=damper.tau(t)damper.splinea.tau(t)=damper.tau(t)ddamper.phirel(t)dt=damper.wrel(t)ddamper.wrel(t)dt=damper.arel(t)damper.tau(t)=damper.ddamper.wrel(t)rotfixed.spline.phi(t)=rotfixed.phi0worldforce.frame_b.fx(t)worldforce.force_y(t)sin(worldforce.phi(t))+worldforce.force_x(t)cos(worldforce.phi(t))=0worldforce.frame_b.fy(t)+worldforce.force_y(t)cos(worldforce.phi(t))+worldforce.force_x(t)sin(worldforce.phi(t))=0worldforce.frame_b.tau(t)+worldforce.torque(t)=0worldforce.force_arrow.r(t)=arrayliteral([3],worldforce.frame_b.x(t),worldforce.frame_b.y(t),worldforce.z_position)worldforce.force_arrow.R(t)=arrayliteral([33],cos(worldforce.phi(t)),sin(worldforce.phi(t)),0,sin(worldforce.phi(t)),cos(worldforce.phi(t)),0,0,0,1)worldforce.force_arrow.r_shape(t)=[000]worldforce.force_arrow.length_direction(t)=arrayliteral([3],worldforce.force_x(t),worldforce.force_y(t),0)worldforce.force_arrow.width_direction(t)=[001]worldforce.force_arrow.length(t)=worldforce.scale(worldforce.force_y(t))2+(worldforce.force_x(t))2worldforce.force_arrow.width(t)=worldforce.arrow_diameterworldforce.force_arrow.height(t)=worldforce.arrow_diameterworldforce.phi(t)=worldforce.frame_b.phi(t)sinefx.y(t)=sinefx.offset+sinefx.amplitudeifelse(tsinefx.start_time,sin(sinefx.phase+6.283185307179586sinefx.frequency(sinefx.start_time+t)),sin(sinefx.phase))sinefy.y(t)=sinefy.offset+sinefy.amplitudeifelse(tsinefy.start_time,sin(sinefy.phase+6.283185307179586sinefy.frequency(sinefy.start_time+t)),sin(sinefy.phase))sinetau.y(t)=sinetau.offset+sinetau.amplitudeifelse(tsinetau.start_time,sin(sinetau.phase+6.283185307179586sinetau.frequency(sinetau.start_time+t)),sin(sinetau.phase))]

Source

dyad
"""
Test for CutTorque sensor: a damped pendulum with a CutTorque sensor, a WorldForce
applying sinusoidal forces and torque to the body.

Topology: Fixed → CutTorque → FixedTranslation1(r=[0.5,0]) → Revolute → FixedTranslation(r=[1,0]) → Body ← WorldForce
A rotational damper stabilizes the revolute joint via its flange.

Translated from PlanarMechanicsTest.Sensors.CutTorques.
"""
test component CutTorqueTest
  world = World() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
      },
      "tags": []
    }
  }
  fixed_frame = MultibodyComponents.PlanarMechanics.Fixed() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 40, "y1": 380, "x2": 140, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  cut_torque = CutTorque(scale = 3) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 155, "y1": 380, "x2": 255, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  rod1 = FixedTranslation(r = [0.5, 0]) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 280, "y1": 380, "x2": 380, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  revolute = Revolute() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 380, "x2": 510, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  rod = FixedTranslation(r = [1, 0]) {
    "Dyad": {
      "placement": {
        "diagram": {
          "iconName": "default",
          "x1": 542.5,
          "y1": 380,
          "x2": 642.5,
          "y2": 480,
          "rot": 0
        }
      },
      "tags": []
    }
  }
  body = Body(m = 1, I = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 670, "y1": 140, "x2": 770, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  damper = RotationalComponents.Components.Damper(d = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 560, "x2": 510, "y2": 660, "rot": 270}
      },
      "tags": []
    }
  }
  rot_fixed = RotationalComponents.Components.Fixed() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 720, "x2": 510, "y2": 820, "rot": 0}
      },
      "tags": []
    }
  }
  "WorldForce applying sinusoidal force and torque to body"
  world_force = WorldForceTorque(resolve_in_frame = MultibodyComponents.ResolveInFrame.FrameB()) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 540, "y1": 140, "x2": 640, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  "Sine signals: force in y direction and torque"
  sine_fx = BlockComponents.Sources.Sine(amplitude = 0, frequency = 1, start_time = 1.8) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 405, "y1": 20, "x2": 505, "y2": 120, "rot": 0}
      },
      "tags": []
    }
  }
  sine_fy = BlockComponents.Sources.Sine(amplitude = -5, frequency = 1, start_time = 1.8) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 405, "y1": 140, "x2": 505, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  sine_tau = BlockComponents.Sources.Sine(amplitude = 1, frequency = 1, start_time = 1.8) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 405, "y1": 260, "x2": 505, "y2": 360, "rot": 0}
      },
      "tags": []
    }
  }
relations
  initial revolute.phi = 0
  initial revolute.w = 0
  # Main chain: Fixed → CutTorque → Rod1 → Revolute → Rod → Body
  connect(fixed_frame.frame_b, cut_torque.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(cut_torque.frame_b, rod1.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod1.frame_b, revolute.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(revolute.frame_b, rod.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod.frame_b, body.frame_a) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 660, "y": 430}], "E": -1}, {"S": -1, "M": [], "E": 2}],
      "junctions": [{"x": 660, "y": 190}],
      "renderStyle": "standard"
    }
  }
  # WorldForce on body
  connect(world_force.frame_b, body.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(sine_fx.y, world_force.force_x) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 525, "y": 70}, {"x": 525, "y": 155}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(sine_fy.y, world_force.force_y) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(sine_tau.y, world_force.torque) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 525, "y": 310}, {"x": 525, "y": 223}], "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(rot_fixed.spline, damper.spline_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
metadata {"Dyad": {"tests": {"case1": {"stop": 3}}}}
end
Flattened Source
dyad
"""
Test for CutTorque sensor: a damped pendulum with a CutTorque sensor, a WorldForce
applying sinusoidal forces and torque to the body.

Topology: Fixed → CutTorque → FixedTranslation1(r=[0.5,0]) → Revolute → FixedTranslation(r=[1,0]) → Body ← WorldForce
A rotational damper stabilizes the revolute joint via its flange.

Translated from PlanarMechanicsTest.Sensors.CutTorques.
"""
test component CutTorqueTest
  world = World() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
      },
      "tags": []
    }
  }
  fixed_frame = MultibodyComponents.PlanarMechanics.Fixed() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 40, "y1": 380, "x2": 140, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  cut_torque = CutTorque(scale = 3) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 155, "y1": 380, "x2": 255, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  rod1 = FixedTranslation(r = [0.5, 0]) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 280, "y1": 380, "x2": 380, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  revolute = Revolute() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 380, "x2": 510, "y2": 480, "rot": 0}
      },
      "tags": []
    }
  }
  rod = FixedTranslation(r = [1, 0]) {
    "Dyad": {
      "placement": {
        "diagram": {
          "iconName": "default",
          "x1": 542.5,
          "y1": 380,
          "x2": 642.5,
          "y2": 480,
          "rot": 0
        }
      },
      "tags": []
    }
  }
  body = Body(m = 1, I = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 670, "y1": 140, "x2": 770, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  damper = RotationalComponents.Components.Damper(d = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 560, "x2": 510, "y2": 660, "rot": 270}
      },
      "tags": []
    }
  }
  rot_fixed = RotationalComponents.Components.Fixed() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 410, "y1": 720, "x2": 510, "y2": 820, "rot": 0}
      },
      "tags": []
    }
  }
  "WorldForce applying sinusoidal force and torque to body"
  world_force = WorldForceTorque(resolve_in_frame = MultibodyComponents.ResolveInFrame.FrameB()) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 540, "y1": 140, "x2": 640, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  "Sine signals: force in y direction and torque"
  sine_fx = BlockComponents.Sources.Sine(amplitude = 0, frequency = 1, start_time = 1.8) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 405, "y1": 20, "x2": 505, "y2": 120, "rot": 0}
      },
      "tags": []
    }
  }
  sine_fy = BlockComponents.Sources.Sine(amplitude = -5, frequency = 1, start_time = 1.8) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 405, "y1": 140, "x2": 505, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  sine_tau = BlockComponents.Sources.Sine(amplitude = 1, frequency = 1, start_time = 1.8) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 405, "y1": 260, "x2": 505, "y2": 360, "rot": 0}
      },
      "tags": []
    }
  }
relations
  initial revolute.phi = 0
  initial revolute.w = 0
  # Main chain: Fixed → CutTorque → Rod1 → Revolute → Rod → Body
  connect(fixed_frame.frame_b, cut_torque.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(cut_torque.frame_b, rod1.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod1.frame_b, revolute.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(revolute.frame_b, rod.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod.frame_b, body.frame_a) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 660, "y": 430}], "E": -1}, {"S": -1, "M": [], "E": 2}],
      "junctions": [{"x": 660, "y": 190}],
      "renderStyle": "standard"
    }
  }
  # WorldForce on body
  connect(world_force.frame_b, body.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(sine_fx.y, world_force.force_x) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 525, "y": 70}, {"x": 525, "y": 155}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(sine_fy.y, world_force.force_y) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(sine_tau.y, world_force.torque) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 525, "y": 310}, {"x": 525, "y": 223}], "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(rot_fixed.spline, damper.spline_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
metadata {"Dyad": {"tests": {"case1": {"stop": 3}}}}
end


Test Cases

Test Case case1