2022-12-06 15:58:59 +00:00
|
|
|
/* Project box
|
|
|
|
|
2022-12-06 21:19:45 +00:00
|
|
|
A parametric box for electronics projects using perforated circuit boards. The
|
|
|
|
board is held above the bottom of the box by four corner supports, and snaps
|
|
|
|
into place to hold it snugly while allowing easy removal.
|
2022-12-07 15:40:32 +00:00
|
|
|
|
|
|
|
Shapes provided as children will be used as cutouts, translated to the origin
|
|
|
|
point of the top of the circuit board. Modules are provided for cutting out
|
|
|
|
two-dimensional shapes from each wall face as well as the lid.
|
2022-12-06 15:58:59 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
$fn=50;
|
|
|
|
|
2022-12-06 21:19:45 +00:00
|
|
|
mode = "case"; // ["case", "lid", "all"]
|
2022-12-06 15:58:59 +00:00
|
|
|
board_x = 50;
|
|
|
|
board_y = 70;
|
2022-12-06 20:10:11 +00:00
|
|
|
board_thickness = 1; // [1:10]
|
|
|
|
clearance_above = 20; // [5:50]
|
|
|
|
clearance_below = 10; // [5:50]
|
2022-12-06 15:58:59 +00:00
|
|
|
fit_tolerance = 0.5;
|
2022-12-06 20:10:11 +00:00
|
|
|
corner_radius=3; // [1:10]
|
|
|
|
support_radius=5; // [1:10]
|
|
|
|
wall_width=3; // [3:10]
|
2022-12-06 15:58:59 +00:00
|
|
|
|
2022-12-07 17:09:05 +00:00
|
|
|
module _rounded_box(box, r) {
|
2022-12-06 15:58:59 +00:00
|
|
|
hull() {
|
|
|
|
translate([0 + r,0 + r,0])
|
2022-12-07 17:09:05 +00:00
|
|
|
cylinder(h=box.z,r=r);
|
|
|
|
translate([box.x - r,0 + r,0])
|
|
|
|
cylinder(h=box.z, r=r);
|
|
|
|
translate([box.x - r,box.y - r,0])
|
|
|
|
cylinder(h=box.z, r=r);
|
|
|
|
translate([0 + r,box.y - r,0])
|
|
|
|
cylinder(h=box.z, r=r);
|
2022-12-06 15:58:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module corner_post(h, r) {
|
|
|
|
intersection() {
|
|
|
|
translate([-0.001,-0.001,-0.001])
|
|
|
|
cube([r*1.1, r*1.1, h*1.2]);
|
|
|
|
cylinder(h=h, r=r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-07 17:09:05 +00:00
|
|
|
module lid_base(dimensions, slot_depth=1.5) {
|
2022-12-06 20:10:11 +00:00
|
|
|
polyhedron([// bottom face
|
|
|
|
[0, 0, 0],
|
2022-12-07 17:09:05 +00:00
|
|
|
[dimensions.x, 0, 0],
|
|
|
|
[dimensions.x, dimensions.y, 0],
|
|
|
|
[0, dimensions.y, 0],
|
2022-12-06 20:10:11 +00:00
|
|
|
// top face
|
2022-12-07 17:09:05 +00:00
|
|
|
[slot_depth, 0, dimensions.z],
|
|
|
|
[dimensions.x - slot_depth, 0, dimensions.z],
|
|
|
|
[dimensions.x - slot_depth, dimensions.y, dimensions.z],
|
|
|
|
[slot_depth, dimensions.y, dimensions.z]],
|
2022-12-06 20:10:11 +00:00
|
|
|
[[0,1,2,3],
|
|
|
|
[4,5,1,0],
|
|
|
|
[7,6,5,4],
|
|
|
|
[5,6,2,1],
|
|
|
|
[6,7,3,2],
|
|
|
|
[7,4,0,3]]);
|
2022-12-06 19:59:31 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 17:09:05 +00:00
|
|
|
module lid(dimensions, slot_depth=1.5, wall_width=3, fit_tolerance=0.5) {
|
|
|
|
indent_width = dimensions.x / 4;
|
2022-12-06 21:19:45 +00:00
|
|
|
difference() {
|
|
|
|
union() {
|
2022-12-07 17:09:05 +00:00
|
|
|
lid_base([dimensions.x, dimensions.y, dimensions.z], slot_depth);
|
2022-12-06 23:34:30 +00:00
|
|
|
// locking tab
|
2022-12-07 17:09:05 +00:00
|
|
|
translate([dimensions.x / 2 - indent_width / 2 - fit_tolerance,
|
|
|
|
dimensions.y - wall_width - fit_tolerance,
|
|
|
|
0])
|
2022-12-06 21:19:45 +00:00
|
|
|
rotate([0, 90, 0])
|
2022-12-07 17:09:05 +00:00
|
|
|
cylinder(h=dimensions.x / 4, r=2*fit_tolerance);
|
2022-12-06 21:19:45 +00:00
|
|
|
}
|
2022-12-06 23:34:30 +00:00
|
|
|
// pull handle
|
2022-12-07 17:09:05 +00:00
|
|
|
translate([dimensions.x / 2 - indent_width / 2 - fit_tolerance,
|
|
|
|
dimensions.y - wall_width + fit_tolerance + 0.001,
|
|
|
|
-0.001]) {
|
|
|
|
cube([indent_width,wall_width - 2 * fit_tolerance,0.6 * dimensions.z]);
|
|
|
|
cube([indent_width,2 + wall_width - 2 * fit_tolerance,0.3 * dimensions.z]);
|
2022-12-07 00:16:34 +00:00
|
|
|
}
|
2022-12-06 21:19:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-07 17:09:05 +00:00
|
|
|
module project_box(box,
|
2022-12-06 15:58:59 +00:00
|
|
|
below=10,
|
|
|
|
board_thickness=1,
|
|
|
|
fit_tolerance=0.5,
|
|
|
|
corner_radius=3,
|
|
|
|
support_radius=5,
|
2022-12-06 21:19:45 +00:00
|
|
|
wall_width=3,
|
|
|
|
mode="case") {
|
2022-12-07 17:43:59 +00:00
|
|
|
internal_width = box.x + (fit_tolerance * 2); // tolerance on either side
|
|
|
|
internal_depth = box.y + (fit_tolerance * 2); // tolerance on either side
|
|
|
|
|
|
|
|
internal_height = (fit_tolerance // top tolerance
|
|
|
|
+ box.z // project height
|
|
|
|
+ board_thickness // board height
|
|
|
|
+ below // bottom clearance
|
|
|
|
+ fit_tolerance); // bottom tolerance
|
|
|
|
|
|
|
|
lid_width = internal_width + wall_width; // Extends halfway into each side wall
|
|
|
|
lid_depth = internal_depth + wall_width; // Extends out of one wall
|
|
|
|
lid_height = wall_width; // Replaces most of the top wall
|
2022-12-06 15:58:59 +00:00
|
|
|
|
2022-12-06 21:19:45 +00:00
|
|
|
// case
|
|
|
|
if ((mode == "case") || (mode == "all")) {
|
|
|
|
difference() {
|
2022-12-07 15:40:32 +00:00
|
|
|
union() {
|
|
|
|
// hollow shell
|
|
|
|
difference() {
|
2022-12-07 17:43:59 +00:00
|
|
|
_rounded_box([internal_width + (wall_width * 2),
|
|
|
|
internal_depth + (wall_width * 2),
|
|
|
|
internal_height + (wall_width * 2)],
|
2022-12-07 15:40:32 +00:00
|
|
|
r=corner_radius);
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([wall_width,wall_width,wall_width + 0.002])
|
|
|
|
cube([internal_width, internal_depth, internal_height]);
|
2022-12-07 15:40:32 +00:00
|
|
|
// lid slot
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([wall_width / 2, wall_width, internal_height + wall_width + 0.001]) {
|
2022-12-07 17:09:05 +00:00
|
|
|
lid_base([lid_width, lid_depth, lid_height]);
|
2022-12-07 15:40:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// supports
|
|
|
|
translate([wall_width,wall_width,wall_width]) {
|
|
|
|
translate([0,0,0])
|
|
|
|
corner_post(h=below, r=support_radius);
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([internal_width, 0, 0])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([0,0,90])
|
|
|
|
corner_post(h=below, r=support_radius);
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([0,internal_depth, 0])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([0,0,270])
|
|
|
|
corner_post(h=below, r=support_radius);
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([internal_width, internal_depth, 0])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([0,0,180])
|
|
|
|
corner_post(h=below, r=support_radius);
|
|
|
|
}
|
|
|
|
|
|
|
|
// locking nubs
|
|
|
|
translate([wall_width,wall_width,wall_width]) {
|
|
|
|
nub_size = fit_tolerance * 2;
|
2022-12-07 17:09:05 +00:00
|
|
|
nub_width = box.y / 4;
|
2022-12-07 15:40:32 +00:00
|
|
|
nub_height = below + board_thickness + (nub_size/2) + (fit_tolerance*2);
|
2022-12-07 17:09:05 +00:00
|
|
|
translate([0,box.y / 2 - nub_width / 2,nub_height])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([270,0,0])
|
|
|
|
cylinder(h=nub_width, r=nub_size/2);
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([internal_width,box.y / 2 - nub_width / 2,nub_height])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([270,0,0])
|
|
|
|
cylinder(h=nub_width, r=nub_size/2);
|
|
|
|
}
|
|
|
|
if (mode == "all") {
|
|
|
|
// lid
|
2022-12-07 17:09:05 +00:00
|
|
|
translate([wall_width / 2 + fit_tolerance,
|
|
|
|
wall_width + fit_tolerance,
|
2022-12-07 17:43:59 +00:00
|
|
|
internal_height + wall_width + fit_tolerance]) {
|
2022-12-07 17:09:05 +00:00
|
|
|
lid([lid_width - (fit_tolerance * 2),
|
|
|
|
lid_depth - (fit_tolerance * 2),
|
|
|
|
lid_height - (fit_tolerance * 2)]);
|
2022-12-07 15:40:32 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-06 21:19:45 +00:00
|
|
|
}
|
2022-12-07 15:40:32 +00:00
|
|
|
// cutouts
|
2022-12-07 17:43:59 +00:00
|
|
|
translate([wall_width + fit_tolerance,
|
|
|
|
wall_width + fit_tolerance,
|
|
|
|
fit_tolerance + wall_width + below + board_thickness])
|
2022-12-07 15:40:32 +00:00
|
|
|
children();
|
2022-12-06 21:19:45 +00:00
|
|
|
}
|
2022-12-07 15:40:32 +00:00
|
|
|
} else if (mode == "lid") {
|
|
|
|
// Flip the lid and translate it into place for printing
|
|
|
|
translate([lid_width - (fit_tolerance * 2),0,lid_height - (fit_tolerance * 2)]) {
|
|
|
|
rotate([0, 180, 0]) {
|
|
|
|
difference() {
|
2022-12-07 17:09:05 +00:00
|
|
|
lid([lid_width - (fit_tolerance * 2),
|
|
|
|
lid_depth - (fit_tolerance * 2),
|
|
|
|
lid_height - (fit_tolerance * 2)]);
|
2022-12-07 15:40:32 +00:00
|
|
|
translate([wall_width + fit_tolerance, wall_width + fit_tolerance, -0.001])
|
|
|
|
children();
|
|
|
|
}
|
|
|
|
}
|
2022-12-06 21:19:45 +00:00
|
|
|
}
|
2022-12-07 15:40:32 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-06 15:58:59 +00:00
|
|
|
|
2022-12-07 17:43:59 +00:00
|
|
|
module cutout_front(box, wall_width=3, fit_tolerance=0.5) {
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([90, 0, 0])
|
2022-12-07 17:43:59 +00:00
|
|
|
linear_extrude(height=wall_width + fit_tolerance + 0.001)
|
2022-12-07 15:40:32 +00:00
|
|
|
children(0);
|
|
|
|
}
|
2022-12-06 21:19:45 +00:00
|
|
|
|
2022-12-07 17:43:59 +00:00
|
|
|
module cutout_back(box, wall_width=3, fit_tolerance=0.5) {
|
|
|
|
translate([box.x,box.y,0])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([90, 0, 180])
|
2022-12-07 17:43:59 +00:00
|
|
|
linear_extrude(height=wall_width + fit_tolerance + .001)
|
2022-12-07 15:40:32 +00:00
|
|
|
children(0);
|
|
|
|
}
|
|
|
|
|
2022-12-07 17:43:59 +00:00
|
|
|
module cutout_right(box, wall_width=3, fit_tolerance=0.5) {
|
|
|
|
translate([box.x,0,0])
|
|
|
|
rotate([90, 0, 90])
|
|
|
|
linear_extrude(height=wall_width + fit_tolerance + 0.001)
|
2022-12-07 15:40:32 +00:00
|
|
|
children(0);
|
|
|
|
}
|
|
|
|
|
2022-12-07 17:43:59 +00:00
|
|
|
module cutout_left(box, wall_width=3, fit_tolerance=0.5) {
|
|
|
|
translate([0, box.y, 0])
|
2022-12-07 15:40:32 +00:00
|
|
|
rotate([90, 0, 270])
|
2022-12-07 17:43:59 +00:00
|
|
|
linear_extrude(height=wall_width + fit_tolerance + 0.001)
|
2022-12-07 15:40:32 +00:00
|
|
|
children(0);
|
|
|
|
}
|
|
|
|
|
2022-12-07 17:43:59 +00:00
|
|
|
module cutout_top(box, wall_width=3, fit_tolerance=0.5) {
|
|
|
|
translate([0, 0, box.z])
|
|
|
|
linear_extrude(height=wall_width + fit_tolerance + 0.001)
|
2022-12-07 15:40:32 +00:00
|
|
|
children(0);
|
2022-12-06 15:58:59 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 17:09:05 +00:00
|
|
|
project_box([board_x, board_y, clearance_above],
|
2022-12-06 15:58:59 +00:00
|
|
|
below=clearance_below,
|
|
|
|
board_thickness=board_thickness,
|
|
|
|
fit_tolerance=fit_tolerance,
|
|
|
|
corner_radius=corner_radius,
|
|
|
|
support_radius=support_radius,
|
2022-12-06 21:19:45 +00:00
|
|
|
wall_width=wall_width,
|
|
|
|
mode=mode);
|