Skip to content
LIBRARY
Rotor1D.md

Rotor1D

Inertia with a 1D rotation axis that is embedded in a 3D mechanism.

J is the moment of inertia about the axis n (resolved in frame_a). flange_a/flange_b are the 1D drivetrain connections and frame_a is the bearing/carrier frame.

When drive_train_mechanics_3d = true the component adds the two effects a plain 1D inertia cannot represent:

  1. the gyroscopic reaction cross(w_a, nJ*w) that the spinning rotor exerts on its carrier, and

  2. the correction -e*dot(nJ, z_a), which returns the axial component of the carrier's angular acceleration to the carrier, because that axial torque is supplied through the flanges rather than through the frame.

Because of (2) this component models only the rotor's spin momentum. The rotor's mass and its full inertia tensor must still be present as an ordinary rigid body (e.g. a BodyCylinder) attached to the same frame; Rotor1D then adds the angular momentum J*e*w due to the relative spin. Using Rotor1D alone leaves the rotor massless in 3D.

exact = false drops the -dot(nJ, z_a) term from the rotor equation only (the carrier reaction is unchanged), neglecting the influence of the bearing on the rotor acceleration in order to break the resulting algebraic loop.

See Mounting1D for the meaning of drive_train_mechanics_3d.

This component extends from Renderable

Usage

MultibodyComponents.Rotor1D(render=true, color=world_default_rod_color(), specular_coefficient=1.5, J=1, n=[1, 0, 0], r_center=[0, 0, 0], cylinder_length=2 * world_default_joint_length(), cylinder_diameter=2 * world_default_joint_width(), e=normalize_(n), nJ=e * J)

Parameters:

NameDescriptionUnitsDefault value
drive_train_mechanics_3dExpose the carrier frame frame_a and apply the rotor's gyroscopic/axial reaction to it. Structural: when false, neither the connector nor any 3D term is emitted.true
exactInclude the influence of the carrier's angular acceleration on the rotor acceleration. Set false to neglect it and break the resulting algebraic loop.true
statePriorityState priority of the rotor's angle and speed10
rendertrue
colorworld_default_rod_color()
specular_coefficient1.5
JMoment of inertia of the rotor about its axiskg.m21
nAxis of rotation, resolved in frame_a[1, 0, 0]
r_centerPosition vector from frame_a to the rotor center, resolved in frame_am[0, 0, 0]
cylinder_lengthLength of the rotor cylinder in animations2 * world_d...nt_length()
cylinder_diameterDiameter of the rotor cylinder in animations2 * world_d...int_width()

Connectors

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

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

  • 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)

Variables

NameDescriptionUnits
phiRotation angle of the rotor relative to frame_arad
wAngular velocity of the rotor relative to frame_arad/s
aAngular acceleration of the rotor relative to frame_arad/s2
w_aAbsolute angular velocity of frame_a (the carrier), resolved in frame_arad/s
z_aAbsolute angular acceleration of frame_a (the carrier), resolved in frame_arad/s2

Behavior

Dict{MIME{Symbol("text/plain")}, String} with 1 entry: MIME type text/plain => "Error displaying result"

Source

