Skip to content
LIBRARY
JointRRR.md

JointRRR

Joint assembly of three revolute joints with parallel axes (hence RRR), connected by two rigid rods. It is built on top of JointUSR (the universal joint there acts as the first two parallel-axis revolutes), so the non-linear loop closure is solved analytically.

The assembly has no mass and no inertia and introduces neither constraints nor potential states. Use it to close planar kinematic loops: it is far more efficient than the equivalent loop built from basic joints plus a cut joint.

Two configurations satisfy the constraints; positive_branch selects which one (elbow up/down), and phi_guess seeds the revolute angle.

This component extends from PartialTwoFrames

Usage

MultibodyComponents.JointRRR(n_a=[0, 0, 1], n_b=[0, 0, 1], rRod1_ia=[1, 0, 0], 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
n_b_nonzeroStructural sparsity mask for the frame_b revolute axis (threaded to the analytic revolute via JointUSR).[true, true, true]
n_aAxis of the revolute joints, resolved in frame_a[0, 0, 1]
n_bAxis of the revolute joint at frame_b, resolved in frame_b[0, 0, 1]
rRod1_iaVector from frame_a origin to the middle revolute joint, resolved in frame_ia[1, 0, 0]
rRod2_ibVector from frame_ib origin to the middle revolute 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_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 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)

Behavior

Source

dyad
"""
Joint assembly of three revolute joints with parallel axes (hence RRR),
connected by two rigid rods. It is built on top of `JointUSR` (the universal
joint there acts as the first two parallel-axis revolutes), so the non-linear
loop closure is solved analytically.

The assembly has no mass and no inertia and introduces neither constraints nor
potential states. Use it to close planar kinematic loops: it is far more
efficient than the equivalent loop built from basic joints plus a cut joint.

Two configurations satisfy the constraints; `positive_branch` selects which one
(elbow up/down), and `phi_guess` seeds the revolute angle.
"""
component JointRRR
  extends PartialTwoFrames()
  "Frame fixed in rod1 at the origin of frame_a"
  frame_ia = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 290, "y1": 450, "x2": 390, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the first-rod side of the middle revolute joint"
  frame_ib = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 630, "y1": 450, "x2": 730, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the middle revolute joint"
  frame_im = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 450, "x2": 550, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange driving the revolute joint at frame_b"
  axis = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 690, "y1": 950, "x2": 790, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange of the revolute joint bearing"
  bearing = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 210, "y1": 950, "x2": 310, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  jointUSR = JointUSR(n1_a = n_a, n_b = n_b, n_b_nonzero = n_b_nonzero, rRod1_ia = rRod1_ia, rRod2_ib = rRod2_ib, phi_offset = phi_offset, phi_guess = phi_guess, positive_branch = positive_branch, rod_radius = rod_radius, rod_color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 610, "x2": 550, "y2": 710, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter positive_branch::Boolean = true
  "Axis of the revolute joints, resolved in frame_a"
  parameter n_a::Real[3] = [0, 0, 1]
  "Axis of the revolute joint at frame_b, resolved in frame_b"
  parameter n_b::Real[3] = [0, 0, 1]
  "Structural sparsity mask for the frame_b revolute axis (threaded to the analytic revolute via JointUSR)."
  structural parameter n_b_nonzero::Boolean[3] = [true, true, true]
  "Vector from frame_a origin to the middle revolute joint, resolved in frame_ia"
  parameter rRod1_ia::Real[3] = [1, 0, 0]
  "Vector from frame_ib origin to the middle revolute 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]
relations
  connect(jointUSR.frame_a, frame_a) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 225, "y": 660}, {"x": 225, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.frame_b, frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 775, "y": 660}, {"x": 775, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.frame_ia, frame_ia) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 475, "y": 610}, {"x": 380, "y": 610}, {"x": 380, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.frame_im, frame_im) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(jointUSR.frame_ib, frame_ib) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 522, "y": 610}, {"x": 640, "y": 610}, {"x": 640, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.axis, axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 523, "y": 890}, {"x": 740, "y": 890}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.bearing, bearing) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 476, "y": 890}, {"x": 260, "y": 890}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/JointRRR.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 200,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
Joint assembly of three revolute joints with parallel axes (hence RRR),
connected by two rigid rods. It is built on top of `JointUSR` (the universal
joint there acts as the first two parallel-axis revolutes), so the non-linear
loop closure is solved analytically.

The assembly has no mass and no inertia and introduces neither constraints nor
potential states. Use it to close planar kinematic loops: it is far more
efficient than the equivalent loop built from basic joints plus a cut joint.

Two configurations satisfy the constraints; `positive_branch` selects which one
(elbow up/down), and `phi_guess` seeds the revolute angle.
"""
component JointRRR
  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": 290, "y1": 450, "x2": 390, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the first-rod side of the middle revolute joint"
  frame_ib = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 630, "y1": 450, "x2": 730, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Frame fixed in rod2 at the middle revolute joint"
  frame_im = Frame3D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 450, "x2": 550, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange driving the revolute joint at frame_b"
  axis = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 690, "y1": 950, "x2": 790, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  "Rotational flange of the revolute joint bearing"
  bearing = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 210, "y1": 950, "x2": 310, "y2": 1050, "rot": 0}
      },
      "tags": []
    }
  }
  jointUSR = JointUSR(n1_a = n_a, n_b = n_b, n_b_nonzero = n_b_nonzero, rRod1_ia = rRod1_ia, rRod2_ib = rRod2_ib, phi_offset = phi_offset, phi_guess = phi_guess, positive_branch = positive_branch, rod_radius = rod_radius, rod_color = rod_color) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 610, "x2": 550, "y2": 710, "rot": 0}
      },
      "tags": []
    }
  }
  structural parameter positive_branch::Boolean = true
  "Axis of the revolute joints, resolved in frame_a"
  parameter n_a::Real[3] = [0, 0, 1]
  "Axis of the revolute joint at frame_b, resolved in frame_b"
  parameter n_b::Real[3] = [0, 0, 1]
  "Structural sparsity mask for the frame_b revolute axis (threaded to the analytic revolute via JointUSR)."
  structural parameter n_b_nonzero::Boolean[3] = [true, true, true]
  "Vector from frame_a origin to the middle revolute joint, resolved in frame_ia"
  parameter rRod1_ia::Real[3] = [1, 0, 0]
  "Vector from frame_ib origin to the middle revolute 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]
relations
  connect(jointUSR.frame_a, frame_a) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 225, "y": 660}, {"x": 225, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.frame_b, frame_b) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 775, "y": 660}, {"x": 775, "y": 500}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.frame_ia, frame_ia) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 475, "y": 610}, {"x": 380, "y": 610}, {"x": 380, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.frame_im, frame_im) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(jointUSR.frame_ib, frame_ib) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 522, "y": 610}, {"x": 640, "y": 610}, {"x": 640, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.axis, axis) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 523, "y": 890}, {"x": 740, "y": 890}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(jointUSR.bearing, bearing) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 476, "y": 890}, {"x": 260, "y": 890}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/JointRRR.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 200,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses