# No. 387 (Brown 1868): "Self-adjusting step-ladder for wharfs at which there are rise and fall of tide. The steps are pivoted at one edge into wooden bars forming string-pieces, and their other edge is supported by rods suspended from bars forming hand-rails. The steps remain horizontal whatever position the ladder assumes."
#
# Model (cm, gravity on): the string-pieces and the hand-rails (100 cm, a pair of each) are pivoted to the wharf's post 30 cm apart, and at
# their outer ends to a post that stands in a boat; string-piece, hand-rail and the two posts make a parallelogram, so the outer post stays
# upright. Each of the 6 steps is pivoted at one edge into the string-pieces; a rod hung from the hand-rail directly above that pivot holds its
# other edge, so pivot, step edge and rod top make a triangle with one upright side of 30 cm: the step stays level. The tide (the one driven
# joint: the boat, floating, rises and falls ±20 cm about half tide at 0.1 Hz) carries the ladder's outer post on its floor (a real
# contact; the post's foot slides on it as the ladder swings): at high water the ladder is level with the wharf, at low it slopes 23 degrees.
# Generator: opencode-runs/batch13/gen387.py.
number: 387
slug: self-adjusting-step-ladder
name: Self-adjusting step-ladder for wharfs
brown: "Self-adjusting step-ladder for wharfs at which there are rise and fall of tide. The steps are pivoted at one edge into wooden bars forming string-pieces, and their other edge is supported by rods suspended from bars forming hand-rails. The steps remain horizontal whatever position the ladder assumes."
units: cm
sim: {timestep: 0.0005, integrator: implicitfast, iterations: 60, duration_s: 10, floor: false}
bodies:
  - id: wharf
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#a9946d"
    pieces:
      - {kind: poly, points: [[0, -46], [6, -46], [6, 36.0], [0, 36.0]], y: [-14, 14], collide: 0}   # the wharf's post
      - {kind: rod, from: [3, 0, 38.5], to: [3, 0, 39.5], radius: 3.4, capsule: true, collide: 0}   # its ball
      - {kind: poly, points: [[6, -46], [90, -46], [90, 0], [6, 0]], y: [-14, 40], collide: 0, color: "#b8b0a0"}   # the wharf, broken off below
      - {kind: poly, points: [[60, 0], [66, 0], [66, 36.0], [60, 36.0]], y: [-14, -8], collide: 0}   # the railing's post
      - {kind: rod, from: [63, -11, 38.5], to: [63, -11, 39.5], radius: 3.4, capsule: true, collide: 0}
      - {kind: poly, points: [[6, 28.0], [60, 28.0], [60, 31.0], [6, 31.0]], y: [-13, -10], collide: 0}   # the railing
      - {kind: poly, points: [[6, 1], [60, 1], [60, 4], [6, 4]], y: [-13, -10], collide: 0}
      - {kind: rod, from: [8, -11.5, 5], to: [58, -11.5, 27.0], radius: 1.0, collide: 0}   # its cross-braces
      - {kind: rod, from: [8, -11.5, 27.0], to: [58, -11.5, 5], radius: 1.0, collide: 0}
      - {kind: rod, from: [0, -12.6, 0], to: [0, -9.4, 0], radius: 0.5, collide: 0, color: "#6f675c"}
      - {kind: rod, from: [0, -12.6, 30.0], to: [0, -9.4, 30.0], radius: 0.5, collide: 0, color: "#6f675c"}
      - {kind: rod, from: [0, 9.4, 0], to: [0, 12.6, 0], radius: 0.5, collide: 0, color: "#6f675c"}
      - {kind: rod, from: [0, 9.4, 30.0], to: [0, 12.6, 30.0], radius: 0.5, collide: 0, color: "#6f675c"}
  - id: stringer
    shape: part
    pos: [0, 0, 0]
    density: 600
    color: "#8c6f47"
    pieces:
      - {kind: rod, from: [0, -11.0, 0], to: [-97.9796, -11.0, -20.0], radius: 1.6, collide: 0}   # a string-piece
      - {kind: rod, from: [0, 11.0, 0], to: [-97.9796, 11.0, -20.0], radius: 1.6, collide: 0}   # a string-piece
  - id: rail
    shape: part
    pos: [0, 0, 30.0]
    density: 600
    color: "#8c6f47"
    pieces:
      - {kind: rod, from: [0, -11.0, 30.0], to: [-97.9796, -11.0, 10.0], radius: 1.3, collide: 0}   # a hand-rail
      - {kind: rod, from: [0, 11.0, 30.0], to: [-97.9796, 11.0, 10.0], radius: 1.3, collide: 0}   # a hand-rail
  - id: post
    shape: part
    pos: [-97.9796, 0, -20.0]
    mount: stringer
    density: 600
    friction: 0.03
    color: "#a9946d"
    pieces:
      - {kind: poly, points: [[-100.9796, -28.0], [-94.9796, -28.0], [-94.9796, 16.0], [-100.9796, 16.0]], y: [-14, 14], collide: 0}   # the outer post, standing in the boat
      - {kind: rod, from: [-97.9796, 0, 18.5], to: [-97.9796, 0, 19.5], radius: 3.4, capsule: true, collide: 0}
      - {kind: rod, from: [-97.9796, -12, -28.5], to: [-97.9796, 12, -28.5], radius: 1.5, capsule: true, collide: 1, color: "#6f675c"}   # its foot, on the boat's floor
  - id: step0
    shape: part
    pos: [-13.7171, 0, -2.8]
    mount: stringer
    density: 600
    color: "#c7ab7c"
    pieces:
      - {kind: poly, points: [[-22.7171, -3.4], [-13.1171, -3.4], [-13.1171, -1.9], [-22.7171, -1.9]], y: [-9.4, 9.4], collide: 0}   # a step, pivoted at one edge into the string-pieces
  - id: rod0
    shape: part
    pos: [-13.7171, 0, 27.2]
    mount: rail
    density: 7800
    color: "#5e5850"
    pieces:
      - {kind: rod, from: [-13.7171, -8.8, 27.2], to: [-21.9171, -8.8, -2.8], radius: 0.45, collide: 0}   # its rods, hung from the hand-rails over the pivot
      - {kind: rod, from: [-13.7171, 8.8, 27.2], to: [-21.9171, 8.8, -2.8], radius: 0.45, collide: 0}
  - id: step1
    shape: part
    pos: [-26.4545, 0, -5.4]
    mount: stringer
    density: 600
    color: "#c7ab7c"
    pieces:
      - {kind: poly, points: [[-35.4545, -6.0], [-25.8545, -6.0], [-25.8545, -4.5], [-35.4545, -4.5]], y: [-9.4, 9.4], collide: 0}
  - id: rod1
    shape: part
    pos: [-26.4545, 0, 24.6]
    mount: rail
    density: 7800
    color: "#5e5850"
    pieces:
      - {kind: rod, from: [-26.4545, -8.8, 24.6], to: [-34.6545, -8.8, -5.4], radius: 0.45, collide: 0}
      - {kind: rod, from: [-26.4545, 8.8, 24.6], to: [-34.6545, 8.8, -5.4], radius: 0.45, collide: 0}
  - id: step2
    shape: part
    pos: [-39.1918, 0, -8.0]
    mount: stringer
    density: 600
    color: "#c7ab7c"
    pieces:
      - {kind: poly, points: [[-48.1918, -8.6], [-38.5918, -8.6], [-38.5918, -7.1], [-48.1918, -7.1]], y: [-9.4, 9.4], collide: 0}
  - id: rod2
    shape: part
    pos: [-39.1918, 0, 22.0]
    mount: rail
    density: 7800
    color: "#5e5850"
    pieces:
      - {kind: rod, from: [-39.1918, -8.8, 22.0], to: [-47.3918, -8.8, -8.0], radius: 0.45, collide: 0}
      - {kind: rod, from: [-39.1918, 8.8, 22.0], to: [-47.3918, 8.8, -8.0], radius: 0.45, collide: 0}
  - id: step3
    shape: part
    pos: [-51.9292, 0, -10.6]
    mount: stringer
    density: 600
    color: "#c7ab7c"
    pieces:
      - {kind: poly, points: [[-60.9292, -11.2], [-51.3292, -11.2], [-51.3292, -9.7], [-60.9292, -9.7]], y: [-9.4, 9.4], collide: 0}
  - id: rod3
    shape: part
    pos: [-51.9292, 0, 19.4]
    mount: rail
    density: 7800
    color: "#5e5850"
    pieces:
      - {kind: rod, from: [-51.9292, -8.8, 19.4], to: [-60.1292, -8.8, -10.6], radius: 0.45, collide: 0}
      - {kind: rod, from: [-51.9292, 8.8, 19.4], to: [-60.1292, 8.8, -10.6], radius: 0.45, collide: 0}
  - id: step4
    shape: part
    pos: [-64.6665, 0, -13.2]
    mount: stringer
    density: 600
    color: "#c7ab7c"
    pieces:
      - {kind: poly, points: [[-73.6665, -13.8], [-64.0665, -13.8], [-64.0665, -12.3], [-73.6665, -12.3]], y: [-9.4, 9.4], collide: 0}
  - id: rod4
    shape: part
    pos: [-64.6665, 0, 16.8]
    mount: rail
    density: 7800
    color: "#5e5850"
    pieces:
      - {kind: rod, from: [-64.6665, -8.8, 16.8], to: [-72.8665, -8.8, -13.2], radius: 0.45, collide: 0}
      - {kind: rod, from: [-64.6665, 8.8, 16.8], to: [-72.8665, 8.8, -13.2], radius: 0.45, collide: 0}
  - id: step5
    shape: part
    pos: [-77.4039, 0, -15.8]
    mount: stringer
    density: 600
    color: "#c7ab7c"
    pieces:
      - {kind: poly, points: [[-86.4039, -16.4], [-76.8039, -16.4], [-76.8039, -14.9], [-86.4039, -14.9]], y: [-9.4, 9.4], collide: 0}
  - id: rod5
    shape: part
    pos: [-77.4039, 0, 14.2]
    mount: rail
    density: 7800
    color: "#5e5850"
    pieces:
      - {kind: rod, from: [-77.4039, -8.8, 14.2], to: [-85.6039, -8.8, -15.8], radius: 0.45, collide: 0}
      - {kind: rod, from: [-77.4039, 8.8, 14.2], to: [-85.6039, 8.8, -15.8], radius: 0.45, collide: 0}
  - id: boat
    shape: part
    pos: [-97.9796, 0, -30.0]
    density: 300
    friction: 0.03
    color: "#9a7b55"
    pieces:
      - {kind: poly, points: [[-119.9796, -33.0], [-75.9796, -33.0], [-75.9796, -30.0], [-119.9796, -30.0]], y: [-14, 14], collide: 2}   # the boat's floor
      - {kind: poly, points: [[-127.9796, -24.0], [-119.9796, -38.0], [-75.9796, -38.0], [-67.9796, -24.0], [-71.9796, -24.0], [-77.9796, -33.0], [-117.9796, -33.0], [-123.9796, -24.0]], y: [-16.5, -14], collide: 0, color: "#8a6c47"}   # its side
      - {kind: poly, points: [[-127.9796, -24.0], [-119.9796, -38.0], [-75.9796, -38.0], [-67.9796, -24.0], [-71.9796, -24.0], [-77.9796, -33.0], [-117.9796, -33.0], [-123.9796, -24.0]], y: [14, 16.5], collide: 0, color: "#8a6c47"}
      - {kind: poly, points: [[-237.9796, -35.5], [0, -35.5], [0, -34.5], [-237.9796, -34.5]], y: [-30, 60], collide: 0, color: "#9fb4bf"}   # the water, rising and falling with it
