# No. 117 (Brown 1868): "A cam acting between two friction-rollers in a yoke. Has been used to give the movement to the valve of a steam engine."
#
# Model (cm): a cam on a shaft turned by hand (20 turns a minute, the one driven joint), struck out as the plate shows: the rollers' centres follow the curve r = 4.3 + 1.6 sin a + 0.25 sin 3 a (odd harmonics only, so
# the two rollers touch the cam together on both sides at every turn) and the cam's edge is that curve drawn in by the roller's radius (0.8 cm) plus 0.03 cm of play. The yoke (side bars, cross-bars,
# valve-rod up and stem down) slides in its guides and is carried by the contacts alone: its lift is -1.6 sin t - 0.25 sin 3t, to and fro 1.39 cm. The rollers turn freely on their pins
# (friction 0.1). The cam's mass is lumped heavy (a flywheel's worth, density 50000) so the velocity driver stays stable at the solver's step. Generator: opencode-runs/batch9/gen117.py.
number: 117
slug: cam-two-rollers-yoke
name: A cam acting between two friction-rollers in a yoke
brown: "A cam acting between two friction-rollers in a yoke. Has been used to give the movement to the valve of a steam engine."
units: cm
sim:
  timestep: 0.0005
  integrator: implicitfast
  iterations: 100
  solver: PGS
  multiccd: true
  duration_s: 12
  floor: false
bodies:
  - id: cam
    shape: part
    pos: [0, 0, 0]
    density: 50000.0
    friction: 0.1
    color: "#d9cfb6"
    pieces:
      - {kind: poly, points: [[0.3908, 3.5848], [0.5431, 3.6627], [0.701, 3.7326], [0.8641, 3.7938], [1.032, 3.8454], [1.2039, 3.8867], [1.3792, 3.9172], [1.5572, 3.9362], [1.7369, 3.9434], [1.9177, 3.9383], [2.0986, 3.9208], [2.2788, 3.8907], [2.4575, 3.8478], [2.6338, 3.7923], [2.8071, 3.7242], [2.9764, 3.6437], [3.1411, 3.5511], [3.3005, 3.4468], [3.454, 3.3311], [3.6009, 3.2046], [3.7408, 3.0677], [3.8732, 2.9211], [3.9977, 2.7653], [4.1139, 2.6011], [4.2217, 2.4291], [4.3208, 2.2501], [4.4112, 2.0646], [4.4927, 1.8734], [4.5653, 1.6773], [4.6291, 1.4767], [4.6842, 1.2724], [4.7305, 1.065], [4.7683, 0.855], [4.7975, 0.643], [4.8184, 0.4295], [4.8308, 0.215], [4.835, 0.0], [4.8308, -0.215], [4.8184, -0.4295], [4.7975, -0.643], [4.7683, -0.855], [4.7305, -1.065], [4.6842, -1.2724], [4.6291, -1.4767], [4.5653, -1.6773], [4.4927, -1.8734], [4.4112, -2.0646], [4.3208, -2.2501], [4.2217, -2.4291], [4.1139, -2.6011], [3.9977, -2.7653], [3.8732, -2.9211], [3.7408, -3.0677], [3.6009, -3.2046], [3.454, -3.3311], [3.3005, -3.4468], [3.1411, -3.5511], [2.9764, -3.6437], [2.8071, -3.7242], [2.6338, -3.7923], [2.4575, -3.8478], [2.2788, -3.8907], [2.0986, -3.9208], [1.9177, -3.9383], [1.7369, -3.9434], [1.5572, -3.9362], [1.3792, -3.9172], [1.2039, -3.8867], [1.032, -3.8454], [0.8641, -3.7938], [0.701, -3.7326], [0.5431, -3.6627], [0.3908, -3.5848], [0.2447, -3.4999], [0.1048, -3.4087], [-0.0287, -3.3122], [-0.1559, -3.2111], [-0.2767, -3.1064], [-0.3915, -2.9988], [-0.5004, -2.8889], [-0.604, -2.7774], [-0.7026, -2.6649], [-0.7967, -2.5517], [-0.8868, -2.4384], [-0.9733, -2.3251], [-1.0567, -2.2124], [-1.1374, -2.1003], [-1.2156, -1.9892], [-1.2916, -1.8794], [-1.3654, -1.7709], [-1.4371, -1.6641], [-1.5064, -1.559], [-1.5733, -1.4558], [-1.6375, -1.3545], [-1.6988, -1.2551], [-1.7567, -1.1576], [-1.8112, -1.0618], [-1.8619, -0.9678], [-1.9087, -0.8752], [-1.9513, -0.7839], [-1.9897, -0.6938], [-2.0236, -0.6048], [-2.0532, -0.5167], [-2.0782, -0.4294], [-2.0986, -0.3427], [-2.1145, -0.2566], [-2.1259, -0.1708], [-2.1327, -0.0853], [-2.135, -0.0], [-2.1327, 0.0853], [-2.1259, 0.1708], [-2.1145, 0.2566], [-2.0986, 0.3427], [-2.0782, 0.4294], [-2.0532, 0.5167], [-2.0236, 0.6048], [-1.9897, 0.6938], [-1.9513, 0.7839], [-1.9087, 0.8752], [-1.8619, 0.9678], [-1.8112, 1.0618], [-1.7567, 1.1576], [-1.6988, 1.2551], [-1.6375, 1.3545], [-1.5733, 1.4558], [-1.5064, 1.559], [-1.4371, 1.6641], [-1.3654, 1.7709], [-1.2916, 1.8794], [-1.2156, 1.9892], [-1.1374, 2.1003], [-1.0567, 2.2124], [-0.9733, 2.3251], [-0.8868, 2.4384], [-0.7967, 2.5517], [-0.7026, 2.6649], [-0.604, 2.7774], [-0.5004, 2.8889], [-0.3915, 2.9988], [-0.2767, 3.1064], [-0.1559, 3.2111], [-0.0287, 3.3122], [0.1048, 3.4087], [0.2447, 3.4999]], y: [-0.4, 0.4], collide: 1}
      - {kind: rod, from: [0, -1.2, 0], to: [0, 3.2, 0], radius: 0.7, color: "#8f8a80"}   # the cam's shaft
  - id: yoke
    shape: part
    pos: [0, 0, 0]
    mass: 0.3
    friction: 0.1
    color: "#b8ad97"
    pieces:
      - {kind: poly, points: [[-6.2716, -5.6], [-5.6716, -5.6], [-5.6716, 4.6], [-6.2716, 4.6]], y: [-0.5, 0.5], collide: 0}
      - {kind: poly, points: [[5.6716, -5.6], [6.2716, -5.6], [6.2716, 4.6], [5.6716, 4.6]], y: [-0.5, 0.5], collide: 0}
      - {kind: poly, points: [[-6.2716, 5.2], [6.2716, 5.2], [6.2716, 6.1], [-6.2716, 6.1]], y: [-0.5, 0.5], collide: 0}
      - {kind: poly, points: [[-6.2716, -6.1], [6.2716, -6.1], [6.2716, -5.2], [-6.2716, -5.2]], y: [-0.5, 0.5], collide: 0}
      - {kind: poly, points: [[-0.45, 6.0], [0.45, 6.0], [0.45, 15.0], [-0.45, 15.0]], y: [-0.45, 0.45], collide: 0}
      - {kind: poly, points: [[-0.45, -13.6], [0.45, -13.6], [0.45, -6.1], [-0.45, -6.1]], y: [-0.45, 0.45], collide: 0}
      - {kind: poly, points: [[-3.0, -15.0], [3.0, -15.0], [3.0, -13.6], [-3.0, -13.6]], y: [-0.9, 0.9], collide: 0}
      - {kind: poly, points: [[-0.4, 4.2], [0.4, 4.2], [0.4, 5.2], [-0.4, 5.2]], y: [0.55, 0.95], collide: 0}
      - {kind: poly, points: [[-0.4, -5.2], [0.4, -5.2], [0.4, -4.2], [-0.4, -4.2]], y: [0.55, 0.95], collide: 0}
  - id: roller_a
    shape: part
    pos: [0, 0, 4.3]
    mount: yoke
    mass: 0.4
    friction: 0.1
    color: "#cfc6b4"
    pieces:
      - {kind: rod, from: [0, -0.1, 4.3], to: [0, 0.1, 4.3], radius: 0.8, capsule: true, collide: 2}
  - id: roller_b
    shape: part
    pos: [0, 0, -4.3]
    mount: yoke
    mass: 0.4
    friction: 0.1
    color: "#cfc6b4"
    pieces:
      - {kind: rod, from: [0, -0.1, -4.3], to: [0, 0.1, -4.3], radius: 0.8, capsule: true, collide: 2}
  - id: frame
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#cfc6b4"
    pieces:
      - {kind: poly, points: [[-1.6, -15.5], [1.6, -15.5], [1.6, 0.0], [-1.6, 0.0]], y: [2.6, 3.6], collide: 0}   # the shaft's standard, behind
      - {kind: poly, points: [[-3.0, 12.0], [3.0, 12.0], [3.0, 13.2], [-3.0, 13.2]], y: [1.0, 2.0], collide: 0}   # the guides, behind the rod
      - {kind: poly, points: [[-3.0, -12.6], [3.0, -12.6], [3.0, -11.4], [-3.0, -11.4]], y: [1.0, 2.0], collide: 0}
      - {kind: poly, points: [[-0.3, -11.4], [0.3, -11.4], [0.3, 12.0], [-0.3, 12.0]], y: [1.0, 2.0], collide: 0}
      - {kind: poly, points: [[-12.0, -20.0], [12.0, -20.0], [12.0, -15.5], [-12.0, -15.5]], y: [-3, 4], collide: 0, color: "#b9b09c"}
