Skip to content
LIBRARY
PlanarMechanics.Cable.md

PlanarMechanics.Cable

Planar cable / rope of total length l and mass m, modeled as n rigid BodyShape segments connected by Revolute joints. This is the planar (PlanarMechanics) analog of the 3D Cable, using 1-DOF revolute joints (rotation about the z-axis) in place of 3-DOF Spherical joints.

When end_joints = true (default), the topology uses n + 1 joints: frame_a → R₁ → link₁ → R₂ → … → Rₙ → linkₙ → Rₙ₊₁ → frame_b

When end_joints = false, only the n − 1 internal joints are kept and both ends attach rigidly to the adjacent frame: frame_a → link₁ → R₁ → link₂ → … → Rₙ₋₁ → linkₙ → frame_b

By default each Revolute joint transmits no torque (its rotational flange is left unconnected), so the cable swings freely. Setting hasdamping = true adds a viscous Damper of constant d_joint to every joint, dissipating energy as the cable flexes (the planar analog of the Rope's d_joint in Multibody.jl). Setting hasstiffness = true adds a rotational Spring of constant c_joint to every joint, giving the cable flexural stiffness (a restoring torque toward the straight configuration). The two are independent and may be combined.

The cable starts straight (along dir); seed an initial bend by setting a joint's angle as an initial condition, e.g. a 0.9 rad bend on the first joint: cable.joints[1].phi = 0.9.

This component extends from PartialTwoFrames This component extends from MultibodyComponents.Renderable

Usage

MultibodyComponents.PlanarMechanics.Cable(render=true, color=[0.5, 0.4, 0.4, 1], specular_coefficient=1.5, d_joint=0, c_joint=0, l=1, m=1, dir=[0, -1], radius=0.05, z_position=0, r_segment=(l / n) * (dir / norm(dir)), m_segment=m / n, I_segment=m_segment * (l / n) ^ 2 / 12)

Parameters:

NameDescriptionUnitsDefault value
nNumber of rigid segments5
end_jointsInclude Revolute joints at both ends (frame_a and frame_b)true
hasdampingAdd viscous damping in the joints between links (dissipates energy while the cable flexes)false
hasstiffnessAdd rotational stiffness in the joints between links (the cable resists bending toward straight)false
njNumber of jointsifelse(end_...+ 1, n - 1)
rendertrue
color[0.5, 0.4, 0.4, 1]
specular_coefficient1.5
d_jointViscous damping constant of each joint (used only if hasdamping = true)N.m.s/rad0
c_jointRotational spring constant of each joint (used only if hasstiffness = true)N.m/rad0
lTotal unstretched length of the ropem1
mTotal mass of the rope (each segment gets m/n)kg1
dirHanging direction in the plane; unit-normalized internally[0, -1]
radiusRendering radius of each segment0.05
z_positionz-position of the cable segments in animations0

Connectors

  • frame_a - Coordinate system (2-dim.) fixed to the component with one cut-force and cut-torque.

All variables are resolved in the planar world frame. (Frame2D)

  • frame_b - Coordinate system (2-dim.) fixed to the component with one cut-force and cut-torque.

All variables are resolved in the planar world frame. (Frame2D)

Behavior

Source

dyad
"""
Planar cable / rope of total length `l` and mass `m`, modeled as `n` rigid
`BodyShape` segments connected by `Revolute` joints. This is the planar
(PlanarMechanics) analog of the 3D `Cable`, using 1-DOF revolute joints
(rotation about the z-axis) in place of 3-DOF `Spherical` joints.

When `end_joints = true` (default), the topology uses `n + 1` joints:
`frame_a → R₁ → link₁ → R₂ → … → Rₙ → linkₙ → Rₙ₊₁ → frame_b`

When `end_joints = false`, only the `n − 1` internal joints are kept and
both ends attach rigidly to the adjacent frame:
`frame_a → link₁ → R₁ → link₂ → … → Rₙ₋₁ → linkₙ → frame_b`

By default each `Revolute` joint transmits no torque (its rotational flange is
left unconnected), so the cable swings freely. Setting `hasdamping = true` adds
a viscous `Damper` of constant `d_joint` to every joint, dissipating energy as
the cable flexes (the planar analog of the `Rope`'s `d_joint` in Multibody.jl).
Setting `hasstiffness = true` adds a rotational `Spring` of constant `c_joint`
to every joint, giving the cable flexural stiffness (a restoring torque toward
the straight configuration). The two are independent and may be combined.

The cable starts straight (along `dir`); seed an initial bend by setting a
joint's angle as an initial condition, e.g. a 0.9 rad bend on the first joint:
`cable.joints[1].phi = 0.9`.
"""
component Cable
  extends PartialTwoFrames
  extends MultibodyComponents.Renderable(color = [0.5, 0.4, 0.4, 1])
  joints = [Revolute(render = false, phi(initial = 0), w(initial = 0)) for i in 1:nj]
  links = [BodyShape(r = r_segment, m = m_segment, I = I_segment, color = color, radius = radius, z_position = z_position) for i in 1:n]
  dampers = [RotationalComponents.Components.Damper(d = d_joint) for i in 1:nj] if hasdamping
  damper_ground = RotationalComponents.Components.Fixed() if hasdamping
  springs = [RotationalComponents.Components.Spring(c = c_joint) for i in 1:nj] if hasstiffness
  spring_ground = RotationalComponents.Components.Fixed() if hasstiffness
  "Number of rigid segments"
  structural parameter n::Integer = 5
  "Include Revolute joints at both ends (frame_a and frame_b)"
  structural parameter end_joints::Boolean = true
  "Add viscous damping in the joints between links (dissipates energy while the cable flexes)"
  structural parameter hasdamping::Boolean = false
  "Viscous damping constant of each joint (used only if hasdamping = true)"
  parameter d_joint::RotationalDampingConstant = 0
  "Add rotational stiffness in the joints between links (the cable resists bending toward straight)"
  structural parameter hasstiffness::Boolean = false
  "Rotational spring constant of each joint (used only if hasstiffness = true)"
  parameter c_joint::RotationalSpringConstant = 0
  "Number of joints"
  final structural parameter nj::Integer = ifelse(end_joints, n + 1, n - 1)
  "Total unstretched length of the rope"
  parameter l::Length = 1
  "Total mass of the rope (each segment gets m/n)"
  parameter m::Mass = 1
  "Hanging direction in the plane; unit-normalized internally"
  parameter dir::Real[2] = [0, -1]
  "Rendering radius of each segment"
  parameter radius::Real = 0.05
  "z-position of the cable segments in animations"
  parameter z_position::Real = 0
  "Vector from frame_a to frame_b of one segment, resolved in segment frame_a"
  final parameter r_segment::Length[2] = (l / n) * (dir / norm(dir))
  "Mass of one segment"
  final parameter m_segment::Mass = m / n
  "Moment of inertia of one segment about its center of mass (thin rod)"
  final parameter I_segment::MomentOfInertia = m_segment * (l / n) ^ 2 / 12
relations
  if end_joints
    connect(frame_a, joints[1].frame_a)
    for i in 1:n
      connect(joints[i].frame_b, links[i].frame_a)
      connect(links[i].frame_b, joints[i + 1].frame_a)
    end
    connect(joints[nj].frame_b, frame_b)
  else
    connect(frame_a, links[1].frame_a)
    for i in 1:nj
      connect(links[i].frame_b, joints[i].frame_a)
      connect(joints[i].frame_b, links[i + 1].frame_a)
    end
    connect(links[n].frame_b, frame_b)
  end
  # viscous joint damping: each joint flange is damped against a fixed reference,
  # so the damper dissipates energy proportional to the joint's angular velocity
  if hasdamping
    for i in 1:nj
      connect(joints[i].flange_a, dampers[i].spline_a)
      connect(dampers[i].spline_b, damper_ground.spline)
    end
  end
  # rotational joint stiffness: each joint flange is sprung against a fixed
  # reference, so the spring applies a restoring torque toward the straight cable
  if hasstiffness
    for i in 1:nj
      connect(joints[i].flange_a, springs[i].spline_a)
      connect(springs[i].spline_b, spring_ground.spline)
    end
  end
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/Cable.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 150,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end
Flattened Source
dyad
"""
Planar cable / rope of total length `l` and mass `m`, modeled as `n` rigid
`BodyShape` segments connected by `Revolute` joints. This is the planar
(PlanarMechanics) analog of the 3D `Cable`, using 1-DOF revolute joints
(rotation about the z-axis) in place of 3-DOF `Spherical` joints.

When `end_joints = true` (default), the topology uses `n + 1` joints:
`frame_a → R₁ → link₁ → R₂ → … → Rₙ → linkₙ → Rₙ₊₁ → frame_b`

When `end_joints = false`, only the `n − 1` internal joints are kept and
both ends attach rigidly to the adjacent frame:
`frame_a → link₁ → R₁ → link₂ → … → Rₙ₋₁ → linkₙ → frame_b`

By default each `Revolute` joint transmits no torque (its rotational flange is
left unconnected), so the cable swings freely. Setting `hasdamping = true` adds
a viscous `Damper` of constant `d_joint` to every joint, dissipating energy as
the cable flexes (the planar analog of the `Rope`'s `d_joint` in Multibody.jl).
Setting `hasstiffness = true` adds a rotational `Spring` of constant `c_joint`
to every joint, giving the cable flexural stiffness (a restoring torque toward
the straight configuration). The two are independent and may be combined.

The cable starts straight (along `dir`); seed an initial bend by setting a
joint's angle as an initial condition, e.g. a 0.9 rad bend on the first joint:
`cable.joints[1].phi = 0.9`.
"""
component Cable
  frame_a = Frame2D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 50, "y1": 450, "x2": 150, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  frame_b = Frame2D() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 850, "y1": 450, "x2": 950, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  parameter render::Boolean = true
  parameter color::Real[4] = [0.5, 0.5, 0.5, 1.0]
  parameter specular_coefficient::Real = 1.5
  joints = [Revolute(render = false, phi(initial = 0), w(initial = 0)) for i in 1:nj]
  links = [BodyShape(r = r_segment, m = m_segment, I = I_segment, color = color, radius = radius, z_position = z_position) for i in 1:n]
  dampers = [RotationalComponents.Components.Damper(d = d_joint) for i in 1:nj] if hasdamping
  damper_ground = RotationalComponents.Components.Fixed() if hasdamping
  springs = [RotationalComponents.Components.Spring(c = c_joint) for i in 1:nj] if hasstiffness
  spring_ground = RotationalComponents.Components.Fixed() if hasstiffness
  "Number of rigid segments"
  structural parameter n::Integer = 5
  "Include Revolute joints at both ends (frame_a and frame_b)"
  structural parameter end_joints::Boolean = true
  "Add viscous damping in the joints between links (dissipates energy while the cable flexes)"
  structural parameter hasdamping::Boolean = false
  "Viscous damping constant of each joint (used only if hasdamping = true)"
  parameter d_joint::RotationalDampingConstant = 0
  "Add rotational stiffness in the joints between links (the cable resists bending toward straight)"
  structural parameter hasstiffness::Boolean = false
  "Rotational spring constant of each joint (used only if hasstiffness = true)"
  parameter c_joint::RotationalSpringConstant = 0
  "Number of joints"
  final structural parameter nj::Integer = ifelse(end_joints, n + 1, n - 1)
  "Total unstretched length of the rope"
  parameter l::Length = 1
  "Total mass of the rope (each segment gets m/n)"
  parameter m::Mass = 1
  "Hanging direction in the plane; unit-normalized internally"
  parameter dir::Real[2] = [0, -1]
  "Rendering radius of each segment"
  parameter radius::Real = 0.05
  "z-position of the cable segments in animations"
  parameter z_position::Real = 0
  "Vector from frame_a to frame_b of one segment, resolved in segment frame_a"
  final parameter r_segment::Length[2] = (l / n) * (dir / norm(dir))
  "Mass of one segment"
  final parameter m_segment::Mass = m / n
  "Moment of inertia of one segment about its center of mass (thin rod)"
  final parameter I_segment::MomentOfInertia = m_segment * (l / n) ^ 2 / 12
relations
  if end_joints
    connect(frame_a, joints[1].frame_a)
    for i in 1:n
      connect(joints[i].frame_b, links[i].frame_a)
      connect(links[i].frame_b, joints[i + 1].frame_a)
    end
    connect(joints[nj].frame_b, frame_b)
  else
    connect(frame_a, links[1].frame_a)
    for i in 1:nj
      connect(links[i].frame_b, joints[i].frame_a)
      connect(joints[i].frame_b, links[i + 1].frame_a)
    end
    connect(links[n].frame_b, frame_b)
  end
  # viscous joint damping: each joint flange is damped against a fixed reference,
  # so the damper dissipates energy proportional to the joint's angular velocity
  if hasdamping
    for i in 1:nj
      connect(joints[i].flange_a, dampers[i].spline_a)
      connect(dampers[i].spline_b, damper_ground.spline)
    end
  end
  # rotational joint stiffness: each joint flange is sprung against a fixed
  # reference, so the spring applies a restoring torque toward the straight cable
  if hasstiffness
    for i in 1:nj
      connect(joints[i].flange_a, springs[i].spline_a)
      connect(springs[i].spline_b, spring_ground.spline)
    end
  end
metadata {
  "Dyad": {
    "icons": {"default": "dyad://MultibodyComponents/Cable.svg"},
    "labels": [
      {
        "label": "$(instance)",
        "x": 500,
        "y": 150,
        "rot": 0,
        "attrs": {"font-size": "160"}
      }
    ]
  }
}
end


Test Cases

No test cases defined.