Skip to content
LIBRARY
JointUSP.md

JointUSP

Universal - spherical - prismatic joint aggregation. Analytically closes a spatial kinematic loop with no constraints and no potential state variables: a UniversalSpherical rod between frame_a and the spherical joint, a rigid rod rRod2_ib, and a PrismaticWithLengthConstraint at frame_b. The rod force is distributed analytically (f_rod) so that the loop is solved without a non-linear system. Interior frames frame_ia (rod1 at frame_a), frame_ibandframe_im(rod2 ends) are exposed for attaching bodies or loads.axis/bearing drive the prismatic joint.

This component extends from PartialTwoFrames

Usage

MultibodyComponents.JointUSP(n1_a=[0, 0, 1], n_b=[-1, 0, 0], rRod1_ia=[1, 0, 0], rRod2_ib=[-1, 0, 0], s_offset=0, s_guess=0, rod_radius=0.05, rod_color=[0.5, 0, 0.5, 1], rod1_length=norm_(rRod1_ia))

Parameters:

NameDescriptionUnitsDefault value
positive_branchtrue
n1_aAxis 1 of the universal joint, resolved in frame_a[0, 0, 1]
n_bAxis of the prismatic joint, resolved in frame_b[-1, 0, 0]
rRod1_iaVector from frame_a origin to the spherical joint, resolved in frame_ia[1, 0, 0]
rRod2_ibVector from frame_ib origin to the spherical joint, resolved in frame_ib[-1, 0, 0]
s_offsetRelative distance offset of the prismatic joint0
s_guessGuess value for the prismatic distance 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_ia - 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 mechanical flange with position and force as the potential and flow variables, respectively. (Flange)

  • bearing - This connector represents a mechanical flange with position and force as the potential and flow variables, respectively. (Flange)

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
"""
Universal - spherical - prismatic joint aggregation. Analytically closes a
spatial kinematic loop with no constraints and no potential state variables: a
`UniversalSpherical` rod between `frame_a` and the spherical joint, a rigid rod
`rRod2_ib`, and a `PrismaticWithLengthConstraint` at `frame_b`. The rod force is
distributed analytically (`f_rod`) so that the loop is solved without a non-linear
system. Interior frames `frame_ia` (rod1 at frame_a), `frame_ib` and `frame_im`
(rod2 ends) are exposed for attaching bodies or loads. `axis`/`bearing` drive the
prismatic joint.
"""
component JointUSP
  extends PartialTwoFrames()
  "Frame fixed in rod1 at the origin of frame_a"
  frame_ia = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 240, "y1": 450, "x2": 340, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the prismatic side (= rod2.frame_a)"
  frame_ib = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 650, "y1": 450, "x2": 750, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the spherical side (= rod2.frame_b)"
  frame_im = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 450, "x2": 550, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Translational flange driving the prismatic joint"
  axis = Flange() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 630, "y1": 950, "x2": 730, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  "Translational flange of the prismatic joint bearing"
  bearing = Flange() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 280, "y1": 960, "x2": 380, "y2": 1060, "rot": 0}
      },
      "tags": []
    }
  }
  rod1 = UniversalSpherical(n1_a = n1_a, rRod_ia = rRod1_ia, kinematic_constraint = false, constraint_residue_external = true, rod_radius = rod_radius, color = rod_color, sphere_color = [0, 0, 0, 0]) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 165, "y1": 580, "x2": 265, "y2": 680, "rot": 0}
      },
      "tags": []
    }
  }
  rod2 = FixedTranslation(r = rRod2_ib, radius = rod_radius, color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 400, "y1": 620, "x2": 500, "y2": 720, "rot": 270}
      },
      "tags": []
    }
  }
  prismatic = PrismaticWithLengthConstraint(n = n_b, length_constraint = rod1_length, s_offset = s_offset, s_guess = s_guess, positive_branch = positive_branch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 550, "y1": 730, "x2": 450, "y2": 830, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter positive_branch::Boolean = true
  "Axis 1 of the universal joint, resolved in frame_a"
  parameter n1_a::Real[3] = [0, 0, 1]
  "Axis of the prismatic joint, resolved in frame_b"
  parameter n_b::Real[3] = [-1, 0, 0]
  "Vector from frame_a origin to the spherical joint, resolved in frame_ia"
  parameter rRod1_ia::Real[3] = [1, 0, 0]
  "Vector from frame_ib origin to the spherical joint, resolved in frame_ib"
  parameter rRod2_ib::Real[3] = [-1, 0, 0]
  "Relative distance offset of the prismatic joint"
  parameter s_offset::Real = 0
  "Guess value for the prismatic distance at the initial time"
  parameter s_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]
  final parameter rod1_length::Real = norm_(rRod1_ia)
  "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(prismatic.e, resolve_relative(rod1.eRod_a, rod1.frame_a.R, rod1.frame_b.R))
  # The guard against division by zero must preserve the sign of aux (MSL:
  # `noEvent(if abs(aux) < 1e-10 then 1e-10 else aux)`).
  f_rod = (-prismatic.f - dot(prismatic.e, frame_ib.f + frame_im.f - 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
  prismatic.r_a = resolve2(frame_b.R, frame_a.r_0 - frame_b.r_0)
  prismatic.r_b = rRod2_ib
  connect(prismatic.frame_b, rod2.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod2.frame_b, rod1.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(prismatic.frame_a, frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 960, "y": 780}, {"x": 960, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod2.frame_a, frame_ib) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 660, "y": 710}, {"x": 660, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod1.frame_a, frame_a) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 40, "y": 630}, {"x": 40, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod1.frame_ia, frame_ia) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 210, "y": 540}, {"x": 290, "y": 540}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod2.frame_b, frame_im) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 450, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(prismatic.axis, axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 690, "y": 830}, {"x": 690, "y": 1000}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(prismatic.bearing, bearing) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 330, "y": 830}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/JointUSP.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 200,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
