Gridfinity Sorting Tray
A shallow tray compatible with the Gridfinity 42 mm grid system, for sorting small parts such as screws, beads and SMD components. The grid of compartments (columns by rows) is independent of the grid size, so a 3 x 2 tray can have 4 x 3 compartments, and every divider has a round finger notch at the middle of each compartment so parts can be picked out even when the tray is only two units high. The floor sits as low as the feet allow to get the most depth, and the feet, outline and optional stacking lip follow the standard profile. The default 3 x 2 tray, 2 units high with 4 x 3 compartments, measures 125.5 x 83.5 x 17.9 mm with 7.2 mm deep compartments. It prints upright on its feet with no supports. Parameters: grid units in X and Y, height units, lip, compartment columns and rows, finger notches, magnet pockets and wall thickness.
# Gridfinity Sorting Tray - a low bin with a grid of compartments and finger notches
#
# A shallow Gridfinity-compatible tray for sorting small parts (screws, beads, SMD reels, pills):
# standard 42 mm grid, stepped feet, optional stacking lip, and a grid of compartments
# (columns x rows) that is independent of the grid size, so a 3 x 2 tray can have 4 x 3 bins.
# Each divider has a round finger notch at the middle of every compartment, so a part can be
# picked out from the side even when the tray is shallow. The floor is as low as the feet
# allow to get the most depth from a 1 or 2 unit tray.
# Prints upright on the feet with no supports (the notches are 45 deg or shallower arcs).
@param 1..8 desc:"Grid units along X"
$units_x = 3
@param 1..8 desc:"Grid units along Y"
$units_y = 2
@param 2..4 desc:"Height in 7 mm units (excluding the lip); 1 unit leaves no depth above the feet"
$height_u = 2
@param desc:"Stacking lip"
$lip = true
@param 1..12 desc:"Compartment columns (along X)"
$cols = 4
@param 1..12 desc:"Compartment rows (along Y)"
$rows = 3
@param desc:"Finger notches in the dividers"
$notches = true
@param desc:"Magnet pockets (6 x 2 mm) under the feet"
$magnets = false
@param 0.8..2.4 step:0.1 desc:"Wall and divider thickness (mm)"
$wall = 1.2
# --- Standard values -------------------------------------------------------
$pitch = 42
$unit = 7
$foot_h = 4.75
$r = 3.75
$lip_land = 0.5
$floor_top = if $magnets then 6 else 5.4 # 0.65 mm of floor above the foot tops without magnets
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
$z_top = if $lip then $H + 4.4 - $lip_land else $H
# --- Feet ------------------------------------------------------------------
$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 ($z_top - $foot_h) | translate 0 0 $foot_h
# --- Cavity, with or without the lip profile ------------------------------------
$Wi = $W - 2 * $wall
$Di = $D - 2 * $wall
$ri = $r - $wall
$sup = 2.6 - $wall
$cav_lip = rr($Wi, $Di, $ri)
| loft [rr($Wi, $Di, $ri), rr($W - 5.2, $D - 5.2, $r - 2.6), rr($W - 1.4, $D - 1.4, $r - 0.7), rr($W - 1.4, $D - 1.4, $r - 0.7), rr($W, $D, $r)] [$H - $sup - $floor_top, $H - $floor_top, $H + 1.9 - $floor_top, $H + 3.7 - $floor_top, $H + 4.4 - $floor_top] ruled:true
| translate 0 0 $floor_top
$cav_open = rr($Wi, $Di, $ri) | extrude ($H + 1 - $floor_top) | translate 0 0 $floor_top
$cavity = if $lip then $cav_lip else $cav_open
$div_top = if $lip then $H - $sup else $H
$div_h = $div_top - $floor_top
assert $div_h > 3 # the tray is deep enough to hold anything
# --- Compartment grid ----------------------------------------------------------------
$px = $Wi / $cols
$py = $Di / $rows
$divs_x = union [box $wall ($Di + 1) $div_h at:(($k + 1) * $px - $Wi / 2, 0, $floor_top + $div_h / 2) for $k in range($cols - 1)]
$divs_y = union [box ($Wi + 1) $wall $div_h at:(0, ($k + 1) * $py - $Di / 2, $floor_top + $div_h / 2) for $k in range($rows - 1)]
# --- Finger notches: a cylinder across each divider at every compartment centre -----------
# Notch radius: a third of the divider height, at most 6 mm. The cylinder axis is at
# the divider's top edge, so the notch is a half circle and its walls start vertical.
$nr = min(6, $div_h / 3)
$nx = cylinder $nr ($wall + 2) | rotate 0 90 0 # axis along X: cuts the Y dividers
$ny = cylinder $nr ($wall + 2) | rotate 90 0 0 # axis along Y: cuts the X dividers
$notch_x = union [$ny | translate (($k % ($cols - 1) + 1) * $px - $Wi / 2) (($k // ($cols - 1) + 0.5) * $py - $Di / 2) $div_top for $k in range(($cols - 1) * $rows)]
$notch_y = union [$nx | translate (($k % $cols + 0.5) * $px - $Wi / 2) (($k // $cols + 1) * $py - $Di / 2) $div_top for $k in range($cols * ($rows - 1))]
# --- Magnets ----------------------------------------------------------------------
$mag = cylinder 3.25 2.6 center:(true, true, false) | translate 0 0 -0.2
$mags = union [$mag | translate (cx(i // 4) + (if i % 2 == 0 then 13 else -13)) (cy(i // 4) + (if i // 2 % 2 == 0 then 13 else -13)) 0 for i in range($n * 4)]
# --- Assemble ----------------------------------------------------------------------
$shell0 = ($feet + $body) - $cavity
$t1 = if $cols > 1 then $shell0 + $divs_x else $shell0
$t2 = if $rows > 1 then $t1 + $divs_y else $t1
$t3 = if $notches and $cols > 1 then $t2 - $notch_x else $t2
$t4 = if $notches and $rows > 1 then $t3 - $notch_y else $t3
$tray = if $magnets then $t4 - $mags else $t4
# --- Checks ------------------------------------------------------------------------
assert $tray.solids == 1
assert $tray.bbox.x ~ $W
assert $tray.bbox.y ~ $D
assert $tray.bbox.z ~ $z_top
assert $tray.volume < $W * $D * $z_top * 0.5
print "compartment (mm)" $px
print "depth (mm)" $div_h
$tray