joints:
  - {id: j_b, type: slide, body: boat, axis: [0, 0, 1], damping: 1}   # the tide: the one driven joint (the boat floats up and down)
  - {id: j_s, type: hinge, body: stringer, axis: [0, 1, 0], damping: 0.05}   # the string-pieces on the wharf's post; + : the outer end rises
  - {id: j_r, type: hinge, body: rail, axis: [0, 1, 0], damping: 0.05}   # the hand-rails on the wharf's post
  - {id: j_p, type: hinge, body: post, axis: [0, 1, 0], damping: 0.05}   # the outer post on the string-pieces
  - {id: j_t0, type: hinge, body: step0, axis: [0, 1, 0], damping: 0.01}   # a step on its pivot in the string-pieces
  - {id: j_q0, type: hinge, body: rod0, axis: [0, 1, 0], damping: 0.01}   # its rods on the hand-rails
  - {id: j_t1, type: hinge, body: step1, axis: [0, 1, 0], damping: 0.01}
  - {id: j_q1, type: hinge, body: rod1, axis: [0, 1, 0], damping: 0.01}
  - {id: j_t2, type: hinge, body: step2, axis: [0, 1, 0], damping: 0.01}
  - {id: j_q2, type: hinge, body: rod2, axis: [0, 1, 0], damping: 0.01}
  - {id: j_t3, type: hinge, body: step3, axis: [0, 1, 0], damping: 0.01}
  - {id: j_q3, type: hinge, body: rod3, axis: [0, 1, 0], damping: 0.01}
  - {id: j_t4, type: hinge, body: step4, axis: [0, 1, 0], damping: 0.01}
  - {id: j_q4, type: hinge, body: rod4, axis: [0, 1, 0], damping: 0.01}
  - {id: j_t5, type: hinge, body: step5, axis: [0, 1, 0], damping: 0.01}
  - {id: j_q5, type: hinge, body: rod5, axis: [0, 1, 0], damping: 0.01}
