Vernier Caliper
A two-part printed caliper: a beam with a fixed jaw and a millimetre scale, and a slider with a second jaw and a vernier scale. The vernier has 10 divisions spread over 9 mm (or 20 over 19 mm for 0.05 mm), so the division that lines up with a main scale mark gives the fraction of a millimetre, and both scales are generated from the code, so the division spacing is exactly (n - 1) / n mm. The slider is a sleeve that rides on the beam, open on top over the scale strip so the two scales meet at the window edge. A printed caliper is a teaching model and a rough gauge rather than a precision instrument; expect about 0.2 mm, limited by the nozzle and the sliding fit. The default 100 mm range beam is 148 x 53 x 10 mm assembled; the print layout, beam flat and slider standing on its jaw face so the sleeve has no overhangs, measures 153 x 111 x 30 mm. No supports. Parameters: view (print layout or assembled), measuring range, jaw length, vernier divisions, sliding clearance and the opening shown in the assembled view.
# Vernier Caliper - two-part printed caliper with a generated 0.1 mm vernier scale
#
# A beam with a fixed jaw and a millimetre scale, and a slider with a second jaw and a
# vernier: 10 divisions spread over 9 mm, so the one that lines up with a main-scale mark
# gives the tenth of a millimetre. Both scales are generated from the code, which is what
# makes the vernier honest: the division spacing is exactly (n - 1) / n mm.
# A printed caliper is a teaching model and a rough gauge, not a precision instrument:
# expect about 0.2 mm, limited by the nozzle and the sliding fit.
# Print layout: the beam flat on the bed, the slider standing on its jaw face so the sleeve
# that rides on the beam has no overhangs. "assembled" shows the slider on the beam.
@param choices:["print", "assembled"] desc:"Print layout or assembled view"
$view = "print"
@param 50..200 step:10 desc:"Measuring range (mm)"
$range = 100
@param 10..50 desc:"Jaw length (mm)"
$jaw_l = 30
@param 10..20 desc:"Vernier divisions (10 reads 0.1 mm, 20 reads 0.05 mm)"
$vdiv = 10
@param 0.2..0.6 step:0.1 desc:"Sliding clearance per side (mm)"
$fit = 0.3
@param 0..200 desc:"Assembled view: jaw opening (mm)"
$open = 23.4
# --- Beam ---------------------------------------------------------------------------
$beam_w = 16 # across (Y)
$beam_t = 4 # thick (Z)
$jaw_t = 8 # jaw thickness along X
$sleeve_l = 30 # slider sleeve length along X
$park = $sleeve_l + 10 # beam beyond the last scale mark
$x0 = $jaw_t # fixed jaw face = scale zero
$L = $x0 + $range + $park
$wall = 3
$window = 7 # strip of the beam's top left uncovered by the sleeve, carrying the scale
$beam_bar = box $L $beam_w $beam_t center:(false, true, false)
$fixed_jaw = box $jaw_t $jaw_l 6 center:(false, false, false) | translate 0 (-($beam_w / 2) - $jaw_l) 0
$beam0 = $beam_bar + $fixed_jaw
# main scale on the top face, along the +Y edge: 1 mm ticks, longer at 5 and 10, numbers every 10
$ye = $beam_w / 2
def tl($n) = if $n % 10 == 0 then 5 else if $n % 5 == 0 then 3.5 else 2
$ticks = union [box 0.35 tl($n) 1 center:(true, false, false) | translate ($x0 + $n) ($ye - tl($n)) ($beam_t - 0.4) for $n in range($range + 1)]
$nums = union [text ("" + ($n * 10)) 2.6 | extrude 1 | translate ($x0 + $n * 10) ($ye - 7.2) ($beam_t - 0.4) for $n in range(1, $range // 10 + 1)]
$beam1 = $beam0 - $ticks
$beam = $beam1 - $nums
# --- Slider: a sleeve around the beam, open on top over the scale window, with a jaw ------
$in_w = $beam_w + 2 * $fit
$in_t = $beam_t + 2 * $fit
$sl_w = $in_w + 2 * $wall
$sl_t = $in_t + 2 * $wall
$sleeve_out = box $sleeve_l $sl_w $sl_t center:(false, true, true)
$sleeve_in = box ($sleeve_l + 2) $in_w $in_t center:(false, true, true) | translate -1 0 0
# the window: remove the top plate over the scale strip (y from ye - window to the wall)
$win = box ($sleeve_l + 2) ($window + $wall + 1) ($wall + 1) center:(false, false, false)
| translate -1 ($ye - $window) ($in_t / 2 - 0.5)
$sleeve0 = $sleeve_out - $sleeve_in
$sleeve = $sleeve0 - $win
$slider_jaw = box $jaw_t $jaw_l $sl_t center:(false, false, true) | translate 0 (-($sl_w / 2) - $jaw_l) 0
$slider0 = $sleeve + $slider_jaw
# the slider jaw's measuring face is at x = 0; the fixed jaw's face is at x = x0, so the
# vernier zero sits at the jaw face: ticks on the top plate along the window edge
$vz = $sl_t / 2
$vy = $ye - $window
$vstep = ($vdiv - 1) / $vdiv
def vl($k) = if $k % 5 == 0 then 4 else 2.5
$vticks = union [box 0.35 vl($k) 1 center:(true, false, false) | translate ($k * $vstep) ($vy - vl($k)) ($vz - 0.4) for $k in range($vdiv + 1)]
$vnums = union [text ("" + $k) 2.2 | extrude 1 | translate ($k * $vstep) ($vy - 6.5) ($vz - 0.4) for $k in [0, $vdiv]]
$slider1 = $slider0 - $vticks
$slider = $slider1 - $vnums
assert $vdiv * $vstep + 2 < $sleeve_l # vernier fits on the sleeve
# --- Assembled: slider at the opening, its jaw face at x0 + open; vertical offset so the
# sleeve is centred on the beam (sleeve is centred on z = 0, the beam sits on z = 0)
$asm_slider = $slider | translate ($x0 + $open) 0 ($beam_t / 2)
$assembled = $beam + $asm_slider
assert clear($beam, $asm_slider)
assert $open <= $range
# --- Print layout: beam flat; slider stood on its jaw face (x = 0 -> z = 0), beside the beam
$stand = $slider | rotate 0 -90 0 | translate 0 ($jaw_l + $sl_w / 2 + $ye + 12) 0
$print = $beam + $stand
assert $stand.bbox.min[2] ~ 0 tol:0.01
assert clear($beam, $stand)
$out = if $view == "assembled" then $assembled else $print
assert $out.solids == 2
assert $beam.bbox.x ~ $L
print "beam (mm)" $L
print "vernier step (mm)" $vstep
$out