From c414d77ddbdb425f41bdc5ae2276dcabd77ebe51 Mon Sep 17 00:00:00 2001 From: Sam Hadow Date: Thu, 3 Sep 2026 17:03:59 +0200 Subject: [PATCH] parametric seedling tray with pushable plates --- seedlings_tray/seedlings-tray.scad | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 seedlings_tray/seedlings-tray.scad diff --git a/seedlings_tray/seedlings-tray.scad b/seedlings_tray/seedlings-tray.scad new file mode 100644 index 0000000..12a727f --- /dev/null +++ b/seedlings_tray/seedlings-tray.scad @@ -0,0 +1,123 @@ +// ======================================================== +// PARAMETRIC SEEDLING TRAY & PUSHABLE PLATES +// ======================================================== + +/* [Grid Configuration] */ +cols = 3; // Number of columns +rows = 2; // Number of rows +cell_size = 35; // Inner width/length of each square cell (mm) +tray_height = 50; // Total height of the tray (mm) + +/* [Wall & Ledge Dimensions] */ +wall_thickness = 1.6; // Thickness of the walls (mm) +bottom_lip = 4.0; // Width of the bottom ledge holding the plate (mm) +floor_thickness = 2.0; // Thickness of the bottom lip (mm) + +/* [Pusher Plate Settings] */ +plate_thickness = 2.0; // Thickness of the pushable plate (mm) +clearance = 0.4; // Gap between cell walls and plate for easy sliding (mm) +drain_hole_dia = 4.5; // Diameter of drainage holes in the pushable plate (mm) + +/* [Render Mode] */ +// ["both_layout", "assembled", "tray_only", "plates_only"] +render_mode = "both_layout"; + + + +// --- DERIVED CALCULATIONS --- +pitch = cell_size + wall_thickness; +total_width = cols * pitch + wall_thickness; +total_length = rows * pitch + wall_thickness; + + +// --- MAIN DISPLAY --- +if (render_mode == "tray_only") { + seedling_tray(); +} else if (render_mode == "plates_only") { + plate_grid(); +} else if (render_mode == "both_layout") { + seedling_tray(); + translate([0, total_length + 10, 0]) + plate_grid(); +} else if (render_mode == "assembled") { + // Visual preview + seedling_tray(); + for (r = [0 : rows - 1]) { + for (c = [0 : cols - 1]) { + translate([ + wall_thickness + c * pitch + clearance/2, + wall_thickness + r * pitch + clearance/2, + floor_thickness + ]) + pusher_plate(); + } + } +} + + +// ======================================================== +// MODULES +// ======================================================== + +// Main seedling tray body +module seedling_tray() { + difference() { + // Outer solid volume + cube([total_width, total_length, tray_height]); + + // Cut out each cell pocket and bottom push hole + for (r = [0 : rows - 1]) { + for (c = [0 : cols - 1]) { + x_pos = wall_thickness + c * pitch; + y_pos = wall_thickness + r * pitch; + + // 1. Main cell compartment + translate([x_pos, y_pos, floor_thickness]) + cube([cell_size, cell_size, tray_height]); + + // 2. Bottom push-through opening + translate([x_pos + bottom_lip, y_pos + bottom_lip, -1]) + cube([ + cell_size - (2 * bottom_lip), + cell_size - (2 * bottom_lip), + floor_thickness + 2 + ]); + } + } + } +} + +// Single pushable bottom plate +module pusher_plate() { + p_size = cell_size - clearance; + offset_margin = p_size / 3.5; + + difference() { + // Plate body + cube([p_size, p_size, plate_thickness]); + + // 5-points drainage hole pattern + translate([p_size / 2, p_size / 2, -1]) + cylinder(h = plate_thickness + 2, d = drain_hole_dia, $fn = 20); + + for (dx = [offset_margin, p_size - offset_margin]) { + for (dy = [offset_margin, p_size - offset_margin]) { + translate([dx, dy, -1]) + cylinder(h = plate_thickness + 2, d = drain_hole_dia, $fn = 20); + } + } + } +} + +// Plate grid +module plate_grid() { + p_size = cell_size - clearance; + spacing = 2; + + for (r = [0 : rows - 1]) { + for (c = [0 : cols - 1]) { + translate([c * (p_size + spacing), r * (p_size + spacing), 0]) + pusher_plate(); + } + } +} \ No newline at end of file