dyad
"""
Inertia with a 1D rotation axis that is embedded in a 3D mechanism.

`J` is the moment of inertia about the axis `n` (resolved in `frame_a`).
`flange_a`/`flange_b` are the 1D drivetrain connections and `frame_a` is the
bearing/carrier frame.

When `drive_train_mechanics_3d = true` the component adds the two effects a plain
1D inertia cannot represent:

1. the gyroscopic reaction `cross(w_a, nJ*w)` that the spinning rotor exerts on
   its carrier, and
2. the correction `-e*dot(nJ, z_a)`, which returns the axial component of the
   carrier's angular acceleration to the carrier, because that axial torque is
   supplied through the *flanges* rather than through the frame.

Because of (2) this component models only the rotor's **spin momentum**. The
rotor's mass and its full inertia tensor must still be present as an ordinary
rigid body (e.g. a `BodyCylinder`) attached to the same frame; `Rotor1D` then adds
the angular momentum `J*e*w` due to the relative spin. Using `Rotor1D` alone
leaves the rotor massless in 3D.

`exact = false` drops the `-dot(nJ, z_a)` term from the rotor equation only (the
carrier reaction is unchanged), neglecting the influence of the bearing on the
rotor acceleration in order to break the resulting algebraic loop.

See `Mounting1D` for the meaning of `drive_train_mechanics_3d`.
"""
component Rotor1D
  extends Renderable(color = world_default_rod_color())
  flange_a = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 180}
      },
      "tags": []
    }
  }
  flange_b = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 950, "y1": 450, "x2": 1050, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  frame_a = Frame3D() if drive_train_mechanics_3d {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 950, "x2": 550, "y2": 1050, "rot": 90}
      },
      "tags": []
    }
  }
  shape = CylinderShape(render = render, color = color, r = frame_a.r_0, R = transpose(frame_a.R), r_shape = r_center - e * (cylinder_length / 2), length_direction = e, length = cylinder_length, width = cylinder_diameter, height = cylinder_diameter) if drive_train_mechanics_3d {}
  "Expose the carrier frame `frame_a` and apply the rotor's gyroscopic/axial reaction to it. Structural: when false, neither the connector nor any 3D term is emitted."
  structural parameter drive_train_mechanics_3d::Boolean = true
  "Include the influence of the carrier's angular acceleration on the rotor acceleration. Set false to neglect it and break the resulting algebraic loop."
  structural parameter exact::Boolean = true
  "State priority of the rotor's angle and speed"
  structural parameter statePriority::Integer = 10
  "Moment of inertia of the rotor about its axis"
  parameter J::Inertia = 1
  "Axis of rotation, resolved in frame_a"
  parameter n::Real[3] = [1, 0, 0]
  "Position vector from frame_a to the rotor center, resolved in frame_a"
  parameter r_center::Length[3] = [0, 0, 0]
  "Length of the rotor cylinder in animations"
  parameter cylinder_length::Real = 2 * world_default_joint_length()
  "Diameter of the rotor cylinder in animations"
  parameter cylinder_diameter::Real = 2 * world_default_joint_width()
  final parameter e::Real[3] = normalize_(n)
  final parameter nJ::Real[3] = e * J
  "Rotation angle of the rotor relative to frame_a"
  variable phi::Angle(statePriority = statePriority)
  "Angular velocity of the rotor relative to frame_a"
  variable w::AngularVelocity(statePriority = statePriority)
  "Angular acceleration of the rotor relative to frame_a"
  variable a::AngularAcceleration
  "Absolute angular velocity of frame_a (the carrier), resolved in frame_a"
  variable w_a::AngularVelocity[3] if drive_train_mechanics_3d
  "Absolute angular acceleration of frame_a (the carrier), resolved in frame_a"
  variable z_a::AngularAcceleration[3] if drive_train_mechanics_3d