joints:
  - {id: j_c, type: hinge, body: cam, axis: [0, 1, 0], damping: 0.002}   # the one driven joint; + : clockwise
  - {id: j_y, type: slide, body: yoke, axis: [0, 0, 1], range: [-1.6866, 1.6866], damping: 0.5}   # the yoke in its guides; + : up
  - {id: j_ra, type: hinge, body: roller_a, axis: [0, 1, 0], damping: 0.0002}
  - {id: j_rb, type: hinge, body: roller_b, axis: [0, 1, 0], damping: 0.0002}
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_c, kind: velocity, rpm: 20.0, kv: 4.0, max_torque: 4.0}
checks:
  - {type: follow, out: j_y, in: j_c, expect: -0.02066, tol: 0.00083, min_r2: 0.99, settle_s: 2.7083, window_s: 0.5833}   # up at its quickest
  - {type: follow, out: j_y, in: j_c, expect: 0.02066, tol: 0.00083, min_r2: 0.99, settle_s: 4.2083, window_s: 0.5833}   # and down
  - {type: follow, out: j_y, in: j_c, expect: -0.02066, tol: 0.00083, min_r2: 0.99, settle_s: 11.7083, window_s: 0.5833}   # a turn on, the same
  - {type: position, joint: j_y, min: -1.4366, max: 1.4366, settle_s: 0.5, window_s: 11}
camera: {target: [0, 0, -3], position: [0, -82.0, -3], fov: 34}
display:
  output: j_y
  labels: {j_c: "Cam (driver)", j_y: "Yoke"}
  proof: {label: "Cam out of the yoke", sub: "the cam turns but the yoke stands"}

