# No. 197 (Brown 1868): "What is called a 'mangle-rack.' A continuous rotation of the pinion will give a reciprocating motion to the square frame. The
#  pinion-shaft must be free to rise and fall, to pass round the guides at the ends of the rack. This motion may be modified as follows: If the square frame be fixed,
#  and the pinion be fixed upon a shaft made with a universal joint, the end of the shaft will describe a line, similar to that shown in the drawing, around the rack."
#
# Model (cm): the square frame slides along x on its guides. Across its middle runs a row of 15 round pins (r 0.35) at pitch 1.257, the rack; behind them a groove
# runs a track 2 above and one 2 below the row, joined by half-rounds about the end pins, between the island and the curved guides at the ends as in the plate.
# A 10-tooth pinion (pitch radius 2) turns in a carriage sliding in a fixed upright slot at x = 0, its follower in the groove, so the pinion-shaft rises and
# falls to pass round the ends. Only the pinion is driven (10 rpm, one way). Above the pins it drives the frame one way at rp = 2 cm a radian; round the end
# pin it drops below and drives it back at the same speed. (Brown's modification, the frame fixed and the shaft universal-jointed, is not modelled.)
# Generator: opencode-runs/batch11/gen197.py.
number: 197
slug: mangle-rack
name: A mangle-rack
brown: "What is called a mangle-rack. A continuous rotation of the pinion will give a reciprocating motion to the square frame. The pinion-shaft must be free to rise and fall, to pass round the guides at the ends of the rack."
units: cm
sim:
  timestep: 0.0002
  integrator: implicitfast
  iterations: 100
  solver: CG
  multiccd: true
  duration_s: 20.1
  floor: false
bodies:
  - id: rack
    shape: part
    pos: [0, 0, 0]
    density: 2700
    friction: 0.1
    color: "#e8dec6"
    pieces:
      - {kind: poly, points: [[-15.29646, -7.0], [15.29646, -7.0], [15.29646, -6.2], [-15.29646, -6.2]], y: [0.8, 1.6], collide: 0}   # the square frame
      - {kind: poly, points: [[-15.29646, 6.2], [15.29646, 6.2], [15.29646, 7.0], [-15.29646, 7.0]], y: [0.8, 1.6], collide: 0}
      - {kind: poly, points: [[-15.29646, -7.0], [-14.49646, -7.0], [-14.49646, 7.0], [-15.29646, 7.0]], y: [0.8, 1.6], collide: 0}
      - {kind: poly, points: [[14.49646, -7.0], [15.29646, -7.0], [15.29646, 7.0], [14.49646, 7.0]], y: [0.8, 1.6], collide: 0}
      - {kind: poly, points: [[-15.29646, -0.3], [-11.82646, -0.3], [-11.82646, 0.3], [-15.29646, 0.3]], y: [0.8, 1.6], collide: 0}   # the arms carrying the rack
      - {kind: poly, points: [[11.82646, -0.3], [15.29646, -0.3], [15.29646, 0.3], [11.82646, 0.3]], y: [0.8, 1.6], collide: 0}
      - {kind: disc, center: [-8.79646, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [-7.53982, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [-6.28319, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [-5.02655, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [-3.76991, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [-2.51327, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [-1.25664, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [0.0, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [1.25664, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [2.51327, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [3.76991, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [5.02655, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [6.28319, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [7.53982, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: disc, center: [8.79646, 0], radius: 0.35, y: [-1.0, -0.05], collide: 1}
      - {kind: poly, points: [[-8.79646, -1.47], [8.79646, -1.47], [8.79646, 1.47], [-8.79646, 1.47]], y: [0.05, 0.8], collide: 1}   # the island between the tracks
      - {kind: poly, points: [[-8.79646, 2.53], [8.79646, 2.53], [8.79646, 3.13], [-8.79646, 3.13]], y: [0.05, 0.8], collide: 1}   # the upper guide
      - {kind: poly, points: [[-8.79646, -2.53], [8.79646, -2.53], [8.79646, -3.13], [-8.79646, -3.13]], y: [0.05, 0.8], collide: 1}   # the lower guide
      - {kind: disc, center: [8.79646, 0], radius: 1.47, y: [0.05, 0.8], collide: 1}   # the island's round end
      - {kind: band, center: [8.79646, 0], r: [2.53, 3.13], a: [-1.5708, 1.5708], slices: 18, y: [0.05, 0.8], collide: 1}   # the guide round the end
      - {kind: disc, center: [-8.79646, 0], radius: 1.47, y: [0.05, 0.8], collide: 1}   # the island's round end
      - {kind: band, center: [-8.79646, 0], r: [2.53, 3.13], a: [1.5708, 4.71239], slices: 18, y: [0.05, 0.8], collide: 1}   # the guide round the end
  - id: carriage
    shape: part
    pos: [0, 0, 2.0]
    density: 2700
    color: "#8f8a80"
    pieces:
      - {kind: disc, center: [0, 2.0], radius: 0.5, y: [0.05, 0.75], collide: 2}            # the follower in the groove
      - {kind: poly, points: [[-0.7, 1.3], [0.7, 1.3], [0.7, 2.7], [-0.7, 2.7]], y: [-3.4, -2.6], collide: 0}   # its block in the upright's slot
      - {kind: rod, from: [0, -2.6, 2.0], to: [0, -1.05, 2.0], radius: 0.3, collide: 0}
  - id: pinion
    shape: part
    mount: carriage
    pos: [0, 0, 2.0]
    density: 7800
    friction: 0.1
    color: "#e4d9bf"
    pieces:
      - {kind: disc, center: [0, 2.0], radius: 1.5, y: [-1.0, -0.05], collide: 0}
      - {kind: poly, points: [[-0.05957, 3.50527], [-0.83658, 3.2528], [-0.80056, 4.28442], [-0.69508, 4.31869]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[-0.93296, 3.18277], [-1.41319, 2.5218], [-1.99041, 3.37758], [-1.92523, 3.4673]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[-1.45, 2.4085], [-1.45, 1.5915], [-2.42, 1.94455], [-2.42, 2.05545]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[-1.41319, 1.4782], [-0.93296, 0.81723], [-1.92523, 0.5327], [-1.99041, 0.62242]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[-0.83658, 0.7472], [-0.05957, 0.49473], [-0.69508, -0.31869], [-0.80056, -0.28442]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[0.05957, 0.49473], [0.83658, 0.7472], [0.80056, -0.28442], [0.69508, -0.31869]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[0.93296, 0.81723], [1.41319, 1.4782], [1.99041, 0.62242], [1.92523, 0.5327]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[1.45, 1.5915], [1.45, 2.4085], [2.42, 2.05545], [2.42, 1.94455]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[1.41319, 2.5218], [0.93296, 3.18277], [1.92523, 3.4673], [1.99041, 3.37758]], y: [-1.0, -0.05], collide: 2}
      - {kind: poly, points: [[0.83658, 3.2528], [0.05957, 3.50527], [0.69508, 4.31869], [0.80056, 4.28442]], y: [-1.0, -0.05], collide: 2}
  - id: upright
    shape: frame
    color: "#8f8a80"
    rods:
      - {from: [-1.1, -3.0, -10.0], to: [-1.1, -3.0, 10.0], radius: 0.35}   # the upright slot's two cheeks
      - {from: [1.1, -3.0, -10.0], to: [1.1, -3.0, 10.0], radius: 0.35}
      - {from: [-25.29646, 1.2, 7.7], to: [25.29646, 1.2, 7.7], radius: 0.3}   # the frame's guides
      - {from: [-25.29646, 1.2, -7.7], to: [25.29646, 1.2, -7.7], radius: 0.3}
joints:
  - {id: j_rack, type: slide, body: rack, axis: [1, 0, 0], damping: 0.5, range: [-11.79646, 11.79646]}
  - {id: j_lift, type: slide, body: carriage, axis: [0, 0, 1], damping: 0.5, range: [-4.6, 0.6]}
  - {id: j_pinion, type: hinge, body: pinion, axis: [0, -1, 0], damping: 0.001}   # the one driven joint; +: counter-clockwise
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_pinion, kind: velocity, rpm: 10.0, kv: 1.5, max_torque: 6}   # gain kept so kv x speed is under the torque cap: the light unloaded pinion stays stable
checks:
  - {type: ratio, out: j_rack, in: j_pinion, expect: 0.02, tol: 0.0006, settle_s: 0.5, window_s: 3.2}   # above the pins: the frame goes right at rp a radian
  - {type: ratio, out: j_rack, in: j_pinion, expect: -0.02, tol: 0.0006, settle_s: 8.2, window_s: 6.4}   # below, after the end: back at the same speed
  - {type: penetration, max: 0.001, settle_s: 0.5}
camera: {target: [0, 0, 0], position: [0, -95, 1], fov: 34}
display:
  output: j_rack
  labels: {j_pinion: "Pinion (driver, one way)", j_rack: "Square frame (to and fro)", j_lift: "Pinion-shaft (rises and falls)"}
  proof: {label: "Pins out of contact", sub: "the pinion turns alone: the frame stands still"}

