# No. 274 (Brown 1868): "An engine-governor. The rise and fall of the balls, K, are guided by the parabolic curved arms, B, on which the anti-friction wheels, L, run. The rods, F, connecting the wheels, L, with the sleeve move it up and down the spindle, C, D."
#
# Model (cm, gravity on): the spindle C D is the one driven joint (165 turns a minute). It carries the two arms B, whose running faces are the parabola z = 20 + x^2/10.
# On each face runs an anti-friction wheel L (radius 0.8), on an axle at the top of a rod F (10) pinned at its foot to the sleeve, which slides on the spindle (a little dashpot);
# the ball K (0.4 kg with its rod) hangs from the wheel's axle. Nothing else is driven: as the spindle runs up, the balls fly out and the wheels climb the arms, and the rods
# lift the sleeve. Contact with the arms is the only thing that guides them. Generator: opencode-runs/batch12/gen274.py.
number: 274
slug: parabolic-arm-governor
name: A governor with parabolic arms and anti-friction wheels
brown: "An engine-governor. The rise and fall of the balls, K, are guided by the parabolic curved arms, B, on which the anti-friction wheels, L, run. The rods, F, connecting the wheels, L, with the sleeve move it up and down the spindle, C, D."
units: cm
sim:
  timestep: 0.0002
  integrator: implicitfast
  iterations: 100
  solver: CG
  multiccd: true
  duration_s: 9
  floor: false
