# No. 139 (Brown 1868): "The internal rack, carried by the rectangular frame, is free to slide up and down within it for a certain distance, so that the pinion can gear with either side of the rack. Continuous circular motion of the pinion is made to produce reciprocating rectilinear motion of rectangular frame."
#
# Model (cm, no gravity: the rack is held in gear by the tooth pressure): a 12-tooth pinion (module 0.8, pitch radius 4.800000000000001) on a fixed shaft is the one driven joint (18 turns a minute, clockwise in the view). It gears inside a stadium-shaped rack of 40 teeth
# (8 pitches of straight side, round ends of pitch radius 9.6), carried by a rectangular frame; the rack slides up and down in the frame 9.6 cm (the centre distance each way) and the frame slides to and fro. On the top side the pinion drives the
# frame forward at one pinion radius per radian; at the end it rolls round the round end, lifting the rack (9.6 cm) by the teeth alone; on the bottom side the frame comes back. Generator: opencode-runs/batch10/gen139.py.
number: 139
slug: internal-rack-frame
name: A pinion working an internal rack in a sliding frame
brown: "The internal rack, carried by the rectangular frame, is free to slide up and down within it for a certain distance, so that the pinion can gear with either side of the rack. Continuous circular motion of the pinion is made to produce reciprocating rectilinear motion of rectangular frame."
units: cm
sim:
  timestep: 0.0002
  integrator: implicitfast
  iterations: 100
  solver: PGS
  multiccd: true
  duration_s: 18.0
  floor: false
  gravity: 0
bodies:
  - id: pinion
    shape: part
    pos: [0, 0, 0]
    density: 7800
    friction: 0.1
    color: "#d9cfb6"
    pieces:
      - {kind: disc, center: [0, 0], radius: 3.95, inner: 0.6, y: [-0.8, 0.8]}
      - {kind: poly, points: [[-0.2199, 4.0822], [-1.8506, 3.6452], [-1.7245, 5.087], [-1.0501, 5.2677]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-2.2316, 3.4253], [-3.4253, 2.2316], [-4.0369, 3.5432], [-3.5432, 4.0369]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-3.6452, 1.8506], [-4.0822, 0.2199], [-5.2677, 1.0501], [-5.087, 1.7245]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-4.0822, -0.2199], [-3.6452, -1.8506], [-5.087, -1.7245], [-5.2677, -1.0501]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-3.4253, -2.2316], [-2.2316, -3.4253], [-3.5432, -4.0369], [-4.0369, -3.5432]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[-1.8506, -3.6452], [-0.2199, -4.0822], [-1.0501, -5.2677], [-1.7245, -5.087]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[0.2199, -4.0822], [1.8506, -3.6452], [1.7245, -5.087], [1.0501, -5.2677]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[2.2316, -3.4253], [3.4253, -2.2316], [4.0369, -3.5432], [3.5432, -4.0369]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[3.6452, -1.8506], [4.0822, -0.2199], [5.2677, -1.0501], [5.087, -1.7245]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[4.0822, 0.2199], [3.6452, 1.8506], [5.087, 1.7245], [5.2677, 1.0501]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[3.4253, 2.2316], [2.2316, 3.4253], [3.5432, 4.0369], [4.0369, 3.5432]], y: [-0.8, 0.8], collide: 1}
      - {kind: poly, points: [[1.8506, 3.6452], [0.2199, 4.0822], [1.0501, 5.2677], [1.7245, 5.087]], y: [-0.8, 0.8], collide: 1}
  - id: frame
    shape: part
    pos: [0, 0, 0]
    mass: 0.3
    color: "#cfc6b4"
    pieces:
      - {kind: poly, points: [[-24.1531, -18.9], [-21.9531, -18.9], [-21.9531, 14.1], [-24.1531, 14.1]], y: [-1.5, 1.5], collide: 0}
      - {kind: poly, points: [[21.9531, -18.9], [24.1531, -18.9], [24.1531, 14.1], [21.9531, 14.1]], y: [-1.5, 1.5], collide: 0}
      - {kind: poly, points: [[-24.1531, 11.9], [24.1531, 11.9], [24.1531, 14.1], [-24.1531, 14.1]], y: [-1.5, 1.5], collide: 0}
      - {kind: poly, points: [[-24.1531, -18.9], [24.1531, -18.9], [24.1531, -16.7], [-24.1531, -16.7]], y: [-1.5, 1.5], collide: 0}
      - {kind: poly, points: [[-35.1531, -3.0], [-24.1531, -3.0], [-24.1531, 3.0], [-35.1531, 3.0]], y: [-1.1, 1.1], collide: 0, color: "#a89a7e"}
      - {kind: poly, points: [[24.1531, -3.0], [35.1531, -3.0], [35.1531, 3.0], [24.1531, 3.0]], y: [-1.1, 1.1], collide: 0, color: "#a89a7e"}
      - {kind: disc, center: [-13.1719, -21.5], radius: 2.6, inner: 0.9, y: [-1.2, 1.2], color: "#a89a7e"}
      - {kind: disc, center: [13.1719, -21.5], radius: 2.6, inner: 0.9, y: [-1.2, 1.2], color: "#a89a7e"}
  - id: rack
    shape: part
    pos: [0.0, 0, -4.8]
    mount: frame
    mass: 0.3
    friction: 0.1
    color: "#b8ad97"
    pieces:
      - {kind: poly, points: [[-10.0531, 5.6], [10.0531, 5.6], [10.0531, 6.5], [-10.0531, 6.5]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-10.0531, -16.1], [10.0531, -16.1], [10.0531, -15.2], [-10.0531, -15.2]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[10.0531, 5.6], [12.7448, 5.2456], [12.9778, 6.115], [10.0531, 6.5]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[12.7448, 5.2456], [15.2531, 4.2067], [15.7031, 4.9861], [12.9778, 6.115]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[15.2531, 4.2067], [17.407, 2.5539], [18.0434, 3.1903], [15.7031, 4.9861]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[17.407, 2.5539], [19.0598, 0.4], [19.8392, 0.85], [18.0434, 3.1903]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[19.0598, 0.4], [20.0987, -2.1083], [20.9681, -1.8753], [19.8392, 0.85]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[20.0987, -2.1083], [20.4531, -4.8], [21.3531, -4.8], [20.9681, -1.8753]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[20.4531, -4.8], [20.0987, -7.4917], [20.9681, -7.7247], [21.3531, -4.8]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[20.0987, -7.4917], [19.0598, -10.0], [19.8392, -10.45], [20.9681, -7.7247]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[19.0598, -10.0], [17.407, -12.1539], [18.0434, -12.7903], [19.8392, -10.45]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[17.407, -12.1539], [15.2531, -13.8067], [15.7031, -14.5861], [18.0434, -12.7903]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[15.2531, -13.8067], [12.7448, -14.8456], [12.9778, -15.715], [15.7031, -14.5861]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[12.7448, -14.8456], [10.0531, -15.2], [10.0531, -16.1], [12.9778, -15.715]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-10.0531, 5.6], [-12.7448, 5.2456], [-12.9778, 6.115], [-10.0531, 6.5]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-12.7448, 5.2456], [-15.2531, 4.2067], [-15.7031, 4.9861], [-12.9778, 6.115]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-15.2531, 4.2067], [-17.407, 2.5539], [-18.0434, 3.1903], [-15.7031, 4.9861]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-17.407, 2.5539], [-19.0598, 0.4], [-19.8392, 0.85], [-18.0434, 3.1903]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-19.0598, 0.4], [-20.0987, -2.1083], [-20.9681, -1.8753], [-19.8392, 0.85]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-20.0987, -2.1083], [-20.4531, -4.8], [-21.3531, -4.8], [-20.9681, -1.8753]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-20.4531, -4.8], [-20.0987, -7.4917], [-20.9681, -7.7247], [-21.3531, -4.8]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-20.0987, -7.4917], [-19.0598, -10.0], [-19.8392, -10.45], [-20.9681, -7.7247]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-19.0598, -10.0], [-17.407, -12.1539], [-18.0434, -12.7903], [-19.8392, -10.45]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-17.407, -12.1539], [-15.2531, -13.8067], [-15.7031, -14.5861], [-18.0434, -12.7903]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-15.2531, -13.8067], [-12.7448, -14.8456], [-12.9778, -15.715], [-15.7031, -14.5861]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-12.7448, -14.8456], [-10.0531, -15.2], [-10.0531, -16.1], [-12.9778, -15.715]], y: [-0.8, 0.8], collide: 0}
      - {kind: poly, points: [[-10.8721, 5.6], [-9.2341, 5.6], [-9.6709, 4.4], [-10.4353, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-8.3588, 5.6], [-6.7209, 5.6], [-7.1576, 4.4], [-7.922, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-5.8455, 5.6], [-4.2076, 5.6], [-4.6443, 4.4], [-5.4087, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-3.3322, 5.6], [-1.6943, 5.6], [-2.1311, 4.4], [-2.8955, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-0.819, 5.6], [0.819, 5.6], [0.3822, 4.4], [-0.3822, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[1.6943, 5.6], [3.3322, 5.6], [2.8955, 4.4], [2.1311, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[4.2076, 5.6], [5.8455, 5.6], [5.4087, 4.4], [4.6443, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[6.7209, 5.6], [8.3588, 5.6], [7.922, 4.4], [7.1576, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[9.2341, 5.6], [10.8721, 5.6], [10.4353, 4.4], [9.6709, 4.4]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[11.9538, 5.4576], [13.5359, 5.0337], [12.8034, 3.9876], [12.0651, 4.1854]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[14.5439, 4.6161], [15.9623, 3.7972], [14.9841, 2.9763], [14.3221, 3.3585]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[16.8279, 3.133], [17.9861, 1.9748], [16.8287, 1.4351], [16.2882, 1.9756]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[18.6503, 1.1092], [19.4692, -0.3092], [18.2116, -0.531], [17.8294, 0.131]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[19.8868, -1.3172], [20.3107, -2.8993], [19.0385, -2.788], [18.8407, -2.0497]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[20.4531, -3.981], [20.4531, -5.619], [19.2531, -5.1822], [19.2531, -4.4178]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[20.3107, -6.7007], [19.8868, -8.2828], [18.8407, -7.5503], [19.0385, -6.812]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[19.4692, -9.2908], [18.6503, -10.7092], [17.8294, -9.731], [18.2116, -9.069]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[17.9861, -11.5748], [16.8279, -12.733], [16.2882, -11.5756], [16.8287, -11.0351]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[15.9623, -13.3972], [14.5439, -14.2161], [14.3221, -12.9585], [14.9841, -12.5763]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[13.5359, -14.6337], [11.9538, -15.0576], [12.0651, -13.7854], [12.8034, -13.5876]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[10.8721, -15.2], [9.2341, -15.2], [9.6709, -14.0], [10.4353, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[8.3588, -15.2], [6.7209, -15.2], [7.1576, -14.0], [7.922, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[5.8455, -15.2], [4.2076, -15.2], [4.6443, -14.0], [5.4087, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[3.3322, -15.2], [1.6943, -15.2], [2.1311, -14.0], [2.8955, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[0.819, -15.2], [-0.819, -15.2], [-0.3822, -14.0], [0.3822, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-1.6943, -15.2], [-3.3322, -15.2], [-2.8955, -14.0], [-2.1311, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-4.2076, -15.2], [-5.8455, -15.2], [-5.4087, -14.0], [-4.6443, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-6.7209, -15.2], [-8.3588, -15.2], [-7.922, -14.0], [-7.1576, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-9.2341, -15.2], [-10.8721, -15.2], [-10.4353, -14.0], [-9.6709, -14.0]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-11.9538, -15.0576], [-13.5359, -14.6337], [-12.8034, -13.5876], [-12.0651, -13.7854]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-14.5439, -14.2161], [-15.9623, -13.3972], [-14.9841, -12.5763], [-14.3221, -12.9585]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-16.8279, -12.733], [-17.9861, -11.5748], [-16.8287, -11.0351], [-16.2882, -11.5756]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-18.6503, -10.7092], [-19.4692, -9.2908], [-18.2116, -9.069], [-17.8294, -9.731]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-19.8868, -8.2828], [-20.3107, -6.7007], [-19.0385, -6.812], [-18.8407, -7.5503]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-20.4531, -5.619], [-20.4531, -3.981], [-19.2531, -4.4178], [-19.2531, -5.1822]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-20.3107, -2.8993], [-19.8868, -1.3172], [-18.8407, -2.0497], [-19.0385, -2.788]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-19.4692, -0.3092], [-18.6503, 1.1092], [-17.8294, 0.131], [-18.2116, -0.531]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-17.9861, 1.9748], [-16.8279, 3.133], [-16.2882, 1.9756], [-16.8287, 1.4351]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-15.9623, 3.7972], [-14.5439, 4.6161], [-14.3221, 3.3585], [-14.9841, 2.9763]], y: [-0.8, 0.8], collide: 2}
      - {kind: poly, points: [[-13.5359, 5.0337], [-11.9538, 5.4576], [-12.0651, 4.1854], [-12.8034, 3.9876]], y: [-0.8, 0.8], collide: 2}
  - id: stand
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#cfc6b4"
    pieces:
      - {kind: rod, from: [0, -1.0, 0], to: [0, 4.6, 0], radius: 0.6, color: "#8f8a80"}   # the pinion's shaft
      - {kind: poly, points: [[-49.1531, -26.3], [49.1531, -26.3], [49.1531, -24.1], [-49.1531, -24.1]], y: [-3.5, 3.5], collide: 0, color: "#b9b09c"}
      - {kind: poly, points: [[-49.1531, -26.3], [49.1531, -26.3], [49.1531, 16.6], [-49.1531, 16.6]], y: [3.6, 4.4], collide: 0, color: "#d8d0bd"}
