diff --git a/libtest.png b/libtest.png index 097e057..39584da 100644 Binary files a/libtest.png and b/libtest.png differ diff --git a/libtest.scad b/libtest.scad index 43c47be..48cd060 100644 --- a/libtest.scad +++ b/libtest.scad @@ -87,16 +87,17 @@ use use use use +use use use +use +use use use use use use use -use -use x0 = 0; x1 = x0 + 100; @@ -146,9 +147,14 @@ translate([x5, cable_grommets_y + 250]) translate([950, 600]) box_test(); +translate([890, 730]) + printed_boxes(); + + translate([850, 1260]) bbox_test(); + inserts_y = 0; nuts_y = inserts_y + 20; washers_y = nuts_y + 100; diff --git a/printed/printed_box.scad b/printed/printed_box.scad new file mode 100644 index 0000000..016b383 --- /dev/null +++ b/printed/printed_box.scad @@ -0,0 +1,230 @@ +// +// NopSCADlib Copyright Chris Palmer 2020 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// + +// +//! A fully parametric 3D printed case that can be customised with cutouts and additions specified by children. +//! +//! The walls can be made wavy, which possibly reduces warping when printing and looks nice, however if holes need to be made +//! in the sides you can't print a wavy bridge. Any holes need to be surrounded by a 45° chamfer to make the bridges straight. +//! See the mounting points for the feet in the first example. +//! +//! It can also have printed feet on the base with the screws doubling up to hold the base on. +// +include <../core.scad> +include <../vitamins/screws.scad> +use <../vitamins/insert.scad> +use + +function pbox_name(type) = type[0]; //! Name to allow more than one box in a project +function pbox_wall(type) = type[1]; //! Wall thickness +function pbox_top(type) = type[2]; //! Top thickness +function pbox_base(type) = type[3]; //! Base thickness, can be zero for no base +function pbox_foot(type) = type[4]; //! Printed foot, can be false to suppress feet +function pbox_base_screw(type) = type[5]; //! Screw type if no feet +function pbox_radius(type) = type[6]; //! Internal corner radius +function pbox_ridges(type) = type[7]; //! Ridge wavelength and amplitude +function pbox_width(type) = type[8]; //! Internal width +function pbox_depth(type) = type[9]; //! Internal depth +function pbox_height(type) = type[10]; //! Internal height + +base_outset = 1; // How much the base overlaps the inner dimensions +base_overlap = 2; // The width of ledge the base sits on +height_overlap = 1; // How far the edges sit below the base + +function pbox_inclusion(type) = pbox_base(type) ? base_overlap - base_outset : 0; //! How far the ledge for the base extends inwards + +function pbox_total_height(type) = //! Total height including base overlap + let(base = pbox_base(type), + foot = pbox_foot(type), + washer = pbox_washer(type), + screw = pbox_screw(type)) + pbox_height(type) + pbox_top(type) + base + (base ? height_overlap : 0) + (foot || !base ? 0 : washer_thickness(washer) + screw_head_height(screw)); + +function pbox_screw(type) = //! Foot screw if got feet else base_screw + let(foot = pbox_foot(type)) foot ? foot_screw(foot) : pbox_base_screw(type); + +function pbox_insert(type) = screw_insert(pbox_screw(type)); //! The insert for the base screws +function pbox_washer(type) = screw_washer(pbox_screw(type)); //! The washer for the base screws + +function pbox_screw_length(type, panel_thickness = 0) = //! Length of the base screw + let(foot = pbox_foot(type)) + screw_shorter_than(pbox_base(type) + washer_thickness(pbox_washer(type)) + + insert_length(pbox_insert(type)) + + (foot ? foot_thickness(foot) : panel_thickness)); + +function pbox_mid_offset(type) = pbox_ridges(type).y + pbox_wall(type) / 2; // Offset to wall midpoint + +function pbox_screw_inset(type) = //! How far the base screws are inset + let(foot = pbox_foot(type), + r = foot ? foot_diameter(foot) / 2 : washer_radius(pbox_washer(type)), + R = pbox_radius(type) + ) max(r, R - (R - r) / sqrt(2)); + +module pbox_screw_positions(type) { + foot = pbox_foot(type); + inset = pbox_screw_inset(type); + for(x = [-1, 1], y = [-1, 1]) + translate([x * (pbox_width(type) / 2 - inset), y * (pbox_depth(type) / 2 - inset)]) + rotate((y > 0 ? -x * 45 : -x * 135) + 90) + children(); +} + +module pbox_mid_shape(type) { + ridges = pbox_ridges(type); + offset = ridges.y + pbox_wall(type) / 2; + rad = pbox_radius(type) + offset; + w = pbox_width(type) + 2 * offset; + d = pbox_depth(type) + 2 * offset; + + module waves(length) { + l = length - 2 * rad; + + waves = round(l / ridges.x); + points = 16; + translate([-l / 2, ridges.y / 2]) + polygon(concat([[0, -10]], [for(i = [0 : waves * points], a = 360 * i / points) [i * l / waves / points, -cos(a) * ridges.y / 2] ], [[l, -10]])); + } + + difference() { + rounded_square([w, d], rad, center = true); + + if(ridges.y) + for(side = [-1, 1]) { + translate([0, side * d / 2]) + rotate(90 + side * 90) + waves(w); + + translate([side * w / 2, 0]) + rotate(side * 90) + waves(d); + } + } +} + +module pbox_inner_shape(type) { + rad = pbox_radius(type); + w = pbox_width(type); + d = pbox_depth(type); + + rounded_square([w, d], rad, center = true); +} + +module pbox_base(type) { //! Generate the STL for the base + stl(str(pbox_name(type),"_base")); + t = pbox_base(type); + difference() { + union() { + linear_extrude(height = t) + offset(base_outset - 0.2) + pbox_inner_shape(type); + + if($children > 0) + children(0); + } + pbox_screw_positions(type) + poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true); + + if($children > 1) + children(1); + } +} + +module pbox(type) { //! Generate the STL for the main case + stl(pbox_name(type)); + + height = pbox_height(type); + total_height = pbox_total_height(type); + top_thickness = pbox_top(type); + wall = pbox_wall(type); + ledge_outset = pbox_ridges(type).y; + ledge_inset = base_outset - base_overlap; + ledge_h = pbox_base(type) ? (ledge_outset - ledge_inset) * 2 : 0; + + difference() { + union() { + linear_extrude(height = total_height) + offset(wall / 2) pbox_mid_shape(type); + + if($children > 2) + children(2); + } + difference() { + translate_z(top_thickness) + union() { + linear_extrude(height = height + eps) + offset(-wall / 2) pbox_mid_shape(type); + + translate_z(height) // Recess for the base + linear_extrude(height = total_height - height) + offset(base_outset) + pbox_inner_shape(type); + } + // Ledge to support the lid + if(ledge_h) + translate_z(top_thickness + height - ledge_h) + difference() { + rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1, center = false); + + hull() { + linear_extrude(height = ledge_h + eps) + offset(ledge_inset) + pbox_inner_shape(type); + + linear_extrude(height = eps) + offset(ledge_outset) + pbox_inner_shape(type); + } + pbox_screw_positions(type) + insert_hole(pbox_insert(type)); + } + + // Corner lugs for inserts + outset = wall + pbox_ridges(type).y; + or = pbox_radius(type) + outset; + inset = pbox_screw_inset(type) + outset; + br = insert_boss_radius(pbox_insert(type), wall); + ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br; + translate_z(height + top_thickness) + pbox_screw_positions(type) + insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or); + + if($children > 0) + children(0); + } + if($children > 1) + children(1); + } +} + +module pbox_inserts(type) //! Place the inserts for the base screws + translate_z(pbox_height(type) + pbox_top(type)) + pbox_screw_positions(type) + insert(pbox_insert(type)); + +module pbox_base_screws(type, thickness = 0) //! Place the screws and feet + translate_z(pbox_height(type) + pbox_top(type) + pbox_base(type)) + pbox_screw_positions(type) { + foot = pbox_foot(type); + if(foot) + color(pp4_colour) + foot(foot); + + translate_z(foot ? foot_thickness(foot) : thickness) + screw_and_washer(pbox_screw(type), pbox_screw_length(type, thickness)); + } diff --git a/readme.md b/readme.md index 34a2521..d1e6f16 100644 --- a/readme.md +++ b/readme.md @@ -31,13 +31,13 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa Extrusion_brackets Ring_terminals Foot Rounded_cylinder Extrusions Rockers Handle Rounded_polygon Fans Rod Pcb_mount Sector - Fuseholder Screws Psu_shroud Sweep - Geared_steppers Scs_bearing_blocks Ribbon_clamp Thread - Green_terminals Sealing_strip Screw_knob Tube - Hot_ends Sheets Socket_box - Hygrometer Sk_brackets Ssr_shroud - Iecs Spades Strap_handle - Inserts Spools + Fuseholder Screws Printed_box Sweep + Geared_steppers Scs_bearing_blocks Psu_shroud Thread + Green_terminals Sealing_strip Ribbon_clamp Tube + Hot_ends Sheets Screw_knob + Hygrometer Sk_brackets Socket_box + Iecs Spades Ssr_shroud + Inserts Spools Strap_handle Jack Springs Kp_pillow_blocks Ssrs Ldrs Stepper_motors @@ -4295,6 +4295,87 @@ The stl must be given a parameterless wrapper in the project that uses it. | 1 | pcb_mount_PI_IO_5.stl | +Top + +--- + +## Printed_box +A fully parametric 3D printed case that can be customised with cutouts and additions specified by children. + +The walls can be made wavy, which possibly reduces warping when printing and looks nice, however if holes need to be made +in the sides you can't print a wavy bridge. Any holes need to be surrounded by a 45° chamfer to make the bridges straight. +See the mounting points for the feet in the first example. + +It can also have printed feet on the base with the screws doubling up to hold the base on. + + +[printed/printed_box.scad](printed/printed_box.scad) Implementation. + +[tests/printed_box.scad](tests/printed_box.scad) Code for this example. + +### Properties +| Function | Description | +|:--- |:--- | +| ```pbox_base(type)``` | Base thickness, can be zero for no base | +| ```pbox_base_screw(type)``` | Screw type if no feet | +| ```pbox_depth(type)``` | Internal depth | +| ```pbox_foot(type)``` | Printed foot, can be false to suppress feet | +| ```pbox_height(type)``` | Internal height | +| ```pbox_name(type)``` | Name to allow more than one box in a project | +| ```pbox_radius(type)``` | Internal corner radius | +| ```pbox_ridges(type)``` | Ridge wavelength and amplitude | +| ```pbox_top(type)``` | Top thickness | +| ```pbox_wall(type)``` | Wall thickness | +| ```pbox_width(type)``` | Internal width | + +### Functions +| Function | Description | +|:--- |:--- | +| ```pbox_inclusion(type)``` | How far the ledge for the base extends inwards | +| ```pbox_insert(type)``` | The insert for the base screws | +| ```pbox_screw(type)``` | Foot screw if got feet else base_screw | +| ```pbox_screw_inset(type)``` | How far the base screws are inset | +| ```pbox_screw_length(type, panel_thickness = 0)``` | Length of the base screw | +| ```pbox_total_height(type)``` | Total height including base overlap | +| ```pbox_washer(type)``` | The washer for the base screws | + +### Modules +| Module | Description | +|:--- |:--- | +| ```pbox(type)``` | Generate the STL for the main case | +| ```pbox_base(type)``` | Generate the STL for the base | +| ```pbox_base_screws(type, thickness = 0)``` | Place the screws and feet | +| ```pbox_inserts(type)``` | Place the inserts for the base screws | + +![printed_box](tests/png/printed_box.png) + +### Vitamins +| Qty | Module call | BOM entry | +| ---:|:--- |:---| +| 4 | ```insert(F1BM)``` | Heatfit insert M2 | +| 4 | ```insert(F1BM3)``` | Heatfit insert M3 | +| 4 | ```screw(M2_cap_screw, 6)``` | Screw M2 cap x 6mm | +| 3 | ```screw(M3_pan_screw, 6)``` | Screw M3 pan x 6mm | +| 4 | ```screw(M3_pan_screw, 10)``` | Screw M3 pan x 10mm | +| 4 | ```washer(M2_washer)``` | Washer M2 x 5mm x 0.3mm | +| 7 | ```washer(M3_washer)``` | Washer M3 x 7mm x 0.5mm | + +### Printed +| Qty | Filename | +| ---:|:--- | +| 1 | box1.stl | +| 1 | box1_base.stl | +| 7 | foot.stl | +| 1 | smooth_box.stl | +| 1 | smooth_box_base.stl | + +### Assemblies +| Qty | Name | +| ---:|:--- | +| 1 | box1_assembly | +| 1 | box2_assembly | + + Top --- diff --git a/tests/png/printed_box.png b/tests/png/printed_box.png new file mode 100644 index 0000000..fc5381d Binary files /dev/null and b/tests/png/printed_box.png differ diff --git a/tests/printed_box.scad b/tests/printed_box.scad new file mode 100644 index 0000000..db0b12e --- /dev/null +++ b/tests/printed_box.scad @@ -0,0 +1,167 @@ +// +// NopSCADlib Copyright Chris Palmer 2020 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// + +include <../core.scad> +include <../vitamins/screws.scad> +use <../printed/foot.scad> +use <../printed/printed_box.scad> + +foot = [13, 5, 2, 1, M3_pan_screw, 10]; +module foot_stl() foot(foot); + +wall = 2; +top_thickness = 2; +base_thickness = 2; +case_inner_rad = 8; + +width = 80; +depth = 45; +height = 40; + +box1 = ["box1", wall, top_thickness, base_thickness, false, M2_cap_screw, case_inner_rad, [8, 1], width, depth, height]; +box2 = ["smooth_box", wall, top_thickness, base_thickness, foot, false, case_inner_rad, [0, 0], width, depth, height]; + +module box1_feet_positions() { + clearance = 2; + foot_r = foot_diameter(foot) / 2; + x_inset = case_inner_rad + foot_r - pbox_ridges(box1).y; + z_inset = foot_r + clearance; + h = height + base_thickness; + + for(p = [[-1, -1], [1, -1], [0, 1]]) + translate([p.x * (width / 2 - x_inset), depth / 2 + wall + pbox_ridges(box1).y, top_thickness + h / 2 + p.y * (h / 2 - z_inset)]) + rotate([90, 0, 0]) + children(); +} + +module box1_internal_additions() { + d = washer_diameter(screw_washer(foot_screw(foot))) + 1; + h = pbox_ridges(box1).y; + box1_feet_positions() + translate_z(wall - eps) + cylinder(d2 = d, d1 = d + 2 * h, h = h); + +} + +module box1_external_additions() { + amp = pbox_ridges(box1).y + eps; + d = foot_diameter(foot) + 1; + box1_feet_positions() + cylinder(d1 = d, d2 = d + 2 * amp, h = amp); +} + +module box1_holes() { + box1_feet_positions() + teardrop(r = screw_pilot_hole(foot_screw(foot)), h = 10, center = true); +} + + +module box1_case_stl() { + pbox(box1) { + box1_internal_additions(); + box1_holes(); + box1_external_additions(); + } +} + +module box1_base_additions() { +} + +module box1_base_holes() { +} + +module box1_base_stl() + pbox_base(box1) { + box1_base_additions(); + box1_base_holes(); + } + +module box1_assembly() +assembly("box1") { + color(pp1_colour) render() box1_case_stl(); + + pbox_inserts(box1); + + pbox_base_screws(box1); + + box1_feet_positions() { + foot_assembly(0, foot); + + vflip() + translate_z(foot_thickness(foot)) + screw_and_washer(foot_screw(foot), 6); + } + + translate_z(height + top_thickness + base_thickness + eps) vflip() + %render() box1_base_stl(); +} + +module box2_internal_additions() { +} + +module box2_holes() { +} + +module box2_external_additions() { +} + +module box2_case_stl() { + pbox(box2) { + box2_internal_additions(); + box2_holes(); + box2_external_additions(); + } +} + +module box2_base_additions() { +} + +module box2_base_holes() { +} + +module box2_base_stl() + pbox_base(box2) { + box2_base_additions(); + box2_base_holes(); + } + +module box2_assembly() +assembly("box2") { + color(pp1_colour) render() box2_case_stl(); + + pbox_inserts(box2); + + pbox_base_screws(box2); + + translate_z(height + top_thickness + base_thickness + eps) vflip() + %render() box2_base_stl(); +} + + +module printed_boxes() { + rotate(180) + box1_assembly(); + + translate([100, 0]) + box2_assembly(); + +} + +if($preview) + printed_boxes();