Universal - spherical - prismatic joint aggregation. Analytically closes a
spatial kinematic loop with no constraints and no potential state variables: a
`UniversalSpherical` rod between `frame_a` and the spherical joint, a rigid rod
`rRod2_ib`, and a `PrismaticWithLengthConstraint` at `frame_b`. The rod force is
distributed analytically (`f_rod`) so that the loop is solved without a non-linear
system. Interior frames `frame_ia` (rod1 at frame_a), `frame_ib` and `frame_im`
(rod2 ends) are exposed for attaching bodies or loads. `axis`/`bearing` drive the
prismatic joint.
"""
component JointUSP
  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 rod1 at the origin of frame_a"
  frame_ia = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 240, "y1": 450, "x2": 340, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the prismatic side (= rod2.frame_a)"
  frame_ib = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 650, "y1": 450, "x2": 750, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the spherical side (= rod2.frame_b)"
  frame_im = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 450, "x2": 550, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Translational flange driving the prismatic joint"
  axis = Flange() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 630, "y1": 950, "x2": 730, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  "Translational flange of the prismatic joint bearing"
  bearing = Flange() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 280, "y1": 960, "x2": 380, "y2": 1060, "rot": 0}
      },
      "tags": []
    }
  }
  rod1 = UniversalSpherical(n1_a = n1_a, rRod_ia = rRod1_ia, kinematic_constraint = false, constraint_residue_external = true, rod_radius = rod_radius, color = rod_color, sphere_color = [0, 0, 0, 0]) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 165, "y1": 580, "x2": 265, "y2": 680, "rot": 0}
      },
      "tags": []
    }
  }
  rod2 = FixedTranslation(r = rRod2_ib, radius = rod_radius, color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 400, "y1": 620, "x2": 500, "y2": 720, "rot": 270}
      },
      "tags": []
    }
  }
  prismatic = PrismaticWithLengthConstraint(n = n_b, length_constraint = rod1_length, s_offset = s_offset, s_guess = s_guess, positive_branch = positive_branch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 550, "y1": 730, "x2": 450, "y2": 830, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter positive_branch::Boolean = true
  "Axis 1 of the universal joint, resolved in frame_a"
  parameter n1_a::Real[3] = [0, 0, 1]
  "Axis of the prismatic joint, resolved in frame_b"
  parameter n_b::Real[3] = [-1, 0, 0]
  "Vector from frame_a origin to the spherical joint, resolved in frame_ia"
  parameter rRod1_ia::Real[3] = [1, 0, 0]
  "Vector from frame_ib origin to the spherical joint, resolved in frame_ib"
  parameter rRod2_ib::Real[3] = [-1, 0, 0]
  "Relative distance offset of the prismatic joint"
  parameter s_offset::Real = 0
  "Guess value for the prismatic distance at the initial time"
  parameter s_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]
  final parameter rod1_length::Real = norm_(rRod1_ia)
  "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(prismatic.e, resolve_relative(rod1.eRod_a, rod1.frame_a.R, rod1.frame_b.R))
  # The guard against division by zero must preserve the sign of aux (MSL:
  # `noEvent(if abs(aux) < 1e-10 then 1e-10 else aux)`).
  f_rod = (-prismatic.f - dot(prismatic.e, frame_ib.f + frame_im.f - 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
  prismatic.r_a = resolve2(frame_b.R, frame_a.r_0 - frame_b.r_0)
  prismatic.r_b = rRod2_ib
  connect(prismatic.frame_b, rod2.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rod2.frame_b, rod1.frame_b) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(prismatic.frame_a, frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 960, "y": 780}, {"x": 960, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod2.frame_a, frame_ib) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 660, "y": 710}, {"x": 660, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod1.frame_a, frame_a) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 40, "y": 630}, {"x": 40, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod1.frame_ia, frame_ia) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 210, "y": 540}, {"x": 290, "y": 540}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(rod2.frame_b, frame_im) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 450, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(prismatic.axis, axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 690, "y": 830}, {"x": 690, "y": 1000}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(prismatic.bearing, bearing) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 330, "y": 830}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/JointUSP.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 200,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses