Created
May 27, 2025 16:59
-
-
Save sowbug/22fd84a627a956d4855ad8b134f821e0 to your computer and use it in GitHub Desktop.
OpenSCAD file for 37-vial upright tray that fits in Igloo Legend 6-can cooler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/revarbat/BOSL/wiki/masks.scad#fillet | |
include <BOSL/constants.scad> | |
use <BOSL/masks.scad> | |
/////////////////////////////////////// | |
// Configurable parameters | |
// 3mL vial | |
// https://www.amazon.com/dp/B0CP3XN582 | |
actual_vial_diameter = 16.2; | |
actual_vial_height = 38.7; | |
// Add a little to make sure the vials fit | |
vial_width = actual_vial_diameter + 0.3; | |
vial_height = actual_vial_height + 1.3; | |
// Needed to offset cylinder projections | |
half_vial_width = vial_width / 2; | |
// Space between side-by-side vials | |
vial_spacing_x = 1.5; | |
// Space between bottom of one vial and top of the next | |
vial_spacing_y = 0.8; | |
// Igloo Legend 6-Can Cooler, Red, 5 Qt | |
// https://www.amazon.com/dp/B00BC3ISDA | |
// | |
// These are the interior dimensions of the usable space | |
// Full size tray | |
max_container_width = 204; // Container width | |
max_container_depth = 152; // Container depth | |
max_container_height = 149; // Container height | |
// Faster to print a smaller tray to test the design | |
// Uncomment these to enable | |
// max_container_width = 80; // Container width | |
// max_container_depth = 50; // Container depth | |
// max_container_height = 40; // Container height | |
// Margin outside the tray but inside the container | |
container_margin = 0.5; | |
two_container_margins = container_margin * 2; | |
// Margin inside the walls of the tray | |
tray_margin = 0.5; | |
two_tray_margins = tray_margin * 2; | |
wall_thickness = 1.25; // Thickness of the exterior tray walls | |
two_walls = wall_thickness * 2; | |
// End configurable parameters | |
/////////////////////////////////////// | |
// Calculate the maximum tray dimensions so we can calculate what fits | |
max_tray_width = max_container_width - two_container_margins; | |
max_tray_depth = max_container_depth - two_container_margins; | |
max_tray_height = vial_width + wall_thickness; | |
// How many vials can we fit? We add the vial spacing to the numerator as well | |
// to compensate for the fact that there are only N-1 spaces between N vials. | |
vials_x = floor((max_tray_width - two_walls + vial_spacing_x) / (vial_width + vial_spacing_x)); | |
vials_y = floor((max_tray_depth - two_walls + vial_spacing_y) / (vial_height + vial_spacing_y)); | |
// We also want to fit some sideways vials in the excess space above the top row. | |
// We assume there's only one row. | |
vials_side_x = floor((max_tray_width - two_walls - two_tray_margins + vial_spacing_y) / | |
(vial_height + vial_spacing_x)); | |
vials_side_y = 1; | |
// Now calculate the actual tray dimensions. HACK: we allow the sideways row to | |
// take up extra depth, but not extra width. | |
side_vials_depth = | |
vials_side_y // number of rows | |
* vial_width // the width/diameter of a vial | |
+ (vials_side_y - 1) // the number of spaces between rows (we know this is zero) | |
* vial_spacing_y // the space between rows of vials | |
+ vial_spacing_y; // the space between the upright and sideways rows | |
tray_width = ceil(vials_x * vial_width + (vials_x - 1) * vial_spacing_x + two_tray_margins + two_walls); | |
tray_depth = ceil(vials_y * vial_height + (vials_y - 1) * vial_spacing_y + two_tray_margins + side_vials_depth + two_walls); | |
tray_height = ceil(wall_thickness + vial_width); | |
side_vials_width = | |
vials_side_x // number of rows | |
* vial_height // the height of a vial | |
+ (vials_side_x - 1) // the number of spaces between rows (we know this is zero) | |
* vial_spacing_y; // the space between rows of vials | |
side_vials_centering_offset = (tray_width - side_vials_width) / 2; | |
vials_per_tray = vials_x * vials_y + vials_side_x * vials_side_y; | |
trays_per_container = floor(max_container_height / tray_height); | |
echo("Container dimensions WxDxH", max_container_width, max_container_depth, max_container_height); | |
echo("Tray dimensions WxDxH", tray_width, tray_depth, tray_height); | |
echo("Max vials/tray", vials_per_tray); | |
echo("Max trays/container", trays_per_container); | |
echo("Max vials/container", vials_per_tray * trays_per_container); | |
// Create the base of the tray | |
module tray_shape() { | |
// Think of grip_factor as how much of the circle you want to hug the vial. | |
// 0.5 is a perfect half-circle, so vials will stay in place if the tray is | |
// laying flat, but they'll fall out if you want the tray on its side (so | |
// that the vials are upright). 0.6 leaves 60% of the circle, which after | |
// some experimentation seemed to provide just enough of a friction fit | |
// without requiring too much force to remove. | |
grip_factor = 0.6; | |
internal_width = tray_width - wall_thickness * 2; | |
internal_depth = tray_depth - wall_thickness * 2; | |
internal_height = tray_height - wall_thickness - tray_height * 0.6; | |
difference() { | |
cube([tray_width, tray_depth, tray_height]); | |
translate([wall_thickness, wall_thickness, tray_height - internal_height]) { | |
cube([internal_width, internal_depth, internal_height]); | |
} | |
} | |
} | |
// Create upright vials | |
module upright_vials(y) { | |
for (x = [0:vials_x - 1]) { | |
translate([ x * (vial_width + vial_spacing_x), | |
y * (vial_height + vial_spacing_y), | |
0]) { | |
translate([half_vial_width, 0, 0]) { // Center the vials | |
rotate([0, 90, 90]) { // Rotate the vials to be upright | |
cylinder(h = vial_height, d = vial_width); | |
} | |
} | |
} | |
} | |
} | |
// Create sideways vials | |
module sideways_vials(y) { | |
for (x = [0:vials_side_x - 1]) { | |
translate([ x * (vial_height + vial_spacing_y) + tray_margin, | |
half_vial_width + vial_spacing_x + y * (vial_width + vial_spacing_x), | |
0]) { | |
rotate([0, 90, 0]) { | |
cylinder(h = vial_height, d = vial_width); | |
} | |
} | |
} | |
} | |
module grip_handle() { | |
handle_width = 8; | |
handle_depth = 2; | |
handle_height = 1; | |
hole_inset = 0.05; // What percentage of the handle is the hole | |
translate([tray_width / 2 , tray_depth + (handle_depth / 2) * 0.2, handle_height / 2]) { | |
fillet(fillet=0.25, size = [handle_width, handle_depth, handle_height], $fn=24) { | |
difference() { | |
cube([handle_width, handle_depth, handle_height], center=true); | |
cube([handle_width * hole_inset, handle_depth * hole_inset, handle_height], center=true); | |
} | |
} | |
} | |
} | |
module tray() { | |
fillet(fillet=2, size = [tray_width, tray_depth, tray_height], $fn=24) { | |
translate([-tray_width / 2, -tray_depth / 2, -tray_height / 2]) { | |
difference() { | |
tray_shape(); | |
// Regular vial orientation | |
translate([wall_thickness + tray_margin, | |
wall_thickness + tray_margin, | |
wall_thickness + half_vial_width]) { | |
for (y = [0:vials_y-1]) { | |
upright_vials(y); | |
} | |
} | |
// Side vial orientation | |
vial_y_space = vials_y * (vial_height) + (vials_y - 1) * vial_spacing_y; | |
translate([side_vials_centering_offset, | |
wall_thickness + vial_y_space + vial_spacing_y, | |
wall_thickness + half_vial_width]) { | |
for (y = [0:vials_side_y-1]) { | |
sideways_vials(y); | |
} | |
} | |
} | |
} | |
} | |
} | |
module handle() { | |
translate([-tray_width / 2, -tray_depth / 2, -tray_height / 2]) { | |
grip_handle(); | |
} | |
} | |
tray(); | |
// removed because it adds too much height | |
// handle(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment