// ======================================================== // PARAMETRIC SEEDLING TRAY SYSTEM // Includes: Tray, Plates, Angled Water Tray, & Ball-Pusher Tool // ======================================================== /* [Grid Configuration] */ cols = 4; // Number of columns rows = 3; // 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 outer and interior walls (mm) bottom_lip = 4.0; // Width of the bottom ledge holding the plate (mm) floor_thickness = 2.0; // Height/thickness of the bottom lip (mm) /* [Pusher Plate Settings] */ plate_thickness = 2.0; // Thickness of the removable 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 plate (mm) /* [Angled Water Tray Settings] */ water_tray_height = 25; // Height of the bottom drip tray (mm) wt_clearance = 1.5; // Extra room around main tray for easy removal (mm) wt_flare = 3.5; // Outward wall expansion at top (mm) /* [Single Pressing Tool Settings] */ tool_plate_thick = 3.0; // Thickness of the square pusher plate (mm) stem_dia = 10.0; // Diameter of the stick (mm) stem_length = 45.0; // Length of the stick shaft (mm) handle_ball_dia = 20.0; // Diameter of the handle ball on top (mm) /* [Render Mode] */ render_mode = "all_layout"; // ["all_layout", "assembled", "tray_only", "plates_only", "water_tray_only", "tool_only"] // --- DERIVED CALCULATIONS --- pitch = cell_size + wall_thickness; total_width = cols * pitch + wall_thickness; total_length = rows * pitch + wall_thickness; // --- MAIN DISPLAY EXECUTION --- if (render_mode == "tray_only") { seedling_tray(); } else if (render_mode == "plates_only") { plate_grid(); } else if (render_mode == "water_tray_only") { water_tray(); } else if (render_mode == "tool_only") { single_pressing_tool(); } else if (render_mode == "all_layout") { // Top Left: Main Tray seedling_tray(); // Bottom Left: Plates Grid translate([0, -total_length - 20, 0]) plate_grid(); // Top Right: Angled Water Tray translate([total_width + 25, 0, 0]) water_tray(); // Bottom Right: Single Pressing Tool translate([total_width + 25 + (total_width / 2), -total_length / 2 - 20, 0]) single_pressing_tool(); } else if (render_mode == "assembled") { // 1. Water tray at base color("DarkSlateGray") water_tray(); // 2. Seedling tray inside water tray translate([wall_thickness + wt_clearance/2, wall_thickness + wt_clearance/2, floor_thickness]) { color("ForestGreen", 0.95) seedling_tray(); // Plates on bottom ledges color("SaddleBrown") { 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(); } } } } // 3. Pressing tool translate([ wall_thickness + wt_clearance/2 + wall_thickness + (cell_size / 2), wall_thickness + wt_clearance/2 + wall_thickness + (cell_size / 2), -stem_length / 2 ]) color("Goldenrod") single_pressing_tool(); } // ======================================================== // MODULES // ======================================================== // 1. Main seedling tray body module seedling_tray() { difference() { cube([total_width, total_length, tray_height]); for (r = [0 : rows - 1]) { for (c = [0 : cols - 1]) { x_pos = wall_thickness + c * pitch; y_pos = wall_thickness + r * pitch; translate([x_pos, y_pos, floor_thickness]) cube([cell_size, cell_size, tray_height]); translate([x_pos + bottom_lip, y_pos + bottom_lip, -1]) cube([ cell_size - (2 * bottom_lip), cell_size - (2 * bottom_lip), floor_thickness + 2 ]); } } } } // 2. Single removable bottom plate module pusher_plate() { p_size = cell_size - clearance; offset_margin = p_size / 3.5; difference() { cube([p_size, p_size, plate_thickness]); 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); } } } } // 3. Print layout grid matching exact tray cell count 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(); } } } // 4. Water Tray with Angled Outward Walls module water_tray() { wt_inner_w = total_width + wt_clearance; wt_inner_l = total_length + wt_clearance; wt_outer_w = wt_inner_w + (2 * wall_thickness); wt_outer_l = wt_inner_l + (2 * wall_thickness); difference() { translate([wt_outer_w / 2, wt_outer_l / 2, 0]) linear_extrude(height = water_tray_height, scale = [(wt_outer_w + 2 * wt_flare) / wt_outer_w, (wt_outer_l + 2 * wt_flare) / wt_outer_l]) square([wt_outer_w, wt_outer_l], center = true); translate([wt_outer_w / 2, wt_outer_l / 2, floor_thickness]) linear_extrude(height = water_tray_height, scale = [(wt_inner_w + 2 * wt_flare) / wt_inner_w, (wt_inner_l + 2 * wt_flare) / wt_inner_l]) square([wt_inner_w, wt_inner_l], center = true); } } // 5. Pressing Tool module single_pressing_tool() { p_size = (cell_size - clearance); // Square pusher plate at base translate([0, 0, tool_plate_thick / 2]) cube([p_size, p_size, tool_plate_thick], center = true); // Vertical stick translate([0, 0, tool_plate_thick]) cylinder(h = stem_length, d = stem_dia, $fn = 32); // Palm ball handle on top translate([0, 0, tool_plate_thick + stem_length]) sphere(d = handle_ball_dia, $fn = 40); }