Gridfinity Bit Bin
A Gridfinity-compatible holder that stands tools upright: the standard 42 mm grid feet and outline, but a solid block drilled with a grid of holes instead of an open cavity. Three kinds are available. Bits is a grid of 1/4 inch hexagonal sockets for screwdriver bits. Drills is one round hole for every diameter from the smallest to the largest size in the chosen step, laid out in rows with the hole pitch growing with the diameter and the size engraved under each hole, so a loose drill set gets an index. Round is a grid of equal holes of a chosen diameter for pens, files, hex keys or punches. The default drill index for 1 to 10 mm in 0.5 mm steps on a 3 x 1 block, 4 units high, measures 125.5 x 41.5 x 28 mm. It prints upright on its feet with no supports. Parameters: kind, grid units in X and Y, height units, drill size range, step and number of rows, round hole diameter, hole clearance and the web between holes.
# Gridfinity Bit Bin - a solid block with a grid of holes for hex bits, drill bits or pens
#
# A Gridfinity-compatible holder that stands tools upright: the standard 42 mm grid feet
# and outline, but a solid block instead of a cavity, drilled with a grid of holes.
# "bits" is a grid of 1/4 inch hexagonal sockets for screwdriver bits. "drills" is one
# round hole per diameter from d_min to d_max in d_step, laid out in rows with the size
# engraved beside each hole, so a loose drill set gets an index. "round" is a grid of
# equal holes of a chosen diameter (pens, files, hex keys, punches).
# Prints upright on the feet with no supports: the holes are vertical and the feet are 45 deg.
@param choices:["bits", "drills", "round"] desc:"What the holes are for"
$kind = "drills"
@param 1..6 desc:"Grid units along X"
$units_x = 3
@param 1..6 desc:"Grid units along Y"
$units_y = 1
@param 2..9 desc:"Height in 7 mm units"
$height_u = 4
@param 1..5 step:0.5 desc:"Drills: smallest diameter (mm)"
$d_min = 1
@param 3..13 step:0.5 desc:"Drills: largest diameter (mm)"
$d_max = 10
@param 0.5..1 step:0.5 desc:"Drills: size step (mm)"
$d_step = 0.5
@param 1..4 desc:"Drills: number of rows"
$d_rows = 2
@param 3..20 step:0.5 desc:"Round: hole diameter (mm)"
$round_d = 8
@param 0.2..0.8 step:0.1 desc:"Clearance added to every hole (mm)"
$clear = 0.4
@param 2..4 step:0.5 desc:"Web between holes (mm)"
$web = 2.5
# --- Standard values ---------------------------------------------------------
$pitch = 42
$unit = 7
$foot_h = 4.75
$r = 3.75
$floor_top = 6 # holes stop here (the feet below stay solid)
def rr($w, $h, $r) = rect ($w - 2 * $r) ($h - 2 * $r) | offset $r
$W = $units_x * $pitch - 0.5
$D = $units_y * $pitch - 0.5
$H = $height_u * $unit
$margin = 2.5 # solid rim around the hole field
$Wi = $W - 2 * $margin
$Di = $D - 2 * $margin
$depth = $H - $floor_top + 1
# --- Feet and block ------------------------------------------------------------
$foot = rr(35.6, 35.6, 0.8)
| loft [rr(37.2, 37.2, 1.6), rr(37.2, 37.2, 1.6), rr(41.5, 41.5, $r)] [0.8, 2.6, $foot_h] ruled:true
def cx($i) = ($i % $units_x - ($units_x - 1) / 2) * $pitch
def cy($i) = ($i // $units_x - ($units_y - 1) / 2) * $pitch
$n = $units_x * $units_y
$feet = union [$foot | translate cx(i) cy(i) 0 for i in range($n)]
$body = rr($W, $D, $r) | extrude ($H - $foot_h) | translate 0 0 $foot_h
$block = $feet + $body
# --- Hole field ------------------------------------------------------------------
$hex_af = 6.35 + $clear # 1/4 inch hex across flats, with clearance
$big = if $kind == "bits" then $hex_af / cos(30) else (if $kind == "drills" then $d_max + $clear else $round_d + $clear)
$text_h = 3.5
# bits / round: a regular grid, as many holes as fit
$pg = $big + $web
$cols = floor(($Wi + $web) / $pg)
$rows_fit = floor(($Di + $web) / $pg)
$n_grid = $cols * $rows_fit
assert $n_grid >= 1
$gx0 = -(($cols - 1) * $pg) / 2
$gy0 = (($rows_fit - 1) * $pg) / 2
def gx($i) = $gx0 + ($i % $cols) * $pg
def gy($i) = $gy0 - ($i // $cols) * $pg
# drills: one hole per size in d_rows rows, the x pitch growing with the diameter,
# the size engraved under each hole. Positions are closed-form sums of the arithmetic
# series of diameters, so no running total is needed.
$n_drills = floor(($d_max - $d_min) / $d_step + 1.001)
$per = ceil($n_drills / $d_rows)
def dia($i) = $d_min + $i * $d_step
def row($i) = $i // $per
def first($i) = row($i) * $per
def last($i) = min(first($i) + $per, $n_drills) # one past the row's last index
def span($s, $e) = ($e - $s) * ($d_min + $clear + $web) + $d_step * ($s + $e - 1) * ($e - $s) / 2 # sum of pitches s..e-1
def roww($i) = span(first($i), last($i)) - $web # width of the row holding hole i
def dx($i) = -roww($i) / 2 + span(first($i), $i) + (dia($i) + $clear) / 2
$row_h = $big + 1 + $text_h # hole plus the label under it
$py = $row_h + $web
$field_h = $d_rows * $py - $web
def dy($i) = $field_h / 2 - $big / 2 - row($i) * $py
$widest = roww($n_drills - 1) # the last row has the largest drills
assert $kind != "drills" or $widest <= $Wi # the row of largest drills fits across
assert $kind != "drills" or $field_h <= $Di # all the rows fit front to back
$count = if $kind == "drills" then $n_drills else $n_grid
$z_hole = $H - $depth + 1
$hex = polygon 6 ($hex_af / 2 / cos(30)) | rotate 30 | extrude $depth | translate 0 0 $z_hole
$holes = if $kind == "bits" then union [$hex | translate gx(i) gy(i) 0 for i in range($count)]
else (if $kind == "drills" then union [cylinder ((dia(i) + $clear) / 2) $depth center:(true, true, false) | translate dx(i) dy(i) $z_hole for i in range($count)]
else union [cylinder (($round_d + $clear) / 2) $depth center:(true, true, false) | translate gx(i) gy(i) $z_hole for i in range($count)])
# size labels, 0.6 mm deep, centred under each drill hole (text is centred on the origin)
$labels = union [text ("" + dia(i)) $text_h | extrude 1 | translate dx(i) (dy(i) - $big / 2 - 1 - $text_h / 2) ($H - 0.6) for i in range($count)]
$b1 = $block - $holes
$bin = if $kind == "drills" then $b1 - $labels else $b1
# --- Checks -----------------------------------------------------------------------
assert $bin.solids == 1
assert $bin.bbox.x ~ $W
assert $bin.bbox.y ~ $D
assert $bin.bbox.z ~ $H
assert $bin.volume < $block.volume
print "holes" $count
print "widest row (mm)" $widest
$bin