Skip to content
LIBRARY
JointSSR.md

JointSSR

Spherical - spherical - revolute joint aggregation. Analytically closes a kinematic loop (no constraints, no potential states): a SphericalSpherical rod of fixed length rod1_length (optionally carrying a point mass rod1_mass) between frame_a and the middle spherical joint, a rigid rod rRod2_ib, and a RevoluteWithLengthConstraint at frame_b. Interior frames frame_ib and frame_im (rod2 ends) are exposed. axis/bearing drive the revolute joint.

This component extends from PartialTwoFrames

Usage

MultibodyComponents.JointSSR(rod1_length=1, rod1_mass=0, n_b=[0, 0, 1], rRod2_ib=[1, 0, 0], phi_offset=0, phi_guess=0, rod_radius=0.05, rod_color=[0.5, 0, 0.5, 1])

Parameters:

NameDescriptionUnitsDefault value
positive_branchtrue
has_massfalse
rod1_lengthDistance between the origins of the two spherical joints (rod1 length)1
rod1_massMass of rod1 (point mass located in the middle of rod1)kg0
n_bAxis of the revolute joint, resolved in frame_b[0, 0, 1]
rRod2_ibVector from frame_ib origin to the middle spherical joint, resolved in frame_ib[1, 0, 0]
phi_offsetRelative angle offset of the revolute joint0
phi_guessGuess value for the revolute angle at the initial time0
rod_radiusRendering radius of the rods0.05
rod_colorRGBA color of the rods[0.5, 0, 0.5, 1]

Connectors

  • frame_a - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

  • frame_b - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

  • frame_ib - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

  • frame_im - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several Frame

connectors that can be connected together (Frame3D)

  • axis - This connector represents a rotational spline with angle and torque as the potential and flow variables, respectively. (Spline)

  • bearing - This connector represents a rotational spline with angle and torque as the potential and flow variables, respectively. (Spline)

Variables

NameDescriptionUnits
auxDenominator used to compute the rod force
f_rodConstraint force in the direction of rod1 (positive if the rod is pressed)

Behavior

Source

dyad
"""
Spherical - spherical - revolute joint aggregation. Analytically closes a
kinematic loop (no constraints, no potential states): a `SphericalSpherical` rod
of fixed length `rod1_length` (optionally carrying a point mass `rod1_mass`)
between `frame_a` and the middle spherical joint, a rigid rod `rRod2_ib`, and a
`RevoluteWithLengthConstraint` at `frame_b`. Interior frames `frame_ib` and
`frame_im` (rod2 ends) are exposed. `axis`/`bearing` drive the revolute joint.
"""
component JointSSR
  extends PartialTwoFrames()
  "Frame fixed in rod2 at the revolute side (= rod2.frame_a)"
  frame_ib = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 600, "y1": 450, "x2": 700, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the middle spherical joint (= rod2.frame_b)"
  frame_im = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 320, "y1": 450, "x2": 420, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange driving the revolute joint"
  axis = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 580, "y1": 950, "x2": 680, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange of the revolute joint bearing"
  bearing = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 170, "y1": 940, "x2": 270, "y2": 1040, "rot": 0}
      },
      "tags": []
    }
  }
  rod1 = SphericalSpherical(r_0 = [rod1_length, 0, 0], kinematic_constraint = false, constraint_residue_external = true, has_mass = has_mass, m = rod1_mass, radius = rod_radius, color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 160, "y1": 450, "x2": 260, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  rod2 = FixedTranslation(r = rRod2_ib, radius = rod_radius, color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 530, "y1": 450, "x2": 430, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  revolute = RevoluteWithLengthConstraint(n = n_b, length_constraint = rod1_length, phi_offset = phi_offset, phi_guess = phi_guess, positive_branch = positive_branch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 630, "y1": 720, "x2": 530, "y2": 820, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter positive_branch::Boolean = true
  structural parameter has_mass::Boolean = false
  "Distance between the origins of the two spherical joints (rod1 length)"
  parameter rod1_length::Real = 1
  "Mass of rod1 (point mass located in the middle of rod1)"
  parameter rod1_mass::Mass = 0 if has_mass
  "Axis of the revolute joint, resolved in frame_b"
  parameter n_b::Real[3] = [0, 0, 1]
  "Vector from frame_ib origin to the middle spherical joint, resolved in frame_ib"
  parameter rRod2_ib::Real[3] = [1, 0, 0]
  "Relative angle offset of the revolute joint"
  parameter phi_offset::Real = 0
  "Guess value for the revolute angle at the initial time"
  parameter phi_guess::Real = 0
  "Rendering radius of the rods"
  parameter rod_radius::Real = 0.05
  "RGBA color of the rods"
  parameter rod_color::Real[4] = [0.5, 0, 0.5, 1]
  "Denominator used to compute the rod force"
  variable aux::Real
  "Constraint force in the direction of rod1 (positive if the rod is pressed)"
  variable f_rod::Real
relations
  aux = dot(cross(revolute.e, rRod2_ib), resolve_relative(rod1.eRod_a, rod1.frame_a.R, rod1.frame_b.R))
  f_rod = (-revolute.tau - dot(revolute.e, frame_ib.tau + frame_im.tau + cross(rRod2_ib, frame_im.f) - cross(rRod2_ib, resolve_relative(rod1.f_b_a1, rod1.frame_a.R, rod1.frame_b.R)))) / ifelse(abs(aux) < 1e-10, 1e-10, aux)
  rod1.constraint_residue = rod1.f_rod - f_rod
  revolute.r_a = resolve2(frame_b.R, frame_a.r_0 - frame_b.r_0)
  revolute.r_b = rRod2_ib
  connect(revolute.frame_b, rod2.frame_a, frame_ib) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [], "E": -1},
        {"S": -1, "M": [], "E": 2},
        {"S": 3, "M": [], "E": -1}
      ],
      "junctions": [{"x": 530, "y": 500}],
      "renderStyle": "standard"
    }
  }
  connect(revolute.frame_a, frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 835, "y": 770}, {"x": 835, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod1.frame_a, frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod1.frame_b, frame_im) {"Dyad": {"renderStyle": "standard", "edges": [{"S": 1, "E": 2, "M": []}]}}
  connect(frame_im, rod2.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(revolute.axis, axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 560, "y": 960}, {"x": 630, "y": 960}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(revolute.bearing, bearing) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 602, "y": 910}, {"x": 220, "y": 910}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/JointSSR.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 200,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