pins:
  - {id: p_rail, a: rail, b: post, at: [-97.9796, 0, 10.0]}   # the hand-rails on the outer post
  - {id: p_rod0, a: rod0, b: step0, at: [-21.9171, 0, -2.8]}   # the rods hold the steps' other edge
  - {id: p_rod1, a: rod1, b: step1, at: [-34.6545, 0, -5.4]}
  - {id: p_rod2, a: rod2, b: step2, at: [-47.3918, 0, -8.0]}
  - {id: p_rod3, a: rod3, b: step3, at: [-60.1292, 0, -10.6]}
  - {id: p_rod4, a: rod4, b: step4, at: [-72.8665, 0, -13.2]}
  - {id: p_rod5, a: rod5, b: step5, at: [-85.6039, 0, -15.8]}
driver: {joint: j_b, kind: velocity, rpm: 0, swing: {amplitude: 0.2, hz: 0.1}, kv: 200000.0, max_torque: 3000}
checks:
  - {type: position, joint: j_s, min: 0.1864, max: 0.2164, settle_s: 2.35, window_s: 0.3}   # high water: the ladder level with the wharf
  - {type: position, joint: j_s, min: -0.2252, max: -0.1952, settle_s: 7.35, window_s: 0.3}   # low water
  - {type: follow, out: j_p, in: j_s, expect: -1.0, tol: 0.03, min_r2: 0.99, settle_s: 0.3, window_s: 9.5}   # the outer post stays upright
  - {type: follow, out: j_t0, in: j_s, expect: -1.0, tol: 0.03, min_r2: 0.99, settle_s: 0.3, window_s: 9.5}   # the steps stay level
  - {type: follow, out: j_t5, in: j_s, expect: -1.0, tol: 0.03, min_r2: 0.99, settle_s: 0.3, window_s: 9.5}
camera: {target: [-25.0, 0, -8.0], position: [5.0, -240.0, 22.0], fov: 34}
display:
  output: j_t0
  labels: {j_b: "Tide (driver)", j_s: "String-pieces", j_t0: "First step"}
  proof: {label: "Boat's floor without contact", sub: "the rising tide no longer lifts the ladder"}
