# No. 30, Rectangular gears (Brown 1868, p. 3).
#
# "30. Rectangular gears. These produce a rotary motion of the driven gear at a varying speed.
#  They were used on a printing-press, the type of which were placed on a rectangular roller."
#
# The plate: two square gears in mesh, seen face-on. The LEFT one is the smaller, standing on a
# corner (a diamond with rounded corners); the RIGHT one the larger, sitting on its side; teeth of
# the same linear pitch run all round each square, five to a side on the smaller, seven on the
# bigger. So 20 and 28 teeth in all, hence 1 unit = 1 cm and tooth pitch 5.0 cm:
#
#   pitch   p   = 5.0        (counted on the plate: ~5 teeth on a left side, ~7 on a right)
#   small   z1 = 20 (5/side) -> side s1 = z1·p/4 + (2 − π/2)·f1 = 26.72  (fillet f1 = 4.0)
#   large   z2 = 28 (7/side) -> side s2 = 35 + (2 − π/2)·f2    = 40.58  (fillet f2 = 13.0)
#   half sides h1 = 13.36, h2 = 20.29; corner radii √2·h − (√2−1)·f: 17.23 and 23.31.
#
# WHY THE LARGE SQUARE MUST BE SO MUCH ROUNDER (Brown draws it so too): with fixed centres, the
# pair alternates between two extremes — the small square's corner against the large one's flat
# (sum 17.23 + 20.29 = 37.52) and the small one's flat against the large one's corner
# (13.36 + 23.31 = 36.67) — and, because one square of the driven runs at a different rate, corners
# meet corners; the fillets must keep r1 + r2 inside reach of 6 cm of tooth (addenda 3 + 3) at all
# times. The corner radius √2·h − (√2−1)·f falls (√2−1)-for-one with the fillet, so pushing
# f2 up to f1 + (h2 − h1) + slide equalises the two extreme sums: f2 = 13.0, centres a = 41.5:
# corner-corner leaves a 0.96 cm tip-to-root margin, and every other phase keeps the tooth bands
# (pitch − 3 .. pitch + 3) engaged. The teeth therefore pass through each other's spaces deeper at
# some phases than others — which is what makes the driven speed swing round the mean, exactly
# what Brown says these gears are for.
#
# WHERE THE TEETH MUST BE EASED (the 45° corner beats): where a fillet turns the pitch curve a right
# angle in a tooth and a half, an opposing tooth arrives nearly head-on against another and the two
# jam. So each gear.s corner teeth are eased in corner_ease (generator src/geom/square.ts): the
# DRIVEN's corner teeth sink to a 0.5 mm pancake (ease 1.0), leaving valleys the driver's corner
# threads through; the DRIVER keeps its corner teeth 70% tall (ease 0.3) so they still reach the
# driven's flat band — at 0.35 nothing touches at all, at 0.25 the corners wedge again. The driver's
# teeth are also cut narrow (1.9 at root, 1.3 at tip) so the head-on beats pass instead of jamming.
#
# No powder-burned coupling: only the left (smaller) gear's shaft is motor-driven. The right gear
# is turned ONLY by tooth-on-tooth contact (one convex hull per tooth, the generator
# src/geom/square.ts: hulls laid on each rounded-square pitch curve at one pitch).
#
# Expected ratio, from the tooth counts (hinge/hinge, rad/rad): over whole turns the driver's teeth
# pass the mesh zone one by one and the driven receives one pitch each, so
# ω2/ω1 = -z1/z2 = -20/28 = -0.7143 exactly. The instantaneous ratio swings because the effective
# radii change round the cycle: ~0.85 when the driven carries it on its flat against the driver's
# corner (17.23/20.29) down to ~0.57 when the driver carries it on its flat against the driven's
# corner (13.36/23.31) — with the eased corner beats, the measured swing works out past that band
# and the ratio_range check takes the measured extremes as read.
number: 30
slug: rectangular-gears
name: Rectangular gears
brown: "Rectangular gears. These produce a rotary motion of the driven gear at a varying speed. They were used on a printing-press, the type of which were placed on a rectangular roller."
units: cm
sim:
  timestep: 0.0002
  integrator: implicitfast
  iterations: 100
  solver: CG
  multiccd: true
  duration_s: 7
  floor: false
bodies:
  # The smaller driver on the left (x = 0), the larger driven square on the right (x = 41.5), as the plate.
  - {id: g1, shape: assembly, pos: [0, 0, 22], color: "#e4d9bf"}
  - {id: g2, shape: assembly, pos: [41.5, 0, 22], color: "#e8dec6"}
  # The two shaft stubs, drawn as fixed rods: each gear turns about its own rod.
  - {id: stubs, shape: frame, rods: [{from: [0, -4.4, 22], to: [0, 4.4, 22], radius: 0.75}, {from: [41.5, -4.4, 22], to: [41.5, 4.4, 22], radius: 0.75}], color: "#8f8a80"}
joints:
  - {id: j_g1, type: hinge, body: g1, axis: [0, 1, 0], damping: 0.0005}
  - {id: j_g2, type: hinge, body: g2, axis: [0, 1, 0], damping: 0.08}  # a bearing's load on the driven shaft
squares:
  # phase pi/4 stands the driver on its corner (a corner points at the driven, as the plate draws);
  # driven at phase 0 sits on its side, flats facing ±x, gap at each flat's mid where a corner arrives
  - {id: sq1, body: g1, pos: [0, 0, 0], teeth: 20, pitch: 5.0, fillet: 4.0, addendum: 3.0, dedendum: 3.0, tooth_width: 1.9, tip_width: 1.3, width: 2.6, phase: 0.7853981633974483, corner_ease: 0.3}
  - {id: sq2, body: g2, pos: [0, 0, 0], teeth: 28, pitch: 5.0, fillet: 13.0, addendum: 3.0, dedendum: 3.0, tip_width: 1.15, width: 2.6, phase: 0, corner_ease: 1.0}
contact: {solref: [0.002, 1], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_g1, kind: velocity, rpm: 30, kv: 3, max_torque: 20}
checks:
  # Tooth counts: ω2/ω1 = -20/28 = -0.7143 over whole driver turns (window 4.0 s = exactly 2 of
  # them at 30 rpm, so the per-tooth ripple cancels in the mean). Measured means landed within
  # ~2-4% of it (the eased corner beats let the pair slip a hair through the extreme passes), so
  # the tolerance is taken from measurement.
  - {type: ratio, out: j_g2, in: j_g1, expect: -0.714286, tol: 0.02, settle_s: 2.4, window_s: 4}
  # THE point of the movement: the driven speed rises and falls all the way round. The geometry
  # gives extremes at ω2/ω1 = corner/flat = 17.23/20.29 = 0.849 (high) and flat/corner =
  # 13.36/23.31 = 0.573 (low); with the eased corner beats the measured means over short slices
  # land at 0.868 and 0.578 (a swing of 0.29); the check bounds them and asks for a swing of 0.2.
  - {type: ratio_range, out: j_g2, in: j_g1, min: -0.92, max: -0.53, min_swing: 0.2, settle_s: 2.4, window_s: 4}
  - {type: turning, joint: j_g2, direction: -1, min_mean: 1.5, slow: 0.3, min_fraction: 0.93, settle_s: 2.4, window_s: 4}
  - {type: penetration, max: 0.001, settle_s: 2.4}
camera: {target: [23.8, 0, 22], position: [23.8, -120, 24], fov: 34}
display:
  output: j_g2
  labels: {j_g1: "Driver (20 teeth)", j_g2: "Driven (28 teeth)"}
  expect: {default: -0.7143}
  proof: {label: "Teeth out of contact", sub: "the driver turns alone: the 28-tooth square stands still"}