Spherical - spherical - revolute joint aggregation. Analytically closes a
kinematic loop (no constraints, no potential states): a `SphericalSpherical` rod
of fixed length `rod1_length` (optionally carrying a point mass `rod1_mass`)
between `frame_a` and the middle spherical joint, a rigid rod `rRod2_ib`, and a
`RevoluteWithLengthConstraint` at `frame_b`. Interior frames `frame_ib` and
`frame_im` (rod2 ends) are exposed. `axis`/`bearing` drive the revolute joint.
"""
component JointSSR
  frame_a = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  frame_b = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 950, "y1": 450, "x2": 1050, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the revolute side (= rod2.frame_a)"
  frame_ib = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 600, "y1": 450, "x2": 700, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the middle spherical joint (= rod2.frame_b)"
  frame_im = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 320, "y1": 450, "x2": 420, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange driving the revolute joint"
  axis = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 580, "y1": 950, "x2": 680, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange of the revolute joint bearing"
  bearing = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 170, "y1": 940, "x2": 270, "y2": 1040, "rot": 0}
      },
      "tags": []
    }
  }
  rod1 = SphericalSpherical(r_0 = [rod1_length, 0, 0], kinematic_constraint = false, constraint_residue_external = true, has_mass = has_mass, m = rod1_mass, radius = rod_radius, color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 160, "y1": 450, "x2": 260, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  rod2 = FixedTranslation(r = rRod2_ib, radius = rod_radius, color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 530, "y1": 450, "x2": 430, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  revolute = RevoluteWithLengthConstraint(n = n_b, length_constraint = rod1_length, phi_offset = phi_offset, phi_guess = phi_guess, positive_branch = positive_branch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 630, "y1": 720, "x2": 530, "y2": 820, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter positive_branch::Boolean = true
  structural parameter has_mass::Boolean = false
  "Distance between the origins of the two spherical joints (rod1 length)"
  parameter rod1_length::Real = 1
  "Mass of rod1 (point mass located in the middle of rod1)"
  parameter rod1_mass::Mass = 0 if has_mass
  "Axis of the revolute joint, resolved in frame_b"
  parameter n_b::Real[3] = [0, 0, 1]
  "Vector from frame_ib origin to the middle spherical joint, resolved in frame_ib"
  parameter rRod2_ib::Real[3] = [1, 0, 0]
  "Relative angle offset of the revolute joint"
  parameter phi_offset::Real = 0
  "Guess value for the revolute angle at the initial time"
  parameter phi_guess::Real = 0
  "Rendering radius of the rods"
  parameter rod_radius::Real = 0.05
  "RGBA color of the rods"
  parameter rod_color::Real[4] = [0.5, 0, 0.5, 1]
  "Denominator used to compute the rod force"
  variable aux::Real
  "Constraint force in the direction of rod1 (positive if the rod is pressed)"
  variable f_rod::Real
relations
  aux = dot(cross(revolute.e, rRod2_ib), resolve_relative(rod1.eRod_a, rod1.frame_a.R, rod1.frame_b.R))
  f_rod = (-revolute.tau - dot(revolute.e, frame_ib.tau + frame_im.tau + cross(rRod2_ib, frame_im.f) - cross(rRod2_ib, resolve_relative(rod1.f_b_a1, rod1.frame_a.R, rod1.frame_b.R)))) / ifelse(abs(aux) < 1e-10, 1e-10, aux)
  rod1.constraint_residue = rod1.f_rod - f_rod
  revolute.r_a = resolve2(frame_b.R, frame_a.r_0 - frame_b.r_0)
  revolute.r_b = rRod2_ib
  connect(revolute.frame_b, rod2.frame_a, frame_ib) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [], "E": -1},
        {"S": -1, "M": [], "E": 2},
        {"S": 3, "M": [], "E": -1}
      ],
      "junctions": [{"x": 530, "y": 500}],
      "renderStyle": "standard"
    }
  }
  connect(revolute.frame_a, frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 835, "y": 770}, {"x": 835, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod1.frame_a, frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod1.frame_b, frame_im) {"Dyad": {"renderStyle": "standard", "edges": [{"S": 1, "E": 2, "M": []}]}}
  connect(frame_im, rod2.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(revolute.axis, axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 560, "y": 960}, {"x": 630, "y": 960}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(revolute.bearing, bearing) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 602, "y": 910}, {"x": 220, "y": 910}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/JointSSR.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 200,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses