# No. 424 (Brown 1868): "Root's double-reciprocating or square piston engine. The "cylinder," A, of this engine is of oblong square form and
# contains two pistons, B and C, the former working horizontally, and the latter working vertically within it; the piston, C, is connected
# with the wrist, a, of the crank on the main shaft, b. The ports for the admission of steam are shown black. The two pistons produce the
# rotation of the crank without dead points."
# Model (cm, Brown's section, no gravity: the engine may lie any way; only the back of the cut cylinder is drawn). The "cylinder" A is an
# oblong box 15.4 x 11 cm inside. The piston B is an open square frame (11 cm) sliding across in A (4.4 cm stroke); the
# piston C (9.8 x 5.4 cm) slides up and down inside B (4.4 cm stroke) and is pinned at its middle to the crank's wrist a, 2.2 cm
# from the main shaft b at the middle of A: so B follows the wrist across and C follows it up and down. The steam (the one input) is let in
# by four ports shown black: at A's two ends (behind and in front of B) and in B's top and bottom (above and below C). Each is a push of
# 10 N on its piston (a press-only actuator on the piston's slide; C's reacts on B), open for the half turn in which it drives the crank
# forward, timed by the shaft's own turn (driver feet.ports); the shaft is free against a load (0.05 N m s). B's push turns the crank
# with F R |sin|, C's with F R |cos|: one is at full lever when the other is at its dead point.
# Generator: opencode-runs/steam/gen424.py.
number: 424
slug: roots-square-piston-engine
name: Root's square piston engine
brown: "Root's double-reciprocating or square piston engine. The \"cylinder,\" A, of this engine is of oblong square form and contains two pistons, B and C, the former working horizontally, and the latter working vertically within it; the piston, C, is connected with the wrist, a, of the crank on the main shaft, b. The ports for the admission of steam are shown black. The two pistons produce the rotation of the crank without dead points."
units: cm
sim:
  timestep: 0.0005
  integrator: implicitfast
  iterations: 100
  solver: PGS
  duration_s: 10
  floor: false
  gravity: 0
bodies:
  - id: piston_B
    shape: part
    pos: [1.6853, 0, 7.3]
    density: 7200
    color: "#a39d90"
    pieces:
      - {kind: poly, points: [[-3.8147, 12.2], [7.1853, 12.2], [7.1853, 12.8], [-3.8147, 12.8]], y: [0, 2.2], collide: 0}
      - {kind: poly, points: [[-3.8147, 1.8], [7.1853, 1.8], [7.1853, 2.4], [-3.8147, 2.4]], y: [0, 2.2], collide: 0}
      - {kind: poly, points: [[-3.8147, 2.4], [-3.2147, 2.4], [-3.2147, 12.2], [-3.8147, 12.2]], y: [0, 2.2], collide: 0}
      - {kind: poly, points: [[6.5853, 2.4], [7.1853, 2.4], [7.1853, 12.2], [6.5853, 12.2]], y: [0, 2.2], collide: 0}
      - {kind: poly, points: [[0.1853, 11.95], [3.1853, 11.95], [3.1853, 12.2], [0.1853, 12.2]], y: [-0.25, 2.2], collide: 0, color: "#222222"}   # the port in B's top (steam for C)
      - {kind: poly, points: [[0.1853, 2.4], [3.1853, 2.4], [3.1853, 2.65], [0.1853, 2.65]], y: [-0.25, 2.2], collide: 0, color: "#222222"}   # the port in B's bottom
  - id: piston_C
    shape: part
    pos: [1.6853, 0, 5.8859]
    mount: piston_B
    density: 7200
    color: "#b8ad97"
    pieces:
      - {kind: poly, points: [[-3.1847, 3.1859], [6.5553, 3.1859], [6.5553, 8.5859], [-3.1847, 8.5859]], y: [0.1, 2.1], collide: 0}   # the piston C
  - id: crank
    shape: part
    pos: [0, 0, 7.3]
    density: 7800
    color: "#6f6a60"
    pieces:
      - {kind: disc, center: [0, 7.3], radius: 0.6, y: [-1.0, 2.6], collide: 0}   # the main shaft b
      - {kind: rod, from: [0, -0.6, 7.3], to: [1.6853, -0.6, 5.8859], radius: 0.35, collide: 0}   # the crank (dotted in Brown's figure, behind C)
      - {kind: disc, center: [1.6853, 5.8859], radius: 0.45, y: [-0.9, 0.3], collide: 0, color: "#4a463f"}   # the wrist a, in C
  - id: frame
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#cfc6b4"
    pieces:
      - {kind: poly, points: [[-8.5, 12.8], [8.5, 12.8], [8.5, 13.6], [-8.5, 13.6]], y: [-0.2, 2.4], collide: 0}
      - {kind: poly, points: [[-8.5, 1], [8.5, 1], [8.5, 1.8], [-8.5, 1.8]], y: [-0.2, 2.4], collide: 0}
      - {kind: poly, points: [[-8.5, 1.8], [-7.7, 1.8], [-7.7, 12.8], [-8.5, 12.8]], y: [-0.2, 2.4], collide: 0}
      - {kind: poly, points: [[7.7, 1.8], [8.5, 1.8], [8.5, 12.8], [7.7, 12.8]], y: [-0.2, 2.4], collide: 0}
      - {kind: poly, points: [[-9.1, 0.1], [9.1, 0.1], [9.1, 1], [-9.1, 1]], y: [-0.6, 2.8], collide: 0}   # the bed
      - {kind: poly, points: [[-8.5, 1], [8.5, 1], [8.5, 13.6], [-8.5, 13.6]], y: [2.4, 2.8], collide: 0, color: "#bdb4a2"}   # the cylinder's back
      - {kind: poly, points: [[-7.95, 5.8], [-7.7, 5.8], [-7.7, 8.8], [-7.95, 8.8]], y: [-0.25, 2.4], collide: 0, color: "#222222"}   # the port at the left end of A (steam for B)
      - {kind: poly, points: [[7.7, 5.8], [7.95, 5.8], [7.95, 8.8], [7.7, 8.8]], y: [-0.25, 2.4], collide: 0, color: "#222222"}   # the port at the right end of A
      - {kind: disc, center: [0, 7.3], radius: 0.9, y: [-1.2, 2.8], collide: 0, color: "#8f8a80"}   # the bearing of the shaft b, in the cylinder's cover
joints:
  - {id: j_b, type: hinge, body: crank, axis: [0, -1, 0], damping: 0.05}   # the main shaft b; + : anticlockwise as drawn
  - {id: j_Bx, type: slide, body: piston_B, axis: [1, 0, 0], range: [-4.1853, 0.8147], damping: 0.001}   # B across in A; + : right
  - {id: j_Cz, type: slide, body: piston_C, axis: [0, 0, 1], range: [-1.0859, 3.9141], damping: 0.001}   # C up and down in B; + : up
pins:
  - {id: wrist_a, a: crank, b: piston_C, at: [1.6853, 0, 5.8859]}   # the wrist a, at C's middle
driver:
  joint: j_b
  kind: feet
  max_torque: 1.0
  feet:
    force: 10
    timed: {joint: j_b, gain: 1, offset: 0.6981}   # x = the crank's angle from the right, anticlockwise
    ports:
      - {joint: j_Bx, sign: 1, open: [180, 360]}   # the port at A's left end: steam behind B, pushing it right
      - {joint: j_Bx, sign: -1, open: [0, 180]}   # the port at A's right end: pushing B left
      - {joint: j_Cz, sign: 1, open: [270, 450]}   # the port in B's bottom: steam under C, pushing it up
      - {joint: j_Cz, sign: -1, open: [90, 270]}   # the port in B's top: pushing C down
checks:
  - {type: monotonic, joint: j_b, direction: 1, max_back: 0.05, settle_s: 0.0, window_s: 9.5}
  - {type: turning, joint: j_b, direction: 1, min_mean: 3.0, min_fraction: 0.9, settle_s: 2.0, window_s: 7.5}
  - {type: amplitude, joint: j_Bx, min: 0.0213, max: 0.0227, sustain: 0.95, settle_s: 2.0, window_s: 7.5}   # B across by the crank's radius either way
  - {type: amplitude, joint: j_Cz, min: 0.0213, max: 0.0227, sustain: 0.95, settle_s: 2.0, window_s: 7.5}   # C up and down by the same
camera: {target: [0, 0, 4.8], position: [0, -68, 4.8], fov: 22}
display:
  output: j_b
  labels: {j_b: "Main shaft b", j_Bx: "Piston B (across)", j_Cz: "Piston C (up and down)"}
