# No. 115 (Brown 1868): "Rotary motion of the toothed wheels produces rectilinear motion of the double rack and gives equal force and velocity to each side, both wheels being of equal size."
#
# Model (cm): two equal wheels (16 teeth, module 0.8, pitch radius 6.4, No. 34's straight-flanked teeth) stand one above the other, gearing with each other; the upper gears with the
# rack on the top bar of an oval frame and the lower with the rack on its bottom bar. The upper wheel is the one driven joint, swung to and fro by the hand 1.6 rad each way
# (0.25 swings a second); the lower is driven only by the upper's teeth. They turn opposite ways, and both racks go the same way at the pitch speed, 6.4 cm to the radian,
# about 10.2 cm each way, the frame sliding on its ways. Generator: opencode-runs/batch9/gen115.py.
number: 115
slug: double-rack-two-wheels
name: Two equal wheels driving a double rack equally
brown: "Rotary motion of the toothed wheels produces rectilinear motion of the double rack and gives equal force and velocity to each side, both wheels being of equal size."
units: cm
sim:
  timestep: 0.0002
  integrator: implicitfast
  iterations: 100
  solver: PGS
  multiccd: true
  duration_s: 10
  floor: false
bodies:
  - id: wheel_a
    shape: part
    pos: [0, 0, 6.4]
    density: 7800
    friction: 0.1
    color: "#d9cfb6"
    pieces:
      - {kind: disc, center: [0, 6.4], radius: 5.55, inner: 0.6, y: [-0.8, 0.8]}
      - {kind: poly, points: [[-0.2646, 12.0571], [-1.9204, 11.7277], [-1.7002, 13.1582], [-1.0154, 13.2944]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-2.4094, 11.5252], [-3.813, 10.5873], [-4.157, 11.9931], [-3.5765, 12.381]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-4.1873, 10.213], [-5.1252, 8.8094], [-5.981, 9.9765], [-5.5931, 10.557]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-5.3277, 8.3204], [-5.6571, 6.6646], [-6.8944, 7.4154], [-6.7582, 8.1002]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-5.6571, 6.1354], [-5.3277, 4.4796], [-6.7582, 4.6998], [-6.8944, 5.3846]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-5.1252, 3.9906], [-4.1873, 2.587], [-5.5931, 2.243], [-5.981, 2.8235]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-3.813, 2.2127], [-2.4094, 1.2748], [-3.5765, 0.419], [-4.157, 0.8069]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-1.9204, 1.0723], [-0.2646, 0.7429], [-1.0154, -0.4944], [-1.7002, -0.3582]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[0.2646, 0.7429], [1.9204, 1.0723], [1.7002, -0.3582], [1.0154, -0.4944]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[2.4094, 1.2748], [3.813, 2.2127], [4.157, 0.8069], [3.5765, 0.419]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[4.1873, 2.587], [5.1252, 3.9906], [5.981, 2.8235], [5.5931, 2.243]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[5.3277, 4.4796], [5.6571, 6.1354], [6.8944, 5.3846], [6.7582, 4.6998]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[5.6571, 6.6646], [5.3277, 8.3204], [6.7582, 8.1002], [6.8944, 7.4154]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[5.1252, 8.8094], [4.1873, 10.213], [5.5931, 10.557], [5.981, 9.9765]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[3.813, 10.5873], [2.4094, 11.5252], [3.5765, 12.381], [4.157, 11.9931]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[1.9204, 11.7277], [0.2646, 12.0571], [1.0154, 13.2944], [1.7002, 13.1582]], y: [-0.8, 0.8], collide: 1}
  - id: wheel_b
    shape: part
    pos: [0, 0, -6.4]
    density: 7800
    friction: 0.1
    color: "#d9cfb6"
    pieces:
      - {kind: disc, center: [0, -6.4], radius: 5.55, inner: 0.6, y: [-0.8, 0.8]}
      - {kind: poly, points: [[0.8441, -0.8], [-0.8441, -0.8], [-0.3491, 0.56], [0.3491, 0.56]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-1.3632, -0.9033], [-2.9229, -1.5493], [-2.986, -0.1034], [-2.341, 0.1638]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-3.3629, -1.8433], [-4.5567, -3.0371], [-5.1683, -1.7254], [-4.6746, -1.2317]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-4.8507, -3.4771], [-5.4967, -5.0368], [-6.5638, -4.059], [-6.2966, -3.414]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-5.6, -5.5559], [-5.6, -7.2441], [-6.96, -6.7491], [-6.96, -6.0509]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-5.4967, -7.7632], [-4.8507, -9.3229], [-6.2966, -9.386], [-6.5638, -8.741]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-4.5567, -9.7629], [-3.3629, -10.9567], [-4.6746, -11.5683], [-5.1683, -11.0746]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-2.9229, -11.2507], [-1.3632, -11.8967], [-2.341, -12.9638], [-2.986, -12.6966]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-0.8441, -12.0], [0.8441, -12.0], [0.3491, -13.36], [-0.3491, -13.36]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[1.3632, -11.8967], [2.9229, -11.2507], [2.986, -12.6966], [2.341, -12.9638]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[3.3629, -10.9567], [4.5567, -9.7629], [5.1683, -11.0746], [4.6746, -11.5683]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[4.8507, -9.3229], [5.4967, -7.7632], [6.5638, -8.741], [6.2966, -9.386]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[5.6, -7.2441], [5.6, -5.5559], [6.96, -6.0509], [6.96, -6.7491]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[5.4967, -5.0368], [4.8507, -3.4771], [6.2966, -3.414], [6.5638, -4.059]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[4.5567, -3.0371], [3.3629, -1.8433], [4.6746, -1.2317], [5.1683, -1.7254]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[2.9229, -1.5493], [1.3632, -0.9033], [2.341, 0.1638], [2.986, -0.1034]], y: [-0.8, 0.8], collide: 2}
  - id: oval
    shape: part
    pos: [0, 0, 0]
    density: 2700
    friction: 0.1
    color: "#b8ad97"
    pieces:
      - {kind: poly, points: [[-16.3363, 13.6], [16.3363, 13.6], [16.3363, 14.6], [-16.3363, 14.6]], y: [-0.8, 0.8], collide: 2}   # the top bar
      - {kind: poly, points: [[-16.3363, -14.6], [16.3363, -14.6], [16.3363, -13.6], [-16.3363, -13.6]], y: [-0.8, 0.8], collide: 1}   # the bottom bar
      - {kind: poly, points: [[-15.8986, 13.6], [-14.2607, 13.6], [-14.6974, 12.4], [-15.4618, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-13.3853, 13.6], [-11.7474, 13.6], [-12.1842, 12.4], [-12.9486, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-10.8721, 13.6], [-9.2341, 13.6], [-9.6709, 12.4], [-10.4353, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-8.3588, 13.6], [-6.7209, 13.6], [-7.1576, 12.4], [-7.922, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-5.8455, 13.6], [-4.2076, 13.6], [-4.6443, 12.4], [-5.4087, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-3.3322, 13.6], [-1.6943, 13.6], [-2.1311, 12.4], [-2.8955, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-0.819, 13.6], [0.819, 13.6], [0.3822, 12.4], [-0.3822, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[1.6943, 13.6], [3.3322, 13.6], [2.8955, 12.4], [2.1311, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[4.2076, 13.6], [5.8455, 13.6], [5.4087, 12.4], [4.6443, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[6.7209, 13.6], [8.3588, 13.6], [7.922, 12.4], [7.1576, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[9.2341, 13.6], [10.8721, 13.6], [10.4353, 12.4], [9.6709, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[11.7474, 13.6], [13.3853, 13.6], [12.9486, 12.4], [12.1842, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[14.2607, 13.6], [15.8986, 13.6], [15.4618, 12.4], [14.6974, 12.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-14.642, -13.6], [-13.004, -13.6], [-13.4408, -12.4], [-14.2052, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-12.1287, -13.6], [-10.4908, -13.6], [-10.9275, -12.4], [-11.6919, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-9.6154, -13.6], [-7.9775, -13.6], [-8.4143, -12.4], [-9.1787, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-7.1021, -13.6], [-5.4642, -13.6], [-5.901, -12.4], [-6.6654, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-4.5889, -13.6], [-2.9509, -13.6], [-3.3877, -12.4], [-4.1521, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-2.0756, -13.6], [-0.4377, -13.6], [-0.8744, -12.4], [-1.6388, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[0.4377, -13.6], [2.0756, -13.6], [1.6388, -12.4], [0.8744, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[2.9509, -13.6], [4.5889, -13.6], [4.1521, -12.4], [3.3877, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[5.4642, -13.6], [7.1021, -13.6], [6.6654, -12.4], [5.901, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[7.9775, -13.6], [9.6154, -13.6], [9.1787, -12.4], [8.4143, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[10.4908, -13.6], [12.1287, -13.6], [11.6919, -12.4], [10.9275, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[13.004, -13.6], [14.642, -13.6], [14.2052, -12.4], [13.4408, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[15.5173, -13.6], [17.1552, -13.6], [16.7185, -12.4], [15.9541, -12.4]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-16.3363, 13.7], [-16.3363, 14.6], [-20.8479, 13.8854], [-20.5698, 13.0295]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-20.5698, 13.0295], [-20.8479, 13.8854], [-24.918, 11.8116], [-24.389, 11.0835]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-24.389, 11.0835], [-24.918, 11.8116], [-28.1479, 8.5817], [-27.4198, 8.0527]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-27.4198, 8.0527], [-28.1479, 8.5817], [-30.2217, 4.5116], [-29.3658, 4.2335]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-29.3658, 4.2335], [-30.2217, 4.5116], [-30.9363, 0.0], [-30.0363, 0.0]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-30.0363, 0.0], [-30.9363, 0.0], [-30.2217, -4.5116], [-29.3658, -4.2335]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-29.3658, -4.2335], [-30.2217, -4.5116], [-28.1479, -8.5817], [-27.4198, -8.0527]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-27.4198, -8.0527], [-28.1479, -8.5817], [-24.918, -11.8116], [-24.389, -11.0835]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-24.389, -11.0835], [-24.918, -11.8116], [-20.8479, -13.8854], [-20.5698, -13.0295]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-20.5698, -13.0295], [-20.8479, -13.8854], [-16.3363, -14.6], [-16.3363, -13.7]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[16.3363, 13.7], [16.3363, 14.6], [20.8479, 13.8854], [20.5698, 13.0295]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[20.5698, 13.0295], [20.8479, 13.8854], [24.918, 11.8116], [24.389, 11.0835]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[24.389, 11.0835], [24.918, 11.8116], [28.1479, 8.5817], [27.4198, 8.0527]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[27.4198, 8.0527], [28.1479, 8.5817], [30.2217, 4.5116], [29.3658, 4.2335]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[29.3658, 4.2335], [30.2217, 4.5116], [30.9363, 0.0], [30.0363, 0.0]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[30.0363, 0.0], [30.9363, 0.0], [30.2217, -4.5116], [29.3658, -4.2335]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[29.3658, -4.2335], [30.2217, -4.5116], [28.1479, -8.5817], [27.4198, -8.0527]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[27.4198, -8.0527], [28.1479, -8.5817], [24.918, -11.8116], [24.389, -11.0835]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[24.389, -11.0835], [24.918, -11.8116], [20.8479, -13.8854], [20.5698, -13.0295]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[20.5698, -13.0295], [20.8479, -13.8854], [16.3363, -14.6], [16.3363, -13.7]], y: [-0.8, 0.8], collide: 0}
      - {kind: rod, from: [-30.9363, 0, 0], to: [-32.5363, 0, 0], radius: 0.9, collide: 0, color: "#8f8a80"}   # the lugs the frame is held by
      - {kind: rod, from: [30.9363, 0, 0], to: [32.5363, 0, 0], radius: 0.9, collide: 0, color: "#8f8a80"}
  - id: frame
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#cfc6b4"
    pieces:
      - {kind: rod, from: [0, -1.4, 6.4], to: [0, 3.0, 6.4], radius: 0.6, color: "#8f8a80"}   # the shafts
      - {kind: rod, from: [0, -1.4, -6.4], to: [0, 3.0, -6.4], radius: 0.6, color: "#8f8a80"}
      - {kind: poly, points: [[-1.4, -18.6], [1.4, -18.6], [1.0, 6.4], [-1.0, 6.4]], y: [2.0, 3.0], collide: 0}   # their standard, behind
      - {kind: poly, points: [[-60, -18.6], [60, -18.6], [60, -17.4], [-60, -17.4]], y: [-3, 3], color: "#b9b09c", collide: 0}   # the bench
      - {kind: poly, points: [[-56, -17.4], [-53, -17.4], [-53, -14.9], [-56, -14.9]], y: [-1.6, 1.6], collide: 0}   # the ways' posts
      - {kind: poly, points: [[53, -17.4], [56, -17.4], [56, -14.9], [53, -14.9]], y: [-1.6, 1.6], collide: 0}
      - {kind: poly, points: [[-56, -14.9], [56, -14.9], [56, -14.65], [-56, -14.65]], y: [-1.6, 1.6], collide: 0, color: "#a39a86"}   # the way the oval rides on
joints:
  - {id: j_a, type: hinge, body: wheel_a, axis: [0, 1, 0], damping: 0.002}   # the one driven joint; + : clockwise
  - {id: j_b, type: hinge, body: wheel_b, axis: [0, 1, 0], damping: 0.002}
  - {id: j_f, type: slide, body: oval, axis: [1, 0, 0], damping: 0.05}   # + : to the right
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_a, kind: velocity, rpm: 0, swing: {amplitude: 1.6, hz: 0.25}, kv: 5.0, max_torque: 20}
checks:
  - {type: follow, out: j_f, in: j_a, expect: 0.064, tol: 0.0019, min_r2: 0.995, settle_s: 0.5, window_s: 3.0}   # the frame goes as the pitch circle
  - {type: follow, out: j_f, in: j_a, expect: 0.064, tol: 0.0019, min_r2: 0.995, settle_s: 4.5, window_s: 3.0}
  - {type: follow, out: j_b, in: j_a, expect: -1.0, tol: 0.03, min_r2: 0.995, settle_s: 0.5, window_s: 3.0}   # the lower wheel turns the other way, as fast
  - {type: position, joint: j_f, min: -11.04, max: 11.04, settle_s: 0.0, window_s: 9}
camera: {target: [0, 0, -4], position: [0, -112.0, -4], fov: 34}
display:
  output: j_f
  labels: {j_a: "Upper wheel (driver)", j_b: "Lower wheel", j_f: "Double rack"}
  proof: {label: "Upper wheel's teeth out of contact", sub: "the wheel turns but the frame stands"}