bodies:
  - id: shaft
    shape: part
    pos: [0, 0, 0]
    density: 7800
    color: "#e4d9bf"
    pieces:
      - {kind: rod, from: [0, 0, 3.2962], to: [0, 0, 35.876], radius: 0.7, collide: 0}   # the spindle C D
      - {kind: rod, from: [0, 0, 32.376], to: [0, 0, 33.976], radius: 1.4, collide: 0, color: "#8f8a80"}   # the hub
      - {kind: poly, points: [[1.8133, 19.5893], [2.0371, 19.6654], [1.8, 20.324], [1.6, 20.256]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.0371, 19.6654], [2.26, 19.7501], [2.0, 20.4], [1.8, 20.324]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.26, 19.7501], [2.4819, 19.8433], [2.2, 20.484], [2.0, 20.4]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.4819, 19.8433], [2.7029, 19.9449], [2.4, 20.576], [2.2, 20.484]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.7029, 19.9449], [2.9229, 20.0549], [2.6, 20.676], [2.4, 20.576]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.9229, 20.0549], [3.142, 20.1732], [2.8, 20.784], [2.6, 20.676]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[3.142, 20.1732], [3.3601, 20.2998], [3.0, 20.9], [2.8, 20.784]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[3.3601, 20.2998], [3.5773, 20.4344], [3.2, 21.024], [3.0, 20.9]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[3.5773, 20.4344], [3.7936, 20.5772], [3.4, 21.156], [3.2, 21.024]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[3.7936, 20.5772], [4.009, 20.7279], [3.6, 21.296], [3.4, 21.156]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[4.009, 20.7279], [4.2236, 20.8867], [3.8, 21.444], [3.6, 21.296]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[4.2236, 20.8867], [4.4373, 21.0534], [4.0, 21.6], [3.8, 21.444]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[4.4373, 21.0534], [4.6502, 21.228], [4.2, 21.764], [4.0, 21.6]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[4.6502, 21.228], [4.8624, 21.4105], [4.4, 21.936], [4.2, 21.764]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[4.8624, 21.4105], [5.0739, 21.6008], [4.6, 22.116], [4.4, 21.936]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[5.0739, 21.6008], [5.2848, 21.799], [4.8, 22.304], [4.6, 22.116]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[5.2848, 21.799], [5.495, 22.005], [5.0, 22.5], [4.8, 22.304]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[5.495, 22.005], [5.7046, 22.2188], [5.2, 22.704], [5.0, 22.5]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[5.7046, 22.2188], [5.9136, 22.4404], [5.4, 22.916], [5.2, 22.704]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[5.9136, 22.4404], [6.1222, 22.6698], [5.6, 23.136], [5.4, 22.916]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[6.1222, 22.6698], [6.3302, 22.9069], [5.8, 23.364], [5.6, 23.136]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[6.3302, 22.9069], [6.5378, 23.1519], [6.0, 23.6], [5.8, 23.364]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[6.5378, 23.1519], [6.7449, 23.4046], [6.2, 23.844], [6.0, 23.6]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[6.7449, 23.4046], [6.9516, 23.665], [6.4, 24.096], [6.2, 23.844]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[6.9516, 23.665], [7.158, 23.9333], [6.6, 24.356], [6.4, 24.096]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[7.158, 23.9333], [7.364, 24.2093], [6.8, 24.624], [6.6, 24.356]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[7.364, 24.2093], [7.5696, 24.4931], [7.0, 24.9], [6.8, 24.624]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[7.5696, 24.4931], [7.775, 24.7847], [7.2, 25.184], [7.0, 24.9]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[7.775, 24.7847], [7.98, 25.0841], [7.4, 25.476], [7.2, 25.184]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[7.98, 25.0841], [8.1848, 25.3913], [7.6, 25.776], [7.4, 25.476]], y: [-0.6, 0.6], collide: 1}
      - {kind: rod, from: [7.6, 0, 25.426], to: [8.5, 0, 27.926], radius: 0.45, collide: 0}
      - {kind: rod, from: [8.5, 0, 27.926], to: [8.2, 0, 30.426], radius: 0.45, collide: 0}
      - {kind: rod, from: [8.2, 0, 30.426], to: [5.0, 0, 32.426], radius: 0.45, collide: 0}
      - {kind: rod, from: [5.0, 0, 32.426], to: [1.0, 0, 33.026], radius: 0.45, collide: 0}
      - {kind: poly, points: [[-1.6, 20.256], [-1.8, 20.324], [-2.0371, 19.6654], [-1.8133, 19.5893]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-1.8, 20.324], [-2.0, 20.4], [-2.26, 19.7501], [-2.0371, 19.6654]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-2.0, 20.4], [-2.2, 20.484], [-2.4819, 19.8433], [-2.26, 19.7501]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-2.2, 20.484], [-2.4, 20.576], [-2.7029, 19.9449], [-2.4819, 19.8433]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-2.4, 20.576], [-2.6, 20.676], [-2.9229, 20.0549], [-2.7029, 19.9449]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-2.6, 20.676], [-2.8, 20.784], [-3.142, 20.1732], [-2.9229, 20.0549]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-2.8, 20.784], [-3.0, 20.9], [-3.3601, 20.2998], [-3.142, 20.1732]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-3.0, 20.9], [-3.2, 21.024], [-3.5773, 20.4344], [-3.3601, 20.2998]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-3.2, 21.024], [-3.4, 21.156], [-3.7936, 20.5772], [-3.5773, 20.4344]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-3.4, 21.156], [-3.6, 21.296], [-4.009, 20.7279], [-3.7936, 20.5772]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-3.6, 21.296], [-3.8, 21.444], [-4.2236, 20.8867], [-4.009, 20.7279]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-3.8, 21.444], [-4.0, 21.6], [-4.4373, 21.0534], [-4.2236, 20.8867]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-4.0, 21.6], [-4.2, 21.764], [-4.6502, 21.228], [-4.4373, 21.0534]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-4.2, 21.764], [-4.4, 21.936], [-4.8624, 21.4105], [-4.6502, 21.228]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-4.4, 21.936], [-4.6, 22.116], [-5.0739, 21.6008], [-4.8624, 21.4105]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-4.6, 22.116], [-4.8, 22.304], [-5.2848, 21.799], [-5.0739, 21.6008]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-4.8, 22.304], [-5.0, 22.5], [-5.495, 22.005], [-5.2848, 21.799]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-5.0, 22.5], [-5.2, 22.704], [-5.7046, 22.2188], [-5.495, 22.005]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-5.2, 22.704], [-5.4, 22.916], [-5.9136, 22.4404], [-5.7046, 22.2188]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-5.4, 22.916], [-5.6, 23.136], [-6.1222, 22.6698], [-5.9136, 22.4404]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-5.6, 23.136], [-5.8, 23.364], [-6.3302, 22.9069], [-6.1222, 22.6698]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-5.8, 23.364], [-6.0, 23.6], [-6.5378, 23.1519], [-6.3302, 22.9069]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-6.0, 23.6], [-6.2, 23.844], [-6.7449, 23.4046], [-6.5378, 23.1519]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-6.2, 23.844], [-6.4, 24.096], [-6.9516, 23.665], [-6.7449, 23.4046]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-6.4, 24.096], [-6.6, 24.356], [-7.158, 23.9333], [-6.9516, 23.665]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-6.6, 24.356], [-6.8, 24.624], [-7.364, 24.2093], [-7.158, 23.9333]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-6.8, 24.624], [-7.0, 24.9], [-7.5696, 24.4931], [-7.364, 24.2093]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-7.0, 24.9], [-7.2, 25.184], [-7.775, 24.7847], [-7.5696, 24.4931]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-7.2, 25.184], [-7.4, 25.476], [-7.98, 25.0841], [-7.775, 24.7847]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-7.4, 25.476], [-7.6, 25.776], [-8.1848, 25.3913], [-7.98, 25.0841]], y: [-0.6, 0.6], collide: 1}
      - {kind: rod, from: [-7.6, 0, 25.426], to: [-8.5, 0, 27.926], radius: 0.45, collide: 0}
      - {kind: rod, from: [-8.5, 0, 27.926], to: [-8.2, 0, 30.426], radius: 0.45, collide: 0}
      - {kind: rod, from: [-8.2, 0, 30.426], to: [-5.0, 0, 32.426], radius: 0.45, collide: 0}
      - {kind: rod, from: [-5.0, 0, 32.426], to: [-1.0, 0, 33.026], radius: 0.45, collide: 0}
  - id: sleeve
    shape: part
    pos: [0, 0, 11.2962]
    mount: shaft
    mass: 0.15
    color: "#b8ad97"
    pieces:
      - {kind: rod, from: [0, 0, 9.8962], to: [0, 0, 12.2962], radius: 1.2, collide: 0}
      - {kind: rod, from: [-1.6, 0, 11.2962], to: [1.6, 0, 11.2962], radius: 0.45, collide: 0, color: "#8f8a80"}
      - {kind: rod, from: [0, 0, 8.8962], to: [0, 0, 9.3962], radius: 2.0, collide: 0, color: "#8f8a80"}   # its collar
  - id: rod_r
    shape: part
    pos: [1.3, 0, 11.2962]
    mount: sleeve
    mass: 0.4
    color: "#8f8a80"
    pieces:
      - {kind: rod, from: [1.3, -0.9, 11.2962], to: [2.0, -0.9, 21.2717], radius: 0.25, collide: 0, color: "#b8ad97"}   # the rod F
      - {kind: rod, from: [2.0, -0.9, 21.2717], to: [3.6, -0.9, 18.4717], radius: 0.25, collide: 0, color: "#b8ad97"}   # the ball's hanger
      - {kind: rod, from: [2.0, -1.0, 21.2717], to: [2.0, 0.9, 21.2717], radius: 0.2, collide: 0}   # the wheel's axle
      - {kind: rod, from: [3.6, -2.0, 18.4717], to: [3.6, 0.2, 18.4717], radius: 2.0, collide: 0}   # the ball K
  - id: wheel_r
    shape: part
    pos: [2.0, 0, 21.2717]
    mount: rod_r
    mass: 0.02
    friction: 0.8
    color: "#e6dcc6"
    pieces:
      - {kind: disc, center: [2.0, 21.2717], radius: 0.8, y: [-0.4, 0.4], collide: 2}   # the anti-friction wheel L
      - {kind: poly, points: [[1.94, 21.5217], [2.06, 21.5217], [2.06, 21.9717], [1.94, 21.9717]], y: [-0.45, -0.4], collide: 0, color: "#6f675a"}
  - id: rod_l
    shape: part
    pos: [-1.3, 0, 11.2962]
    mount: sleeve
    mass: 0.4
    color: "#8f8a80"
    pieces:
      - {kind: rod, from: [-1.3, -0.9, 11.2962], to: [-2.0, -0.9, 21.2717], radius: 0.25, collide: 0, color: "#b8ad97"}   # the rod F
      - {kind: rod, from: [-2.0, -0.9, 21.2717], to: [-3.6, -0.9, 18.4717], radius: 0.25, collide: 0, color: "#b8ad97"}   # the ball's hanger
      - {kind: rod, from: [-2.0, -1.0, 21.2717], to: [-2.0, 0.9, 21.2717], radius: 0.2, collide: 0}   # the wheel's axle
      - {kind: rod, from: [-3.6, -2.0, 18.4717], to: [-3.6, 0.2, 18.4717], radius: 2.0, collide: 0}   # the ball K
  - id: wheel_l
    shape: part
    pos: [-2.0, 0, 21.2717]
    mount: rod_l
    mass: 0.02
    friction: 0.8
    color: "#e6dcc6"
    pieces:
      - {kind: disc, center: [-2.0, 21.2717], radius: 0.8, y: [-0.4, 0.4], collide: 2}   # the anti-friction wheel L
      - {kind: poly, points: [[-2.06, 21.5217], [-1.94, 21.5217], [-1.94, 21.9717], [-2.06, 21.9717]], y: [-0.45, -0.4], collide: 0, color: "#6f675a"}
  - id: frame
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#cfc6b4"
    pieces:
      - {kind: rod, from: [0, 0, 1.2962], to: [0, 0, 3.7962], radius: 1.5, collide: 0, color: "#8f8a80"}   # the spindle's step
      - {kind: poly, points: [[-8, 0.0962], [8, 0.0962], [8, 1.2962], [-8, 1.2962]], y: [-4, 4], collide: 0, color: "#b9b09c"}
joints:
  - {id: j_s, type: hinge, body: shaft, axis: [0, 0, 1], damping: 0.002}   # the one driven joint: the spindle
  - {id: j_z, type: slide, body: sleeve, axis: [0, 0, 1], range: [-0.5, 6], damping: 0.3}   # the sleeve; + : up
  - {id: j_r, type: hinge, body: rod_r, axis: [0, 1, 0], range: [-0.3, 0.9], damping: 0.002}   # the right rod F; + : outward
  - {id: j_l, type: hinge, body: rod_l, axis: [0, -1, 0], range: [-0.3, 0.9], damping: 0.002}   # the left rod F; + : outward
  - {id: j_wr, type: hinge, body: wheel_r, axis: [0, 1, 0], damping: 0.00001}   # the wheels on their axles
  - {id: j_wl, type: hinge, body: wheel_l, axis: [0, 1, 0], damping: 0.00001}
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_s, kind: velocity, rpm: 165, kv: 1.0, max_torque: 5}
checks:
  - {type: follow, out: j_z, in: j_r, expect: 0.1128, tol: 0.0056, min_r2: 0.995, settle_s: 0.6, window_s: 1.0}   # the sleeve rises as the wheel climbs the parabola (m per radian of rod)
  - {type: follow, out: j_l, in: j_r, expect: 1.0, tol: 0.03, min_r2: 0.995, settle_s: 0.0, window_s: 1.5}   # both balls alike
  - {type: position, joint: j_r, min: 0.17, max: 0.22, settle_s: 3.0, window_s: 5.5}   # the balls stand out where the arms and the spin balance them
  - {type: position, joint: j_z, min: 1.4, max: 1.85, settle_s: 3.0, window_s: 5.5}   # and the sleeve stands up about 1.6 cm
  - {type: penetration, max: 0.001, settle_s: 0.5}
camera: {target: [0, 0, 12.5], position: [0, -78, 15], fov: 34}
display:
  output: j_z
  labels: {j_s: "Spindle (driver)", j_r: "Right rod F", j_l: "Left rod F", j_z: "Sleeve (slide)"}
  proof: {label: "Parabolic governor", sub: "the wheels climb the arms and lift the sleeve"}