joints:
  - {id: j_s, type: hinge, body: pinion, axis: [0, 1, 0], damping: 0.002}   # the one driven joint; + : clockwise
  - {id: j_x, type: slide, body: frame, axis: [1, 0, 0], damping: 0.05}   # the frame on its rails; + : to the right
  - {id: j_z, type: slide, body: rack, axis: [0, 0, 1], range: [-0.02, 9.62], damping: 0.05, frictionloss: 0.08}   # the rack in the frame; + : up
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_s, kind: velocity, rpm: 18.0, kv: 1.0, max_torque: 0.02}
checks:
  - {type: follow, out: j_x, in: j_s, expect: 0.048, tol: 0.0024, min_r2: 0.995, settle_s: 0.5, window_s: 0.7}   # top side of the rack: the frame goes forward, one pinion radius per radian
  - {type: follow, out: j_x, in: j_s, expect: -0.048, tol: 0.0024, min_r2: 0.995, settle_s: 3.4, window_s: 1.5}   # bottom side of the rack: the frame goes back, one pinion radius per radian
  - {type: follow, out: j_x, in: j_s, expect: 0.048, tol: 0.0024, min_r2: 0.995, settle_s: 7.2, window_s: 1.6}   # top side of the rack: the frame goes forward, one pinion radius per radian
  - {type: follow, out: j_x, in: j_s, expect: -0.048, tol: 0.0024, min_r2: 0.995, settle_s: 11.2, window_s: 1.6}   # bottom side of the rack: the frame goes back, one pinion radius per radian
  - {type: follow, out: j_x, in: j_s, expect: 0.048, tol: 0.0024, min_r2: 0.995, settle_s: 15.2, window_s: 1.6}   # top side of the rack: the frame goes forward, one pinion radius per radian
  - {type: follow, out: j_z, in: j_s, expect: 0.0472, tol: 0.0028, min_r2: 0.99, settle_s: 1.9033, window_s: 0.3333}   # on a round end the rack climbs as the pinion rolls round it
  - {type: follow, out: j_z, in: j_s, expect: -0.0472, tol: 0.0028, min_r2: 0.99, settle_s: 5.8333, window_s: 0.3333}   # on a round end the rack falls as the pinion rolls round it
  - {type: follow, out: j_z, in: j_s, expect: 0.0472, tol: 0.0028, min_r2: 0.99, settle_s: 9.6833, window_s: 0.3333}   # on a round end the rack climbs as the pinion rolls round it
  - {type: position, joint: j_x, min: -15.6531, max: 15.6531, settle_s: 0.0, window_s: 17.0}
  - {type: position, joint: j_z, min: -0.1, max: 9.7, settle_s: 0.0, window_s: 17.0}
  - {type: penetration, max: 0.001, settle_s: 0.5}
camera: {target: [0, 0, -9.0], position: [0, -120.0, -9.0], fov: 34}
display:
  output: j_x
  labels: {j_s: "Pinion (driver)", j_x: "Frame", j_z: "Rack"}
  proof: {label: "Teeth out of contact", sub: "the pinion turns but the frame stands still"}