relations
  phi = flange_a.phi
  phi = flange_b.phi
  w = der(phi)
  a = der(w)
  if drive_train_mechanics_3d
    # Frame3D carries no angular velocity, so w_a is reconstructed from D(R) and
    # z_a is a second derivative of R. Naming both (rather than inlining
    # der(angular_velocity2(...))) is the idiom that MTK handles.
    w_a = angular_velocity2(ori(frame_a))
    z_a = der(w_a)
    frame_a.f = [0, 0, 0]
    frame_a.tau = cross(w_a, nJ * w) - e * dot(nJ, z_a)
    if exact
      J * a = flange_a.tau + flange_b.tau - dot(nJ, z_a)
    else
      J * a = flange_a.tau + flange_b.tau
    end
  else
    J * a = flange_a.tau + flange_b.tau
  end
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/Rotor1D.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 150,
        "rot": 0,
        "attrs": {"font-size": "140"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
Inertia with a 1D rotation axis that is embedded in a 3D mechanism.

`J` is the moment of inertia about the axis `n` (resolved in `frame_a`).
`flange_a`/`flange_b` are the 1D drivetrain connections and `frame_a` is the
bearing/carrier frame.

When `drive_train_mechanics_3d = true` the component adds the two effects a plain
1D inertia cannot represent:

1. the gyroscopic reaction `cross(w_a, nJ*w)` that the spinning rotor exerts on
   its carrier, and
2. the correction `-e*dot(nJ, z_a)`, which returns the axial component of the
   carrier's angular acceleration to the carrier, because that axial torque is
   supplied through the *flanges* rather than through the frame.

Because of (2) this component models only the rotor's **spin momentum**. The
rotor's mass and its full inertia tensor must still be present as an ordinary
rigid body (e.g. a `BodyCylinder`) attached to the same frame; `Rotor1D` then adds
the angular momentum `J*e*w` due to the relative spin. Using `Rotor1D` alone
leaves the rotor massless in 3D.

`exact = false` drops the `-dot(nJ, z_a)` term from the rotor equation only (the
carrier reaction is unchanged), neglecting the influence of the bearing on the
rotor acceleration in order to break the resulting algebraic loop.

See `Mounting1D` for the meaning of `drive_train_mechanics_3d`.
"""
component Rotor1D
  parameter render::Boolean = true
  parameter color::Real[4] = [0.5, 0.5, 0.5, 1.0]
  parameter specular_coefficient::Real = 1.5
  flange_a = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -50, "y1": 450, "x2": 50, "y2": 550, "rot": 180}
      },
      "tags": []
    }
  }
  flange_b = Spline() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 950, "y1": 450, "x2": 1050, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  frame_a = Frame3D() if drive_train_mechanics_3d {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 450, "y1": 950, "x2": 550, "y2": 1050, "rot": 90}
      },
      "tags": []
    }
  }
  shape = CylinderShape(render = render, color = color, r = frame_a.r_0, R = transpose(frame_a.R), r_shape = r_center - e * (cylinder_length / 2), length_direction = e, length = cylinder_length, width = cylinder_diameter, height = cylinder_diameter) if drive_train_mechanics_3d {}
  "Expose the carrier frame `frame_a` and apply the rotor's gyroscopic/axial reaction to it. Structural: when false, neither the connector nor any 3D term is emitted."
  structural parameter drive_train_mechanics_3d::Boolean = true
  "Include the influence of the carrier's angular acceleration on the rotor acceleration. Set false to neglect it and break the resulting algebraic loop."
  structural parameter exact::Boolean = true
  "State priority of the rotor's angle and speed"
  structural parameter statePriority::Integer = 10
  "Moment of inertia of the rotor about its axis"
  parameter J::Inertia = 1
  "Axis of rotation, resolved in frame_a"
  parameter n::Real[3] = [1, 0, 0]
  "Position vector from frame_a to the rotor center, resolved in frame_a"
  parameter r_center::Length[3] = [0, 0, 0]
  "Length of the rotor cylinder in animations"
  parameter cylinder_length::Real = 2 * world_default_joint_length()
  "Diameter of the rotor cylinder in animations"
  parameter cylinder_diameter::Real = 2 * world_default_joint_width()
  final parameter e::Real[3] = normalize_(n)
  final parameter nJ::Real[3] = e * J
  "Rotation angle of the rotor relative to frame_a"
  variable phi::Angle(statePriority = statePriority)
  "Angular velocity of the rotor relative to frame_a"
  variable w::AngularVelocity(statePriority = statePriority)
  "Angular acceleration of the rotor relative to frame_a"
  variable a::AngularAcceleration
  "Absolute angular velocity of frame_a (the carrier), resolved in frame_a"
  variable w_a::AngularVelocity[3] if drive_train_mechanics_3d
  "Absolute angular acceleration of frame_a (the carrier), resolved in frame_a"
  variable z_a::AngularAcceleration[3] if drive_train_mechanics_3d
relations
  phi = flange_a.phi
  phi = flange_b.phi
  w = der(phi)
  a = der(w)
  if drive_train_mechanics_3d
    # Frame3D carries no angular velocity, so w_a is reconstructed from D(R) and
    # z_a is a second derivative of R. Naming both (rather than inlining
    # der(angular_velocity2(...))) is the idiom that MTK handles.
    w_a = angular_velocity2(ori(frame_a))
    z_a = der(w_a)
    frame_a.f = [0, 0, 0]
    frame_a.tau = cross(w_a, nJ * w) - e * dot(nJ, z_a)
    if exact
      J * a = flange_a.tau + flange_b.tau - dot(nJ, z_a)
    else
      J * a = flange_a.tau + flange_b.tau
    end
  else
    J * a = flange_a.tau + flange_b.tau
  end
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/Rotor1D.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 150,
        "rot": 0,
        "attrs": {"font-size": "140"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.

  • Examples

  • Experiments

  • Analyses